<commit_before>import React from 'react'
import ImageIcon from '../imageicon'
import IconIcon from '../iconicon'
import ServiceSettings from 'app/containers/service/settings'
import HoldButton from '../holdbutton'
import rpc from 'app/rpc'
import Flash from 'app/flash'
import ActionModal from './actionmodal'
import Command from 'app/utils/command'
import VirtualServices from './virtual'
import {colorize} from 'app/utils'

require("sass/service/card.sass")
const icon = require("../../../imgs/services.svg")

const ServiceField=React.createClass({
  getInitialState(){
    return {service: undefined}
  },
  componentDidMount(){
    rpc.call("service.info", [this.props.value]).then( (service) => {
      this.setState({service: service.name})
    })
  },
  render(){
    if (this.state.service)
      return (
        {this.props.description.label}: {this.state.service}

      )
    else
      return (

      )
  }
})

function Field(props){
  if (props.description.type=='service')
    return (
      <ServiceField {...props}/>
    )
  return (
    {props.description.label}: {props.value}

  )
}

function RealBottomMenu(props){
  return (

      {props.service.virtual ? (
         props.setModal('virtual', {service: props.service})}>Related services
      ) : []}

          Options

            {!props.service.is_virtual ? (
              <HoldButton className="item" onHoldClick={props.handleDetach}>Hold to Detach</HoldButton>
            ) : []}
            {props.service.fields ? (

Settings

            ) : []}
            {props.actions ? props.actions.map( (ac) => (

 props.triggerAction(ac.id)}>{ ac.extra.icon ? (<i className={`ui ${ac.extra.icon} icon`}/>) : []} {ac.name}

            )) : (

                Loading

            ) }

  )
}

const VirtualBottomMenu=React.createClass({
  componentDidMount(){
    $(this.refs.dropdown).dropdown()
  },
  componentDidUpdate(){
    $(this.refs.dropdown).dropdown() // Ensure has working dropdown
  },
  render(){
    const props=this.props
    if (!props.actions){
      return (

          Loading

      )
    }

    const maxicons=4
    const head = props.actions.slice(0, maxicons)
    //const tail = props.actions.slice(maxicons)
    return (

        { head.map( (ac) => (
           props.triggerAction(ac.id)}>
            <i className={`ui ${ac.extra.icon} icon`} title={ac.name}/>

        ) ) }

              { props.actions.map( (ac) => (
                 props.triggerAction(ac.id)}>
                  {ac.name} <i className={`ui ${ac.extra.icon} icon`}/>

              ) ) }

    )
  }
})

const Card=React.createClass({
  getInitialState(){
    return {
      actions: undefined,
      loading: false
    }
  },

  componentDidMount(){
    if (this.props.service.is_virtual){
      this.loadAvailableActions()
    }
    else{
      let dropdown=$(this.refs.menu).find('.ui.dropdown')
      dropdown.dropdown({
          // you can use any ui transition
          transition: 'fade up',
          onShow: this.loadAvailableActions,
        })
      let self=this
      let s = this.props.service
      Command.add_command_search(`service-${s.uuid}`, (Q, context) => [
        {id: `service-settings-${s.uuid}`, title: `${s.name} settings`,
         description: `Modify ${s.name} service settings`, run: () => self.handleOpenSettings()},
        {id: `service-more-${s.uuid}`, title: `${s.name} more actions`,
         description: `Show ${s.name} more actions menu`, run: () => dropdown.dropdown('show').focus()},
      ],2 )
    }
  },
  componentWillUnmount(){
    Command.remove_command_search(`service-${this.props.service.uuid}`)
  },
  setModal(modal, data){
    let state
    if (data){
      state={ modal, service: this.props.service, data }
    }
    else{
      state={ modal, service: this.props.service }
    }
    this.context.router.push( {
      pathname: this.props.location.pathname,
      state: state
    } )
  },
  closeModal(){
    this.setModal(false)
  },
  contextTypes: {
    router: React.PropTypes.object
  },

  loadAvailableActions(){
    if (!this.state.actions){
      this.setState({loading: true})
      rpc.call("action.filter", {traits: this.props.service.traits}).then((actions) => {
        this.setState({
          actions: actions,
          loading: false
        })
      }).catch(() => {
        Flash.error("Could not load actions for this service")
        this.setState({
          actions: undefined,
          loading: false
        })
      })
    }
    return true;
  },

  triggerAction(action_id){
    let action=this.state.actions.filter( (a) => a.id == action_id )[0]
    // Discriminate depending on action type (by shape)
    if (action.extra.call){
      const params = this.props.service.config

      let missing_params = action.extra.call.params.filter((p) => !(p.name in params))
      if (missing_params.length==0){
        rpc.call("action.trigger",
          [action_id, params]).then(function(){
          })
      }
      else{
        this.setModal("action",{ action, params, missing_params })
      }
    }
    else if (action.extra.screen){
      this.context.router.push({
        pathname: `/s/${action.id}`,
        state: { service: this.props.service }
      })
    }
    else {
      Flash.error("Dont know how to trigger this action")
    }
  },

  handleOpenSettings(){
    this.setModal("settings")
  },
  handleDetach(){
    this.props.onDetach( this.props.serverboard.shortname, this.props.service.uuid )
  },
  get_field(k){
    var fields = (this.props.service_description || {}).fields
    if (!fields)
      return undefined
    for(var p of fields){
      if (p.name==k){
        return p
      }
    }
    return undefined;
  },
  show_config(k){
    var field = this.get_field(k)
    if (!field)
      return false
    return field.card ? true : false
  },
  render(){
    let props=this.props.service
    let popup=[]
    let current_modal = (
      this.props.location.state &&
      (this.props.location.state.service == this.props.service) &&
      this.props.location.state.modal
    )
    switch(current_modal){
      case 'settings':
        popup=(
          <ServiceSettings
            onAdd={this.handleAddService}
            onAttach={this.handleAttachService}
            onClose={this.closeModal}
            service={props}
            />
        )
        break;
      case 'action':
        popup=(
          <ActionModal {...this.props.location.state.data}/>
        )
        break;
      case 'virtual':
        popup=(
          <VirtualServices serverboards={this.props.serverboards} parent={props} location={this.props.location}/>
        )
        break;
    }
    return (

            {props.icon ? (
              <IconIcon src={icon} icon={props.icon} plugin={props.type.split('/',1)[0]}/>
            ) : (
              <ImageIcon src={icon}  name={props.name}/>
            )}

{props.name}

{(props.tags || []).map( (l) => (
            <span className={`ui circular empty ${colorize(l)} label`}/> {l}
          ))}

{props.description || ""}

          {(Object.keys(props.config || {})).map((k) => this.show_config(k) ? (
            <Field key={k} name={k} value={props.config[k]} description={this.get_field(k)}/>
          ) : [])}

          {props.is_virtual ? (
            <VirtualBottomMenu
              actions={this.state.actions}
              triggerAction={this.triggerAction}
              service={props}
              />
          ) : (
            <RealBottomMenu
              actions={this.state.actions}
              setModal={this.setModal}
              handleDetach={this.handleDetach}
              handleOpenSettings={this.handleOpenSettings}
              triggerAction={this.triggerAction}
              service={props}
              />
          )}

        {popup}

    )
  }
})

export default Card
<commit_msg>At plugin screens send all service information<commit_after>import React from 'react'
import ImageIcon from '../imageicon'
import IconIcon from '../iconicon'
import ServiceSettings from 'app/containers/service/settings'
import HoldButton from '../holdbutton'
import rpc from 'app/rpc'
import Flash from 'app/flash'
import ActionModal from './actionmodal'
import Command from 'app/utils/command'
import VirtualServices from './virtual'
import {colorize} from 'app/utils'

require("sass/service/card.sass")
const icon = require("../../../imgs/services.svg")

const ServiceField=React.createClass({
  getInitialState(){
    return {service: undefined}
  },
  componentDidMount(){
    rpc.call("service.info", [this.props.value]).then( (service) => {
      this.setState({service: service.name})
    })
  },
  render(){
    if (this.state.service)
      return (
        {this.props.description.label}: {this.state.service}

      )
    else
      return (

      )
  }
})

function Field(props){
  if (props.description.type=='service')
    return (
      <ServiceField {...props}/>
    )
  return (
    {props.description.label}: {props.value}

  )
}

function RealBottomMenu(props){
  return (

      {props.service.virtual ? (
         props.setModal('virtual', {service: props.service})}>Related services
      ) : []}

          Options

            {!props.service.is_virtual ? (
              <HoldButton className="item" onHoldClick={props.handleDetach}>Hold to Detach</HoldButton>
            ) : []}
            {props.service.fields ? (

Settings

            ) : []}
            {props.actions ? props.actions.map( (ac) => (

 props.triggerAction(ac.id)}>{ ac.extra.icon ? (<i className={`ui ${ac.extra.icon} icon`}/>) : []} {ac.name}

            )) : (

                Loading

            ) }

  )
}

const VirtualBottomMenu=React.createClass({
  componentDidMount(){
    $(this.refs.dropdown).dropdown()
  },
  componentDidUpdate(){
    $(this.refs.dropdown).dropdown() // Ensure has working dropdown
  },
  render(){
    const props=this.props
    if (!props.actions){
      return (

          Loading

      )
    }

    const maxicons=4
    const head = props.actions.slice(0, maxicons)
    //const tail = props.actions.slice(maxicons)
    return (

        { head.map( (ac) => (
           props.triggerAction(ac.id)}>
            <i className={`ui ${ac.extra.icon} icon`} title={ac.name}/>

        ) ) }

              { props.actions.map( (ac) => (
                 props.triggerAction(ac.id)}>
                  {ac.name} <i className={`ui ${ac.extra.icon} icon`}/>

              ) ) }

    )
  }
})

const Card=React.createClass({
  getInitialState(){
    return {
      actions: undefined,
      loading: false
    }
  },

  componentDidMount(){
    if (this.props.service.is_virtual){
      this.loadAvailableActions()
    }
    else{
      let dropdown=$(this.refs.menu).find('.ui.dropdown')
      dropdown.dropdown({
          // you can use any ui transition
          transition: 'fade up',
          onShow: this.loadAvailableActions,
        })
      let self=this
      let s = this.props.service
      Command.add_command_search(`service-${s.uuid}`, (Q, context) => [
        {id: `service-settings-${s.uuid}`, title: `${s.name} settings`,
         description: `Modify ${s.name} service settings`, run: () => self.handleOpenSettings()},
        {id: `service-more-${s.uuid}`, title: `${s.name} more actions`,
         description: `Show ${s.name} more actions menu`, run: () => dropdown.dropdown('show').focus()},
      ],2 )
    }
  },
  componentWillUnmount(){
    Command.remove_command_search(`service-${this.props.service.uuid}`)
  },
  setModal(modal, data){
    let state
    if (data){
      state={ modal, service: this.props.service, data }
    }
    else{
      state={ modal, service: this.props.service }
    }
    this.context.router.push( {
      pathname: this.props.location.pathname,
      state: state
    } )
  },
  closeModal(){
    this.setModal(false)
  },
  contextTypes: {
    router: React.PropTypes.object
  },

  loadAvailableActions(){
    if (!this.state.actions){
      this.setState({loading: true})
      rpc.call("action.filter", {traits: this.props.service.traits}).then((actions) => {
        this.setState({
          actions: actions,
          loading: false
        })
      }).catch(() => {
        Flash.error("Could not load actions for this service")
        this.setState({
          actions: undefined,
          loading: false
        })
      })
    }
    return true;
  },

  triggerAction(action_id){
    let action=this.state.actions.filter( (a) => a.id == action_id )[0]
    // Discriminate depending on action type (by shape)
    if (action.extra.call){
      const params = this.props.service.config

      let missing_params = action.extra.call.params.filter((p) => !(p.name in params))
      if (missing_params.length==0){
        rpc.call("action.trigger",
          [action_id, params]).then(function(){
          })
      }
      else{
        this.setModal("action",{ action, params, missing_params })
      }
    }
    else if (action.extra.screen){
      // Use full info, not just the one at card. May have more info as _pw
      rpc.call('service.info',[this.props.service.uuid]).then( (service) => {
        this.context.router.push({
          pathname: `/s/${action.id}`,
          state: { service }
        })
      })
    }
    else {
      Flash.error("Dont know how to trigger this action")
    }
  },

  handleOpenSettings(){
    this.setModal("settings")
  },
  handleDetach(){
    this.props.onDetach( this.props.serverboard.shortname, this.props.service.uuid )
  },
  get_field(k){
    var fields = (this.props.service_description || {}).fields
    if (!fields)
      return undefined
    for(var p of fields){
      if (p.name==k){
        return p
      }
    }
    return undefined;
  },
  show_config(k){
    var field = this.get_field(k)
    if (!field)
      return false
    return field.card ? true : false
  },
  render(){
    let props=this.props.service
    let popup=[]
    let current_modal = (
      this.props.location.state &&
      (this.props.location.state.service == this.props.service) &&
      this.props.location.state.modal
    )
    switch(current_modal){
      case 'settings':
        popup=(
          <ServiceSettings
            onAdd={this.handleAddService}
            onAttach={this.handleAttachService}
            onClose={this.closeModal}
            service={props}
            />
        )
        break;
      case 'action':
        popup=(
          <ActionModal {...this.props.location.state.data}/>
        )
        break;
      case 'virtual':
        popup=(
          <VirtualServices serverboards={this.props.serverboards} parent={props} location={this.props.location}/>
        )
        break;
    }
    return (

            {props.icon ? (
              <IconIcon src={icon} icon={props.icon} plugin={props.type.split('/',1)[0]}/>
            ) : (
              <ImageIcon src={icon}  name={props.name}/>
            )}

{props.name}

{(props.tags || []).map( (l) => (
            <span className={`ui circular empty ${colorize(l)} label`}/> {l}
          ))}

{props.description || ""}

          {(Object.keys(props.config || {})).map((k) => this.show_config(k) ? (
            <Field key={k} name={k} value={props.config[k]} description={this.get_field(k)}/>
          ) : [])}

          {props.is_virtual ? (
            <VirtualBottomMenu
              actions={this.state.actions}
              triggerAction={this.triggerAction}
              service={props}
              />
          ) : (
            <RealBottomMenu
              actions={this.state.actions}
              setModal={this.setModal}
              handleDetach={this.handleDetach}
              handleOpenSettings={this.handleOpenSettings}
              triggerAction={this.triggerAction}
              service={props}
              />
          )}

        {popup}

    )
  }
})

export default Card
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2014-2018 Eric Gach <eric.gach@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

const Me = imports.misc.extensionUtils.getCurrentExtension();
const Config = imports.misc.config;
const Gettext = imports.gettext.domain('desk-changer');
const Gio = imports.gi.Gio;
const Lang = imports.lang;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Util = imports.misc.util;
const _ = Gettext.gettext;

const Convenience = Me.imports.convenience;
const DeskChangerDaemon = Me.imports.daemon.DeskChangerDaemon;
const DeskChangerSettings = Me.imports.settings.DeskChangerSettings;
const DeskChangerVersion = Me.metadata.version;
const debug = Me.imports.utils.debug;
const Menu = Me.imports.menu;
const Ui = Me.imports.ui;

/**
 * This is the actual indicator that should be added to the main panel.
 *
 * @type {Lang.Class}
 */
const DeskChangerIndicator = new Lang.Class({
    Name: 'DeskChangerIndicator',
    Extends: PanelMenu.Button,

    _init: function (daemon) {
        this.settings = new DeskChangerSettings();
        this.parent(0.0, 'DeskChanger');
        this.daemon = daemon;

        this.actor.add_child(new Ui.DeskChangerIcon(this.daemon, this.settings));
        this.menu.addMenuItem(new Menu.DeskChangerProfileDesktop(this.settings));
        if (this.settings.update_lockscreen) {
            this.menu.addMenuItem(new Menu.DeskChangerProfileLockscreen(this.settings));
        }
        this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
        this.menu.addMenuItem(new Menu.DeskChangerSwitch(_('Change with Profile'), 'auto_rotate', this.settings));
        this.menu.addMenuItem(new Menu.DeskChangerSwitch(_('Notifications'), 'notifications', this.settings));
        this.menu.addMenuItem(new Menu.DeskChangerSwitch(_('Remember Profile State'), 'remember_profile_state', this.settings));

        if (Main.screenShield !== null) {
            this.menu.addMenuItem(new Menu.DeskChangerSwitch(_('Update Lock Screen'), 'update_lockscreen', this.settings));
        }

        this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
        this.menu.addMenuItem(new Menu.DeskChangerPreviewMenuItem(this.daemon));
        this.menu.addMenuItem(new Menu.DeskChangerOpenCurrent());
        this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
        this.menu.addMenuItem(new Menu.DeskChangerRotation(this.settings, true));
        this.menu.addMenuItem(new Menu.DeskChangerControls(this.daemon, this.settings));
        this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
        this.menu.addMenuItem(new Menu.DeskChangerDaemonControls(this.daemon));
        // Simple settings for the extension
        let settings = new PopupMenu.PopupMenuItem(_('DeskChanger Settings'));
        settings.connect('activate', function () {
            Util.spawn(['gnome-shell-extension-prefs', Me.metadata.uuid]);
        });
        this.menu.addMenuItem(settings);
        this.settings.connect('changed::update-lockscreen', Lang.bind(this, function () {
            if (this.settings.update_lockscreen) {
                this.menu.addMenuItem(new Menu.DeskChangerProfileLockscreen(this.settings), 1);
            } else {
                this.menu.box.get_children().map(function (actor) {
                    return actor._delegate;
                }).filter(function (item) {
                    item instanceof Menu.DeskChangerProfileLockscreen && item.destroy();
                });
            }
        }));
    },

    destroy: function () {
        this.parent();
        this.settings.destroy();
    }
});

const DeskChangerSystemIndicator = new Lang.Class({
    Name: 'DeskChangerSystemIndicator',
    Extends: PanelMenu.SystemIndicator,

    _init: function (daemon, menu) {
        this.parent();
        this.daemon = daemon;

        this.settings = new DeskChangerSettings();
        this._menu = new PopupMenu.PopupSubMenuMenuItem('DeskChanger', true);
        this._menu.icon.set_gicon(Gio.icon_new_for_string(Me.path + '/icons/wallpaper-icon.png'));
        this._menu.menu.addMenuItem(new Menu.DeskChangerProfileDesktop(this.settings, false));
        this._menu.menu.addMenuItem(new Menu.DeskChangerPreviewMenuItem(this.daemon));
        this._menu.menu.addMenuItem(new Menu.DeskChangerOpenCurrent());
        this._menu.menu.addMenuItem(new Menu.DeskChangerRotation(this.settings, false));
        this._menu.menu.addMenuItem(new Menu.DeskChangerControls(this.daemon, this.settings));
        this._menu.menu.addMenuItem(new Menu.DeskChangerDaemonControls(this.daemon));
        // Simple settings for the extension
        let settings = new PopupMenu.PopupMenuItem(_('DeskChanger Settings'));
        settings.connect('activate', function () {
            Util.spawn(['gnome-shell-extension-prefs', Me.metadata.uuid]);
        });
        this._menu.menu.addMenuItem(settings);
        let position = (parseInt(Config.PACKAGE_VERSION.split(".")[1]) < 18) ? this._menu.menu.numMenuItems - 2 : this._menu.menu.numMenuItems - 1;
        menu.addMenuItem(this._menu, position);
        this._indicator = null;
        this.settings.connect('changed::icon-preview', Lang.bind(this, this._update_indicator));
        this._update_indicator();
    },

    destroy: function () {
        if (this._indicator) {
            this._indicator.destroy();
        }

        this._menu.destroy();
        this.settings.destroy();
    },

    _update_indicator: function () {
        if (this._indicator !== null) {
            this.indicators.remove_actor(this._indicator);
            this._indicator.destroy();
            this._indicator = null;
        }

        if (this.settings.icon_preview) {
            this._indicator = new Ui.DeskChangerIcon(this.daemon, this.settings);
            this.indicators.add_actor(this._indicator);
            this._indicator.connect('notify::visible', Lang.bind(this, this._syncIndicatorsVisible));
            this._syncIndicatorsVisible();
        }
    }
});

let daemon, indicator, settings, shellSettings;
let changed_id, current_profile_id, notifications_id, random_id, rotation_id;

function disable() {
    debug('disabling extension');

    if (typeof indicator.destroy === "function") {
        indicator.destroy();
    }

    if (current_profile_id) {
        settings.disconnect(current_profile_id);
    }

    if (notifications_id) {
        settings.disconnect(notifications_id);
    }

    if (changed_id) {
        daemon.disconnect(changed_id);
    }

    if (random_id) {
        settings.disconnect(random_id);
    }

    if (rotation_id) {
        settings.disconnect(rotation_id);
    }

    changed_id = null;
    current_profile_id = null;
    notifications_id = null;
    random_id = null;
    rotation_id = null;
    indicator = null;
}

function enable() {
    debug('enabling extension');

    current_profile_id = settings.connect('changed::current-profile', function () {
        if (settings.notifications)
            Main.notify('Desk Changer', _('Profile changed to %s'.format(settings.current_profile)));
    });

    notifications_id = settings.connect('changed::notifications', function () {
        Main.notify('Desk Changer', ((settings.notifications) ? _('Notifications are now enabled') : _('Notifications are now disabled')));
    });

    changed_id = daemon.desktop_profile.connect('changed', function (obj, wallpaper) {
        if (settings.notifications)
            Main.notify('Desk Changer', _('Wallpaper Changed: %s'.format(wallpaper)));
    });

    random_id = settings.connect('changed::random', function () {
        if (settings.notifications) {
            let message;

            if (settings.random) {
                message = _('Wallpapers will be shown in a random order');
            } else {
                message = _('Wallpapers will be shown in the order the were loaded');
            }

            Main.notify('Desk Changer', message);
        }
    });

    rotation_id = settings.connect('changed::rotation', function () {
        if (settings.notifications) {
            let message;
            switch (settings.rotation) {
                case 'interval':
                    message = _('Rotation will occur every %d seconds'.format(settings.interval));
                    break;
                case 'hourly':
                    message = _('Rotation will occur at the beginning of every hour');
                    break;
                default:
                    message = _('Rotation has been disabled');
                    break;
            }

            Main.notify('Desk Changer', message);
        }
    });

    if (!daemon.running && settings.auto_start) {
        // run if auto start is enabled and its not already running
        daemon.start();
    }

    if (settings.integrate_system_menu) {
        indicator = new DeskChangerSystemIndicator(daemon, Main.panel.statusArea.aggregateMenu.menu);
        Main.panel.statusArea.aggregateMenu._indicators.insert_child_at_index(indicator.indicators, 0);
    } else {
        indicator = new DeskChangerIndicator(daemon);
        Main.panel.addToStatusArea('deskchanger', indicator);
    }
}

function init() {
    Convenience.initTranslations();
    debug('initalizing extension version: %s'.format(DeskChangerVersion));
    settings = new DeskChangerSettings();
    shellSettings = new Gio.Settings({'schema': 'org.gnome.shell'});
    daemon = new DeskChangerDaemon(settings);
    if (Main.screenShield !== null) {
        daemon.lockscreen = Main.screenShield.locked;
        Main.screenShield.connect('locked-changed', function () {
            // lockscreen mode toggle through signals
            daemon.lockscreen = Main.screenShield.locked;
        });
    }

    Gio.DBus.session.connect('closed', function () {
        if (daemon.running) {
            daemon.stop();
        }
    });

    settings.connect('changed::integrate-system-menu', function () {
        if (indicator !== null) {
            disable();
            enable();
        }
    });
}
<commit_msg>Fixing extension not surviving lock/unlock<commit_after>/**
 * Copyright (c) 2014-2018 Eric Gach <eric.gach@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

const Me = imports.misc.extensionUtils.getCurrentExtension();
const Config = imports.misc.config;
const Gettext = imports.gettext.domain('desk-changer');
const Gio = imports.gi.Gio;
const Lang = imports.lang;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Util = imports.misc.util;
const _ = Gettext.gettext;

const Convenience = Me.imports.convenience;
const DeskChangerDaemon = Me.imports.daemon.DeskChangerDaemon;
const DeskChangerSettings = Me.imports.settings.DeskChangerSettings;
const DeskChangerVersion = Me.metadata.version;
const debug = Me.imports.utils.debug;
const Menu = Me.imports.menu;
const Ui = Me.imports.ui;

/**
 * This is the actual indicator that should be added to the main panel.
 *
 * @type {Lang.Class}
 */
const DeskChangerIndicator = new Lang.Class({
    Name: 'DeskChangerIndicator',
    Extends: PanelMenu.Button,

    _init: function (daemon) {
        this.settings = new DeskChangerSettings();
        this.parent(0.0, 'DeskChanger');
        this.daemon = daemon;

        this.actor.add_child(new Ui.DeskChangerIcon(this.daemon, this.settings));
        this.menu.addMenuItem(new Menu.DeskChangerProfileDesktop(this.settings));
        if (this.settings.update_lockscreen) {
            this.menu.addMenuItem(new Menu.DeskChangerProfileLockscreen(this.settings));
        }
        this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
        this.menu.addMenuItem(new Menu.DeskChangerSwitch(_('Change with Profile'), 'auto_rotate', this.settings));
        this.menu.addMenuItem(new Menu.DeskChangerSwitch(_('Notifications'), 'notifications', this.settings));
        this.menu.addMenuItem(new Menu.DeskChangerSwitch(_('Remember Profile State'), 'remember_profile_state', this.settings));

        if (Main.screenShield !== null) {
            this.menu.addMenuItem(new Menu.DeskChangerSwitch(_('Update Lock Screen'), 'update_lockscreen', this.settings));
        }

        this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
        this.menu.addMenuItem(new Menu.DeskChangerPreviewMenuItem(this.daemon));
        this.menu.addMenuItem(new Menu.DeskChangerOpenCurrent());
        this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
        this.menu.addMenuItem(new Menu.DeskChangerRotation(this.settings, true));
        this.menu.addMenuItem(new Menu.DeskChangerControls(this.daemon, this.settings));
        this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
        this.menu.addMenuItem(new Menu.DeskChangerDaemonControls(this.daemon));
        // Simple settings for the extension
        let settings = new PopupMenu.PopupMenuItem(_('DeskChanger Settings'));
        settings.connect('activate', function () {
            Util.spawn(['gnome-shell-extension-prefs', Me.metadata.uuid]);
        });
        this.menu.addMenuItem(settings);
        this.settings.connect('changed::update-lockscreen', Lang.bind(this, function () {
            if (this.settings.update_lockscreen) {
                this.menu.addMenuItem(new Menu.DeskChangerProfileLockscreen(this.settings), 1);
            } else {
                this.menu.box.get_children().map(function (actor) {
                    return actor._delegate;
                }).filter(function (item) {
                    item instanceof Menu.DeskChangerProfileLockscreen && item.destroy();
                });
            }
        }));
    },

    destroy: function () {
        this.parent();
        this.settings.destroy();
    }
});

const DeskChangerSystemIndicator = new Lang.Class({
    Name: 'DeskChangerSystemIndicator',
    Extends: PanelMenu.SystemIndicator,

    _init: function (daemon, menu) {
        this.parent();
        this.daemon = daemon;

        this.settings = new DeskChangerSettings();
        this._menu = new PopupMenu.PopupSubMenuMenuItem('DeskChanger', true);
        this._menu.icon.set_gicon(Gio.icon_new_for_string(Me.path + '/icons/wallpaper-icon.png'));
        this._menu.menu.addMenuItem(new Menu.DeskChangerProfileDesktop(this.settings, false));
        this._menu.menu.addMenuItem(new Menu.DeskChangerPreviewMenuItem(this.daemon));
        this._menu.menu.addMenuItem(new Menu.DeskChangerOpenCurrent());
        this._menu.menu.addMenuItem(new Menu.DeskChangerRotation(this.settings, false));
        this._menu.menu.addMenuItem(new Menu.DeskChangerControls(this.daemon, this.settings));
        this._menu.menu.addMenuItem(new Menu.DeskChangerDaemonControls(this.daemon));
        // Simple settings for the extension
        let settings = new PopupMenu.PopupMenuItem(_('DeskChanger Settings'));
        settings.connect('activate', function () {
            Util.spawn(['gnome-shell-extension-prefs', Me.metadata.uuid]);
        });
        this._menu.menu.addMenuItem(settings);
        let position = (parseInt(Config.PACKAGE_VERSION.split(".")[1]) < 18) ? this._menu.menu.numMenuItems - 2 : this._menu.menu.numMenuItems - 1;
        menu.addMenuItem(this._menu, position);
        this._indicator = null;
        this.settings.connect('changed::icon-preview', Lang.bind(this, this._update_indicator));
        this._update_indicator();
    },

    destroy: function () {
        if (this._indicator) {
            this._indicator.destroy();
        }

        this._menu.destroy();
        this.settings.destroy();
    },

    _update_indicator: function () {
        if (this._indicator !== null) {
            this.indicators.remove_actor(this._indicator);
            this._indicator.destroy();
            this._indicator = null;
        }

        if (this.settings.icon_preview) {
            this._indicator = new Ui.DeskChangerIcon(this.daemon, this.settings);
            this.indicators.add_actor(this._indicator);
            this._indicator.connect('notify::visible', Lang.bind(this, this._syncIndicatorsVisible));
            this._syncIndicatorsVisible();
        }
    }
});

let daemon, indicator, settings, shellSettings;
let changed_id, current_profile_id, notifications_id, random_id, rotation_id;

function disable() {
    debug('disabling extension');

    if (typeof indicator.destroy === "function") {
        indicator.destroy();
    }

    if (current_profile_id) {
        settings.disconnect(current_profile_id);
    }

    if (notifications_id) {
        settings.disconnect(notifications_id);
    }

    if (changed_id) {
        daemon.disconnect(changed_id);
    }

    if (random_id) {
        settings.disconnect(random_id);
    }

    if (rotation_id) {
        settings.disconnect(rotation_id);
    }

    changed_id = null;
    current_profile_id = null;
    notifications_id = null;
    random_id = null;
    rotation_id = null;
    indicator = null;
}

function enable() {
    debug('enabling extension');

    current_profile_id = settings.connect('changed::current-profile', function () {
        if (settings.notifications)
            Main.notify('Desk Changer', _('Profile changed to %s'.format(settings.current_profile)));
    });

    notifications_id = settings.connect('changed::notifications', function () {
        Main.notify('Desk Changer', ((settings.notifications) ? _('Notifications are now enabled') : _('Notifications are now disabled')));
    });

    changed_id = daemon.connect('changed', function (obj, wallpaper) {
        if (settings.notifications)
            Main.notify('Desk Changer', _('Wallpaper Changed: %s'.format(wallpaper)));
    });

    random_id = settings.connect('changed::random', function () {
        if (settings.notifications) {
            let message;

            if (settings.random) {
                message = _('Wallpapers will be shown in a random order');
            } else {
                message = _('Wallpapers will be shown in the order the were loaded');
            }

            Main.notify('Desk Changer', message);
        }
    });

    rotation_id = settings.connect('changed::rotation', function () {
        if (settings.notifications) {
            let message;
            switch (settings.rotation) {
                case 'interval':
                    message = _('Rotation will occur every %d seconds'.format(settings.interval));
                    break;
                case 'hourly':
                    message = _('Rotation will occur at the beginning of every hour');
                    break;
                default:
                    message = _('Rotation has been disabled');
                    break;
            }

            Main.notify('Desk Changer', message);
        }
    });

    if (!daemon.running && settings.auto_start) {
        // run if auto start is enabled and its not already running
        daemon.start();
    }

    if (settings.integrate_system_menu) {
        indicator = new DeskChangerSystemIndicator(daemon, Main.panel.statusArea.aggregateMenu.menu);
        Main.panel.statusArea.aggregateMenu._indicators.insert_child_at_index(indicator.indicators, 0);
    } else {
        indicator = new DeskChangerIndicator(daemon);
        Main.panel.addToStatusArea('deskchanger', indicator);
    }
}

function init() {
    Convenience.initTranslations();
    debug('initalizing extension version: %s'.format(DeskChangerVersion));
    settings = new DeskChangerSettings();
    shellSettings = new Gio.Settings({'schema': 'org.gnome.shell'});
    daemon = new DeskChangerDaemon(settings);
    if (Main.screenShield !== null) {
        daemon.lockscreen = Main.screenShield.locked;
        Main.screenShield.connect('locked-changed', function () {
            // lockscreen mode toggle through signals
            daemon.lockscreen = Main.screenShield.locked;
        });
    }

    Gio.DBus.session.connect('closed', function () {
        if (daemon.running) {
            daemon.stop();
        }
    });

    settings.connect('changed::integrate-system-menu', function () {
        if (indicator !== null) {
            disable();
            enable();
        }
    });
}
<|endoftext|>


<commit_before>/*
 * grunt-shopify-theme-settings
 * https://github.com/discolabs/grunt-shopify-theme-settings
 *
 * Copyright (c) 2014 Gavin Ballard
 * Licensed under the MIT license.
 */

'use strict';
var tidy = require('htmltidy').tidy;
var cheerio = require('cheerio');
var yaml = require('js-yaml');

module.exports = function(grunt) {

  grunt.registerTask('shopify_import_theme_settings', 'Grunt task to import settings.html into out settings.yml format.', function() {

    // Read options.
    var importFile = grunt.option('importFile');
    var exportFile = grunt.option('exportFile');

    // Mark this task as asynchronous.
    var done = this.async();

    // Check that an importFile option was provided.
    if(!importFile) {
      grunt.log.warn('You must provide the path to a settings.html file to import from with the --importFile argument.');
      return false;
    }

    // Check that an exportFile option was provided.
    if(!exportFile) {
      grunt.log.warn('You must provide the path to a settings.yml file to export to with the --exportFile argument.');
      return false;
    }

    // Check that the importFile provided is valid.
    if(!grunt.file.exists(importFile)) {
      grunt.log.warn('The specified file ' + importFile + ' does not exist!');
      return false;
    }

    // Read and tidy the input HTML for consistency.
    tidy(grunt.file.read(importFile), {}, function(err, html) {

      // Check to see if there were any errors tidying the HTML.
      if(err) {
        grunt.log.error(err);
        done(false);
      }

      // Parse the HTML using Cheerio.
      var $ = cheerio.load(html);

      // Extract sections from the parsed HTML.
      var sections = getSections($);

      //
      grunt.log.writeln(JSON.stringify(sections));

      // Write the output.
      grunt.file.write(exportFile, yaml.safeDump(sections));

      // Print a success message and mark the asynchronous task as done.
      grunt.log.writeln('File "' + exportFile + '" created.');
      done();
    });
  });

  /**
   * Extract a structured Javascript object from the given $ objects, which
   * represents a DOM tree parsed by Cheerio.
   */
  function getSections($) {
    // Create a sections object to return.
    var sections = {};

    // Iterate through each Fieldset ("Section").
    $('fieldset').each(function() {
      var $fieldset           = $(this),
          sectionName         = getSectionNameFromFieldset($, $fieldset),
          sectionSubsections  = getSectionSubsectionsFromFieldset($, $fieldset);

      sections[sectionName] = sectionSubsections;
    });

    return sections;
  }

  /**
   * Extract the name of this section from the given $fieldset.
   */
  function getSectionNameFromFieldset($, $fieldset) {
    return $fieldset.find('legend').first().text();
  }

  /**
   * Extract the subsections for this section from the given $fieldset.
   */
  function getSectionSubsectionsFromFieldset($, $fieldset) {
    // Create a subsections object to return.
    var subsections = {};

    // Iterate through each Table ("Subsection").
    $fieldset.children('table').each(function(i) {
      var $table            = $(this),
          subsectionName    = getSubsectionNameFromTable($, $table),
          subsectionFields  = getSubsectionFieldsFromTable($, $table);

      // If we couldn't extract a name from the subsection, generate one and mark the title as hidden.
      if(!subsectionName) {
        subsectionName = 'Untitled Subsection #' + i;
        subsectionFields.notitle = true;
      }

      subsections[subsectionName] = subsectionFields;
    });

    return subsections;
  }

  /**
   * Extract the name of this subsection from the given $table.
   */
  function getSubsectionNameFromTable($, $table) {
    // First, see if there's an explicit <h3> header before this table.
    var $h3 = $table.prev('h3');
    if($h3.length === 0) {
      return null;
    }
    return $h3.first().text();
  }

  /**
   * Extract the fields for this subsection from the given $table.
   */
  function getSubsectionFieldsFromTable($, $table) {
    return {};
  }

};<commit_msg>Further improvements to import.<commit_after>/*
 * grunt-shopify-theme-settings
 * https://github.com/discolabs/grunt-shopify-theme-settings
 *
 * Copyright (c) 2014 Gavin Ballard
 * Licensed under the MIT license.
 */

'use strict';
var tidy = require('htmltidy').tidy;
var cheerio = require('cheerio');
var yaml = require('js-yaml');

module.exports = function(grunt) {

  grunt.registerTask('shopify_import_theme_settings', 'Grunt task to import settings.html into out settings.yml format.', function() {

    // Read options.
    var importFile = grunt.option('importFile');
    var exportFile = grunt.option('exportFile');

    // Mark this task as asynchronous.
    var done = this.async();

    // Check that an importFile option was provided.
    if(!importFile) {
      grunt.log.warn('You must provide the path to a settings.html file to import from with the --importFile argument.');
      return false;
    }

    // Check that an exportFile option was provided.
    if(!exportFile) {
      grunt.log.warn('You must provide the path to a settings.yml file to export to with the --exportFile argument.');
      return false;
    }

    // Check that the importFile provided is valid.
    if(!grunt.file.exists(importFile)) {
      grunt.log.warn('The specified file ' + importFile + ' does not exist!');
      return false;
    }

    // Set up options to pass to HTMLTidy.
    var tidyOptions = {
      wrap: 0
    };

    // Read and tidy the input HTML for consistency.
    tidy(grunt.file.read(importFile), tidyOptions, function(err, html) {

      // Check to see if there were any errors tidying the HTML.
      if(err) {
        grunt.log.error(err);
        done(false);
      }

      // Parse the HTML using Cheerio.
      var $ = cheerio.load(html);

      // Extract sections from the parsed HTML.
      var sections = getSections($);

      // Write the output.
      grunt.file.write(exportFile, yaml.safeDump(sections));

      // Print a success message and mark the asynchronous task as done.
      grunt.log.writeln('File "' + exportFile + '" created.');
      done();
    });
  });

  /**
   * Extract a structured Javascript object from the given $ objects, which
   * represents a DOM tree parsed by Cheerio.
   */
  function getSections($) {
    // Create a sections object to return.
    var sections = {};

    // Iterate through each Fieldset ("Section").
    $('fieldset').each(function() {
      var $fieldset           = $(this),
          sectionName         = getSectionNameFromFieldset($, $fieldset),
          sectionSubsections  = getSectionSubsectionsFromFieldset($, $fieldset);

      sections[sectionName] = sectionSubsections;
    });

    return sections;
  }

  /**
   * Extract the name of this section from the given $fieldset.
   */
  function getSectionNameFromFieldset($, $fieldset) {
    return $fieldset.find('legend').first().text();
  }

  /**
   * Extract the subsections for this section from the given $fieldset.
   */
  function getSectionSubsectionsFromFieldset($, $fieldset) {
    // Create a subsections object to return.
    var subsections = {};

    // Iterate through each Table ("Subsection").
    $fieldset.children('table').each(function(i) {
      var $table            = $(this),
          subsectionName    = getSubsectionNameFromTable($, $table),
          subsectionFields  = {};

      // If we couldn't extract a name from the subsection, generate one and mark the title as hidden.
      if(!subsectionName) {
        subsectionName = 'Untitled Subsection #' + (i + 1);
        subsectionFields.notitle = true;
      }

      // Add any extracted fields to the fields hash.
      addSubsectionFieldsFromTable($, subsectionFields, $table);

      subsections[subsectionName] = subsectionFields;
    });

    return subsections;
  }

  /**
   * Extract the name of this subsection from the given $table.
   */
  function getSubsectionNameFromTable($, $table) {
    // First, see if there's an explicit <h3> header before this table.
    var $h3 = $table.prev('h3');
    if($h3.length === 0) {
      return null;
    }
    return $h3.first().text();
  }

  /**
   * Extract the fields for this subsection from the given $table and add
   * them to the given fields object.
   */
  function addSubsectionFieldsFromTable($, fields, $table) {
    // Iterate through each input inside the table.
    $table.find(':input').each(function(i) {
      var $input      = $(this),
          fieldLabel  = getFieldLabelFromInput($, $input);

      // If we couldn't extract a label from the field, generate one.
      if(!fieldLabel) {
        fieldLabel = 'Untitled Field #' + (i + 1);
      }

      fields[fieldLabel] = getFieldData($, $input);
    });

    return fields;
  }

  /**
   * Extract the field label from the given $input.
   */
  function getFieldLabelFromInput($, $input) {
    // Try and find a <label> element in the same row.
    var $label = $input.closest('tr').find('label');
    if($label.length === 0) {
      return null;
    }
    return $label.first().text();
  }

  /**
   * Extract field information from the given $input.
   */
  function getFieldData($, $input) {
    var fieldData = {};

    var fieldName = $input.attr('name');
    fieldData['name'] = fieldName;

    var fieldType = getFieldType($, $input);
    fieldData['type'] = fieldType;

    var fieldHelp = getFieldHelp($, $input);
    if(fieldHelp) {
      fieldData['help'] = fieldHelp;
    }

    // Add options for select and font types.
    if(fieldType === 'select' || fieldType === 'font') {
      fieldData['options'] = getFieldOptions($, $input);
    }

    // Add width/height for file types.
    if(fieldType === 'file') {
      if($input.data('maxWidth')) {
        fieldData['width'] = $input.data('maxWidth');
      }
      if($input.data('maxHeight')) {
        fieldData['height'] = $input.data('maxHeight');
      }
    }

    // Add cols/rows for text-multi types.
    if(fieldType === 'text-multi') {
      if($input.attr('cols')) {
        fieldData['cols'] = $input.attr('cols');
      }
      if($input.attr('rows')) {
        fieldData['rows'] = $input.attr('rows');
      }
    }

    return fieldData;
  }

  /**
   * Get the field type of the passed $input.
   */
  function getFieldType($, $input) {
    // Check for simple properties that determine type.
    if($input.is('textarea')) { return 'text-multi'; }
    if($input.is('[type="checkbox"]')) { return 'checkbox'; }
    if($input.is('[type="file"]')) { return 'file'; }

    // Check for <select>-based inputs.
    if($input.is('select')) {
      if($input.hasClass('font')) { return 'font'; }
      if($input.hasClass('blog')) { return 'blog'; }
      if($input.hasClass('collection')) { return 'collection'; }
      if($input.hasClass('linklist')) { return 'linklist'; }
      if($input.hasClass('page')) { return 'page'; }
      if($input.hasClass('snippet')) { return 'snippet'; }
      return 'select';
    }

    // Text-based inputs.
    if($input.hasClass('color')) { return 'color'; }

    return 'text-single';
  }

  /**
   * Try to extract any help text for the given field.
   */
  function getFieldHelp($, $input) {
    // Try and find a <small> element in the same row.
    var $small = $input.closest('tr').find('small');
    if($small.length === 0) {
      return null;
    }
    return $small.first().html();
  }

  /**
   * Get the options for a field.
   */
  function getFieldOptions($, $input) {
    var options = {};

    $input.find('option').each(function() {
      var $option = $(this);
      options[$option.attr('value')] = $option.text();
    });

    return options;
  }

};<|endoftext|>


<commit_before>// SearchService.js - in api/services
var _ = require('lodash');
module.exports = {

  DAILY: 86400,

  queries: {
    aggregations: {
      download_per_package : {
        "terms" : { "field" : "package", "size" : 10000 }, //calculate percentile over all packages
        "aggs" : {
            "download_count" : { "value_count" : { "field" : "package" } }
        }
      },
      download_percentiles: {
        "percentiles_bucket": {
            "buckets_path": "download_per_package>download_count",
            "percents": _.range(1.00001, 100, 1).concat([99.5, 99.9, 99.99])

        }
      },
      "last_month_per_day": {
          "date_histogram" : {
              "field" : "datetime",
              "interval" : "day"
          }
      }
    },
    filters: {
      lastMonthStats: {
        "bool": {
          "filter": [
            {
                "term": { "_type": "stats" }
            },
            {
              "range": {
                  "datetime":  {
                      "gte" : "now-1M/d",
                      "lt" :  "now/d"
                  }
              }
            }
          ]
        }
      },
      lastMonthDownloads: function(n){
        return {
        "size":"10000",
        "fields":["datetime","ip_id","package","version"],
        "sort":[ {"ip_id":{"order":"asc","ignore_unmapped" : true}},
                    {"datetime":{"order":"asc","ignore_unmapped" : true}}],
        "query":{
            "bool": {
                  "filter": [
                    {
                        "term": { "_type": "stats" }
                    },
                    {
                      "range": {
                          "datetime":  {
                              "gte" : "now-"+(n+1)+"d/d",
                              "lt" :  "now-"+n+"d/d"
                          }
                      }
                    }
                  ]
                  }
              }

          }
        }
    }
  },

  lastMonthPercentiles: function() {
    var body = {
      "query": ElasticSearchService.queries.filters.lastMonthStats,
      "size": 0, // do not retrieve data, we are only interested in aggregation data
      "aggs" : _.pick(ElasticSearchService.queries.aggregations, ['download_per_package', 'download_percentiles'])
    };

    return es.search({
      index: 'stats',
      requestCache: true, //cache the result
      body: body
    }).then(function(response) {
      return response.aggregations.download_percentiles.values;
    });

  },

  lastMonthDownloadCount: function() {
    var body = {
      "query": ElasticSearchService.queries.filters.lastMonthStats,
      "size": 0, // do not retrieve data, we are only interested in aggregation data
      "aggs" : {
        download_per_package: ElasticSearchService.queries.aggregations.download_per_package
      }
    };

    return es.search({
      index: 'stats',
      requestCache: true, //cache the result
      body: body
    }).then(function(response) {
      return response.aggregations.download_per_package.buckets;
    });

  },

  lastMonthPerDay: function(packageName) {
    var lastMonthPackageFilter =  _.cloneDeep(ElasticSearchService.queries.filters.lastMonthStats);
    lastMonthPackageFilter.bool.filter.push({ "term": { "package": packageName } });
    var body = {
      "query": lastMonthPackageFilter,
      "size": 0, // do not retrieve data, we are only interested in aggregation data
      "aggs" : {
        last_month_per_day: ElasticSearchService.queries.aggregations.last_month_per_day
      }
    };

    return es.search({
      index: 'stats',
      requestCache: true, //cache the result,
      body: body
    }).then(function(response) {
      return response.aggregations.last_month_per_day.buckets;
    });
  },

  cachedLastMonthPercentiles: function(res) {
    return RedisService.getJSONFromCache('percentiles', res, RedisService.DAILY, function() {
      return ElasticSearchService.lastMonthPercentiles();
    });
  },
  //download first 10000 results and proceed by processing and scrolling
  dailyDownloadsBulk:function(days,callback){
      hits = [];
      var body = ElasticSearchService.queries.filters.lastMonthDownloads(days);
      return es.search({
      scroll:'5M',
      index: 'stats',
      body: body,
      },function processAndGetMore(error,response){
            //check the response
        if (typeof response == "undefined" || typeof response.hits == "undefined") {
          var err ="you received an undefined response, response:"+response+
          "\n this was probably caused because there were no stats yet for this day"+
          "\n or processing time took over 5 minutes (the scroll interval";
        callback(err);
        }
        DownloadStatsService.processDownloads(response,{},{},10000,callback);
        });
  },
  //scroll further in search result, when response already contains a scroll id
  scrollDailyDownloadsBulk:function(response,date,directDownloads,indirectDownloads,total,callback){
    console.log("processing next 10000 records");
    if (response.hits.total > total) {
        // now we can call scroll over and over
        es.scroll({
          scrollId: response._scroll_id,
          scroll: '5M'
        }, function processScroll(error,response){
            if (typeof response == "undefined" || typeof response.hits == "undefined") {
              var err ="you received an undefined response, response:"+response+
              "\n this was probably caused because there were no stats yet for this day"+
              "\n or processing time took over 5 minutes (the scroll interval";
            callback(err);
            }
            return DownloadStatsService.processDownloads(response,directDownloads,indirectDownloads,total+10000,callback);
        });
      } else {
        //write the responses to the database when done
          DownloadStatsService.writeSplittedDownloadCounts(date,directDownloads,indirectDownloads).then(function(result){
            callback(null,result);
          });

      }
  }
};
<commit_msg>fix indentation<commit_after>// SearchService.js - in api/services
var _ = require('lodash');
module.exports = {

  DAILY: 86400,

  queries: {
    aggregations: {
      download_per_package : {
        "terms" : { "field" : "package", "size" : 10000 }, //calculate percentile over all packages
        "aggs" : {
            "download_count" : { "value_count" : { "field" : "package" } }
        }
      },
      download_percentiles: {
        "percentiles_bucket": {
            "buckets_path": "download_per_package>download_count",
            "percents": _.range(1.00001, 100, 1).concat([99.5, 99.9, 99.99])

        }
      },
      "last_month_per_day": {
          "date_histogram" : {
              "field" : "datetime",
              "interval" : "day"
          }
      }
    },
    filters: {
      lastMonthStats: {
        "bool": {
          "filter": [
            {
                "term": { "_type": "stats" }
            },
            {
              "range": {
                  "datetime":  {
                      "gte" : "now-1M/d",
                      "lt" :  "now/d"
                  }
              }
            }
          ]
        }
      },
      lastMonthDownloads: function(n){
        return {
          "size": "10000",
          "fields": ["datetime","ip_id","package","version"],
          "sort": [
            {"ip_id":{"order":"asc","ignore_unmapped" : true}},
            {"datetime":{"order":"asc","ignore_unmapped" : true}}
          ],
          "query":{
            "bool": {
              "filter": [
                {
                  "term": { "_type": "stats" }
                },
                {
                  "range": {
                    "datetime":  {
                      "gte" : "now-"+(n+1)+"d/d",
                      "lt" :  "now-"+n+"d/d"
                    }
                  }
                }
              ]
            }
          }

        };
      }
    }
  },

  lastMonthPercentiles: function() {
    var body = {
      "query": ElasticSearchService.queries.filters.lastMonthStats,
      "size": 0, // do not retrieve data, we are only interested in aggregation data
      "aggs" : _.pick(ElasticSearchService.queries.aggregations, ['download_per_package', 'download_percentiles'])
    };

    return es.search({
      index: 'stats',
      requestCache: true, //cache the result
      body: body
    }).then(function(response) {
      return response.aggregations.download_percentiles.values;
    });

  },

  lastMonthDownloadCount: function() {
    var body = {
      "query": ElasticSearchService.queries.filters.lastMonthStats,
      "size": 0, // do not retrieve data, we are only interested in aggregation data
      "aggs" : {
        download_per_package: ElasticSearchService.queries.aggregations.download_per_package
      }
    };

    return es.search({
      index: 'stats',
      requestCache: true, //cache the result
      body: body
    }).then(function(response) {
      return response.aggregations.download_per_package.buckets;
    });

  },

  lastMonthPerDay: function(packageName) {
    var lastMonthPackageFilter =  _.cloneDeep(ElasticSearchService.queries.filters.lastMonthStats);
    lastMonthPackageFilter.bool.filter.push({ "term": { "package": packageName } });
    var body = {
      "query": lastMonthPackageFilter,
      "size": 0, // do not retrieve data, we are only interested in aggregation data
      "aggs" : {
        last_month_per_day: ElasticSearchService.queries.aggregations.last_month_per_day
      }
    };

    return es.search({
      index: 'stats',
      requestCache: true, //cache the result,
      body: body
    }).then(function(response) {
      return response.aggregations.last_month_per_day.buckets;
    });
  },

  cachedLastMonthPercentiles: function(res) {
    return RedisService.getJSONFromCache('percentiles', res, RedisService.DAILY, function() {
      return ElasticSearchService.lastMonthPercentiles();
    });
  },

  //download first 10000 results and proceed by processing and scrolling
  dailyDownloadsBulk:function(days, callback){
    var body = ElasticSearchService.queries.filters.lastMonthDownloads(days);

    return es.search({
      scroll:'5M',
      index: 'stats',
      body: body,
    }, function processAndGetMore(error,response){
      //check the response
      if (typeof response == "undefined" || typeof response.hits == "undefined") {
        var err ="you received an undefined response, response:"+response+
        "\n this was probably caused because there were no stats yet for this day"+
        "\n or processing time took over 5 minutes (the scroll interval";
        callback(err);
      }
      DownloadStatsService.processDownloads(response,{},{},10000,callback);
    });
  },

  //scroll further in search result, when response already contains a scroll id
  scrollDailyDownloadsBulk: function(response,date,directDownloads,indirectDownloads,total,callback) {
    console.log("processing next 10000 records");
    if (response.hits.total > total) {
      // now we can call scroll over and over
      es.scroll({
        scrollId: response._scroll_id,
        scroll: '5M'
      }, function processScroll(error,response){
        if (typeof response == "undefined" || typeof response.hits == "undefined") {
          var err ="you received an undefined response, response:"+response+
          "\n this was probably caused because there were no stats yet for this day"+
          "\n or processing time took over 5 minutes (the scroll interval";
          callback(err);
        }
        return DownloadStatsService.processDownloads(response,directDownloads,indirectDownloads,total+10000,callback);
      });
    } else {
      //write the responses to the database when done
      DownloadStatsService.writeSplittedDownloadCounts(date,directDownloads,indirectDownloads).then(function(result){
        callback(null,result);
      });
    }
  }
};
<|endoftext|>


<commit_before>/*!
 * jQuery Fork stuff
 */

/**
 * Share-button
 * This plugin will convert a single item into a list with share-options.
 *
 * What information will be used.
 * - Url that will be shared: if there is a href-attribute this value will be used as url, if not the url of the current page will be used
 * - The title of the item:
 * 		1. if the OpenGraph-title-tag is provided, the value of the tag is used.
 * 		2. if the title-attribute is used this value will be used in favor of the OpenGraph-title-tag.
 * 		3. if the data-title-attribute is set this value will be used, OpenGraph and title-attribute will be ignored.
 * 		4. as a fallback the value of the title-tag is used.
 * - The description (used by: delicious, linkedin, netlog, twitter)
 * 		1. if the OpenGraph-description-tag is provided, that value will be used.
 * 		2. if the data-description-attribute is set this value will be used, even if the OpenGraph-image-tag is provided.
 * 		3. no description will be used.
 * - The image (used by: netlog)
 * 		1. if the OpenGraph-image tag is available the value of this tag will be used.
 * 		2. if the data-image-attribute is set this value will be used, even if the OpenGraph-image-tag is provided.
 * 		3. the default image if there is one provided.
 * 		4. no image will be used .
 *
 * Possible options:
 * - debug			if debug is enabled a warning will be logged to the console if og-parameters aren't available, possible values are: true, false.
 * - default_image	the image that will be used by default.
 * - sequence		an array containing the names of the share-items in the wanted sequence.
 * - isDropdown		will the plugin be used as a dropdownmenu? If so we will hide it by default an show on click/hover.
 *
 * @author	Tijs Verkoyen <tijs@sumocoders.be>
 */
(function($)
{
	$.fn.shareMenu = function(options)
	{
		var twitterLoaded = false;
		var linkedInLoaded = false;
		var googlePlusLoaded = false;
		var pinterestLoaded = false;

		// define defaults
		var defaults =
		{
			debug: false,
			default_image: document.location.protocol + '//' + document.location.host + '/apple-touch-icon.png',
			sequence: ['facebook', 'twitter', 'netlog', 'linkedin', 'digg', 'delicious', 'googleplus', 'pinterest'],
			isDropdown: true,

			delicious: { name: 'delicious', show: true, label: 'Delicious'},
			digg: { name: 'digg', show: true, label: 'Digg' },
			facebook: { name: 'facebook', show: true, width: 90, verb: 'like', colorScheme: 'light', font : 'arial' },
			linkedin: { name: 'linkedin', show: true, label: 'LinkedIn' },
			netlog: { name: 'netlog', show: true, label: 'Netlog' },
			twitter: { name: 'twitter', show: true, label: 'tweet' },
			googleplus: { name: 'googleplus', show: true, label: 'Google +1' },
			pinterest: { name: 'pinterest', show: true, label: 'Pin it', countLayout: 'horizontal' } // possible values for countLayout: horizontal/vertical/none
		};

		// extend options
		var options = $.extend(true, defaults, options);

		return this.each(function()
		{
			// grab current element
			var $this = $(this);

			// init vars
			var link = document.location.href;
			var title = $('title').html();
			var description = '';
			var image = '';

			// get the link
			if($this.attr('href') != undefined) link = $this.attr('href');
			if(link.substr(0, 1) == '#') link = document.location.href;
			if(link.substr(0, 4) != 'http') link = document.location.protocol + '//' + document.location.host + link;

			// get the title
			if($('meta[property="og:title"]').attr('content') != undefined) title = $('meta[property="og:title"]').attr('content');
			if($this.attr('title') != undefined) title = $this.attr('title');
			if($this.data('title') != undefined) title = $this.data('title');

			// get the description
			if($('meta[property="og:description"]').attr('content') != undefined) description = $('meta[property="og:description"]').attr('content');
			if($this.data('description') != undefined) description = $this.data('description');

			// get the image
			if($('meta[property="og:image"]').attr('content') != undefined) image = $('meta[property="og:image"]').attr('content');
			if($this.data('image') != undefined) image = $this.data('image');
			if(image == '' && options.default_image != '') image = options.default_image;

			// start HTML
			if(options.isDropdown) var html = '
' + "\n";
			else var html = '
' + "\n";

			// loop items
			for(var i in options.sequence)
			{
				// is the option enabled?
				if(options[options.sequence[i]].show)
				{
					// based on the type we should generate the correct markup
					switch(options[options.sequence[i]].name)
					{
						// delicious
						case 'delicious':
							// build url
							var url = 'http://delicious.com/save?url=' + encodeURIComponent(link);
							if(title != '') url += '&title=' + title;
							if(description != '') url += '&notes=' + description;

							// add html
							html += '
' +
									'	' +
									'		' +
									'		' + options.delicious.label + '' +
									'	' +
									'
' + "\n";
						break;

						// digg
						case 'digg':
							// build url
							var url = 'http://digg.com/submit?url=' + encodeURIComponent(link);
							if(title != '') url += '&title=' + title;

							// add html
							html += '
' +
									'	' +
									'		' +
									'		' + options.digg.label + '' +
									'	' +
									'
' + "\n";
						break;

						// facebook?
						case 'facebook':
							// check for OG-data.
							if(options.debug && $('meta[property^="og"]').length == 0) console.log('You should provide OpenGraph data.');

							// add html
							html += '
';

							// check if the FB-object is available
							if(typeof FB != 'object')
							{
								html += '';
							}
							else
							{
								html += '<fb:like href="' + link + '" send="false" layout="button_count" width="' + options.facebook.width + '" show_face="false" action="' + options.facebook.verb + '" colorscheme="' + options.facebook.colorScheme + '" font="' + options.facebook.font  + '"></fb:like>' + "\n";
							}

							// end html
							html += '
';
						break;

						// linkedin
						case 'linkedin':
							if(!linkedInLoaded)
							{
								// loop all script to check if the twitter-widget is already loaded
								$('script').each(function()
								{
									if($(this).attr('src') == 'http://platform.linkedin.com/in.js') linkedInLoaded = true;
								});

								// not loaded?
								if(!linkedInLoaded)
								{
									// create the script tag
									var script = document.createElement('script')
									script.src = 'http://platform.linkedin.com/in.js';

									// add into head
									$('head').after(script);

									// reset var
									linkedInLoaded = true;
								}
							}

							// build url
							var url = encodeURIComponent(link);

							// add html
							html += '
' +
									'	' +
									'
' + "\n";
						break;

						// netlog?
						case 'netlog':
							// build url
							var url = 'http://www.netlog.com/go/manage/links/view=save&origin=external&url=' + encodeURIComponent(link);
							if(title != '') url += '&title=' + title;
							if(description != '') url += '&description=' + description;
							if(image != '') url += '&thumb=' + encodeURIComponent(image);
							url += '&referer=' + encodeURIComponent(document.location);

							// add html
							html += '
' +
									'	' +
									'		' +
									'		' + options.netlog.label + '' +
									'	' +
									'
' + "\n";
						break;

						// twitter
						case 'twitter':
							if(!twitterLoaded)
							{
								// loop all script to check if the twitter-widget is already loaded
								$('script').each(function()
								{
									if($(this).attr('src') == 'http://platform.twitter.com/widgets.js') twitterLoaded = true;
								});

								// not loaded?
								if(!twitterLoaded)
								{
									// create the script tag
									var script = document.createElement('script')
									script.src = 'http://platform.twitter.com/widgets.js';

									// add into head
									$('head').after(script);

									// reset var
									twitterLoaded = true;
								}
							}

							// build & add html
							html += '
' +
									'	' + options.twitter.label  + '';
							html += '
';
						break;

						// google plus
						case 'googleplus':
							if(!googlePlusLoaded)
							{
								// loop all script to check if the twitter-widget is already loaded
								$('script').each(function()
								{
									if($(this).attr('src') == 'https://apis.google.com/js/plusone.js') googlePlusLoaded = true;
								});

								// not loaded?
								if(!googlePlusLoaded)
								{
									// create the script tag
									var script = document.createElement('script')
									script.src = 'https://apis.google.com/js/plusone.js';

									// add into head
									$('head').after(script);

									// reset var
									googlePlusLoaded = true;
								}
							}

							// build & add html
							html += '
' +
							'

';
							html += '
';
						break;

						// pinterest
						case 'pinterest':
							if(image != '')
							{
								if(!pinterestLoaded)
								{
									// loop all script to check if the google plus widget is already loaded
									$('script').each(function()
									{
										if($(this).attr('src') == '//assets.pinterest.com/js/pinit.js') pinterestLoaded = true;
									});

									// not loaded?
									if(!pinterestLoaded)
									{
										// create the script tag
										var script = document.createElement('script')
										script.src = '//assets.pinterest.com/js/pinit.js';

										// add into head
										$('head').after(script);

										// reset var
										pinterestLoaded = true;
									}

									if(typeof options[options.sequence[i]].countLayout != 'undefined') countLayout = options[options.sequence[i]].countLayout;
									else countLayout = 'none';
									if(countLayout != 'horizontal' || countLayout != 'vertical' || countLayout != 'none') countLayout = 'none';

									// build & add html
									html += '
' +
									'	' +
										'';
									html += '
';
								}
							}
						break;
					}
				}
			}

			// end html
			html += '
';

			// append to current element
			$this.append(html);

			if(options.isDropdown)
			{
				// bind click
				$this.on('click', function(e)
				{
					// toggle menu
					$this.find('ul.shareMenu').toggle();
				});

				$this.hover(
					function()
					{
						$this.find('ul.shareMenu').show();
					},
					function()
					{
						$this.find('ul.shareMenu').hide();
					}
				);
			}
		});
	};
})(jQuery);<commit_msg>jquery.extend with true (deep extend) doesn't overwrite an array but merges it. I've split up the defaults into defaults and settings so that they both can be used by jquery.extend. But only the settings will do a deep extend.<commit_after>/*!
 * jQuery Fork stuff
 */

/**
 * Share-button
 * This plugin will convert a single item into a list with share-options.
 *
 * What information will be used.
 * - Url that will be shared: if there is a href-attribute this value will be used as url, if not the url of the current page will be used
 * - The title of the item:
 * 		1. if the OpenGraph-title-tag is provided, the value of the tag is used.
 * 		2. if the title-attribute is used this value will be used in favor of the OpenGraph-title-tag.
 * 		3. if the data-title-attribute is set this value will be used, OpenGraph and title-attribute will be ignored.
 * 		4. as a fallback the value of the title-tag is used.
 * - The description (used by: delicious, linkedin, netlog, twitter)
 * 		1. if the OpenGraph-description-tag is provided, that value will be used.
 * 		2. if the data-description-attribute is set this value will be used, even if the OpenGraph-image-tag is provided.
 * 		3. no description will be used.
 * - The image (used by: netlog)
 * 		1. if the OpenGraph-image tag is available the value of this tag will be used.
 * 		2. if the data-image-attribute is set this value will be used, even if the OpenGraph-image-tag is provided.
 * 		3. the default image if there is one provided.
 * 		4. no image will be used .
 *
 * Possible options:
 * - debug			if debug is enabled a warning will be logged to the console if og-parameters aren't available, possible values are: true, false.
 * - default_image	the image that will be used by default.
 * - sequence		an array containing the names of the share-items in the wanted sequence.
 * - isDropdown		will the plugin be used as a dropdownmenu? If so we will hide it by default an show on click/hover.
 *
 * @author	Tijs Verkoyen <tijs@sumocoders.be>
 */
(function($)
{
	$.fn.shareMenu = function(options)
	{
		var twitterLoaded = false;
		var linkedInLoaded = false;
		var googlePlusLoaded = false;
		var pinterestLoaded = false;

		// define defaults
		var defaults =
		{
			debug: false,
			default_image: document.location.protocol + '//' + document.location.host + '/apple-touch-icon.png',
			sequence: ['facebook', 'twitter', 'netlog', 'linkedin', 'digg', 'delicious', 'googleplus', 'pinterest'],
			isDropdown: true,
		}
		var settings =
		{
			delicious: { name: 'delicious', show: true, label: 'Delicious'},
			digg: { name: 'digg', show: true, label: 'Digg' },
			facebook: { name: 'facebook', show: true, width: 90, verb: 'like', colorScheme: 'light', font : 'arial' },
			linkedin: { name: 'linkedin', show: true, label: 'LinkedIn' },
			netlog: { name: 'netlog', show: true, label: 'Netlog' },
			twitter: { name: 'twitter', show: true, label: 'tweet' },
			googleplus: { name: 'googleplus', show: true, label: 'Google +1' },
			pinterest: { name: 'pinterest', show: true, label: 'Pin it', countLayout: 'horizontal' } // possible values for countLayout: horizontal/vertical/none
		};

		// extend options
		var options = $.extend(defaults, options);
		options = $.extend(true, settings, options);

		return this.each(function()
		{
			// grab current element
			var $this = $(this);

			// init vars
			var link = document.location.href;
			var title = $('title').html();
			var description = '';
			var image = '';

			// get the link
			if($this.attr('href') != undefined) link = $this.attr('href');
			if(link.substr(0, 1) == '#') link = document.location.href;
			if(link.substr(0, 4) != 'http') link = document.location.protocol + '//' + document.location.host + link;

			// get the title
			if($('meta[property="og:title"]').attr('content') != undefined) title = $('meta[property="og:title"]').attr('content');
			if($this.attr('title') != undefined) title = $this.attr('title');
			if($this.data('title') != undefined) title = $this.data('title');

			// get the description
			if($('meta[property="og:description"]').attr('content') != undefined) description = $('meta[property="og:description"]').attr('content');
			if($this.data('description') != undefined) description = $this.data('description');

			// get the image
			if($('meta[property="og:image"]').attr('content') != undefined) image = $('meta[property="og:image"]').attr('content');
			if($this.data('image') != undefined) image = $this.data('image');
			if(image == '' && options.default_image != '') image = options.default_image;

			// start HTML
			if(options.isDropdown) var html = '
' + "\n";
			else var html = '
' + "\n";

			// loop items
			for(var i in options.sequence)
			{
				// is the option enabled?
				if(options[options.sequence[i]].show)
				{
					// based on the type we should generate the correct markup
					switch(options[options.sequence[i]].name)
					{
						// delicious
						case 'delicious':
							// build url
							var url = 'http://delicious.com/save?url=' + encodeURIComponent(link);
							if(title != '') url += '&title=' + title;
							if(description != '') url += '&notes=' + description;

							// add html
							html += '
' +
									'	' +
									'		' +
									'		' + options.delicious.label + '' +
									'	' +
									'
' + "\n";
						break;

						// digg
						case 'digg':
							// build url
							var url = 'http://digg.com/submit?url=' + encodeURIComponent(link);
							if(title != '') url += '&title=' + title;

							// add html
							html += '
' +
									'	' +
									'		' +
									'		' + options.digg.label + '' +
									'	' +
									'
' + "\n";
						break;

						// facebook?
						case 'facebook':
							// check for OG-data.
							if(options.debug && $('meta[property^="og"]').length == 0) console.log('You should provide OpenGraph data.');

							// add html
							html += '
';

							// check if the FB-object is available
							if(typeof FB != 'object')
							{
								html += '';
							}
							else
							{
								html += '<fb:like href="' + link + '" send="false" layout="button_count" width="' + options.facebook.width + '" show_face="false" action="' + options.facebook.verb + '" colorscheme="' + options.facebook.colorScheme + '" font="' + options.facebook.font  + '"></fb:like>' + "\n";
							}

							// end html
							html += '
';
						break;

						// linkedin
						case 'linkedin':
							if(!linkedInLoaded)
							{
								// loop all script to check if the twitter-widget is already loaded
								$('script').each(function()
								{
									if($(this).attr('src') == 'http://platform.linkedin.com/in.js') linkedInLoaded = true;
								});

								// not loaded?
								if(!linkedInLoaded)
								{
									// create the script tag
									var script = document.createElement('script')
									script.src = 'http://platform.linkedin.com/in.js';

									// add into head
									$('head').after(script);

									// reset var
									linkedInLoaded = true;
								}
							}

							// build url
							var url = encodeURIComponent(link);

							// add html
							html += '
' +
									'	' +
									'
' + "\n";
						break;

						// netlog?
						case 'netlog':
							// build url
							var url = 'http://www.netlog.com/go/manage/links/view=save&origin=external&url=' + encodeURIComponent(link);
							if(title != '') url += '&title=' + title;
							if(description != '') url += '&description=' + description;
							if(image != '') url += '&thumb=' + encodeURIComponent(image);
							url += '&referer=' + encodeURIComponent(document.location);

							// add html
							html += '
' +
									'	' +
									'		' +
									'		' + options.netlog.label + '' +
									'	' +
									'
' + "\n";
						break;

						// twitter
						case 'twitter':
							if(!twitterLoaded)
							{
								// loop all script to check if the twitter-widget is already loaded
								$('script').each(function()
								{
									if($(this).attr('src') == 'http://platform.twitter.com/widgets.js') twitterLoaded = true;
								});

								// not loaded?
								if(!twitterLoaded)
								{
									// create the script tag
									var script = document.createElement('script')
									script.src = 'http://platform.twitter.com/widgets.js';

									// add into head
									$('head').after(script);

									// reset var
									twitterLoaded = true;
								}
							}

							// build & add html
							html += '
' +
									'	' + options.twitter.label  + '';
							html += '
';
						break;

						// google plus
						case 'googleplus':
							if(!googlePlusLoaded)
							{
								// loop all script to check if the twitter-widget is already loaded
								$('script').each(function()
								{
									if($(this).attr('src') == 'https://apis.google.com/js/plusone.js') googlePlusLoaded = true;
								});

								// not loaded?
								if(!googlePlusLoaded)
								{
									// create the script tag
									var script = document.createElement('script')
									script.src = 'https://apis.google.com/js/plusone.js';

									// add into head
									$('head').after(script);

									// reset var
									googlePlusLoaded = true;
								}
							}

							// build & add html
							html += '
' +
							'

';
							html += '
';
						break;

						// pinterest
						case 'pinterest':
							if(image != '')
							{
								if(!pinterestLoaded)
								{
									// loop all script to check if the google plus widget is already loaded
									$('script').each(function()
									{
										if($(this).attr('src') == '//assets.pinterest.com/js/pinit.js') pinterestLoaded = true;
									});

									// not loaded?
									if(!pinterestLoaded)
									{
										// create the script tag
										var script = document.createElement('script')
										script.src = '//assets.pinterest.com/js/pinit.js';

										// add into head
										$('head').after(script);

										// reset var
										pinterestLoaded = true;
									}

									if(typeof options[options.sequence[i]].countLayout != 'undefined') countLayout = options[options.sequence[i]].countLayout;
									else countLayout = 'none';
									if(countLayout != 'horizontal' || countLayout != 'vertical' || countLayout != 'none') countLayout = 'none';

									// build & add html
									html += '
' +
									'	' +
										'';
									html += '
';
								}
							}
						break;
					}
				}
			}

			// end html
			html += '
';

			// append to current element
			$this.append(html);

			if(options.isDropdown)
			{
				// bind click
				$this.on('click', function(e)
				{
					// toggle menu
					$this.find('ul.shareMenu').toggle();
				});

				$this.hover(
					function()
					{
						$this.find('ul.shareMenu').show();
					},
					function()
					{
						$this.find('ul.shareMenu').hide();
					}
				);
			}
		});
	};
})(jQuery);<|endoftext|>


<commit_before>YUI().use( "node", "io-base", "io-form", "json-parse", "node-event-simulate", function(Y) {
    var form = Y.one('#commentForm');
    var formError = Y.one('#formError');
    var formSuccess = Y.one('#formSuccess');
    var submitButton = Y.one( '#commentForm input[name^=AddComment]');
    var commentSort = Y.one( '#comments-sort' );

    form.on( 'submit', function(evt) {
        formError.setHTML('');
        formSuccess.setHTML('');

        evt.preventDefault();
        Y.io( window.url, {
            method: 'POST',
            form: {
                id: form,
                useDisabled: true
            },
            on: {
                start: function( id, args ) {
                    submitButton.set('disabled', true);
                },
                success: function( id, response, args ) {
                    var data = response.responseText;
                    formSuccess.setHTML( data );
                    form.remove();
                },
                failure: function(id, response, args ) {
                    data = Y.JSON.parse( response.responseText );
                    var error = "";

                    Y.Array.each( Object.keys(data), function( key ) {
                        error += data[key] + "
";
                    });
                    formError.setHTML( error );
                    Y.one("a.captcha_reload").simulate("click");
                    submitButton.set('disabled', false);
                }
            }
        });
    });

    if( commentSort && commentSort.length){
        commentSort.on( 'change', function(evt) {
            var sort = this.get('value').split("_")[0];
            var order = this.get('value').split("_")[1];
            var url = window.full_url;

            window.location.href = url + "/(cSort)/" + sort + "/(cOrder)/" + order + "/?#comments";
        });
    }

});<commit_msg>More generic JS element selection (input tag not required anymore)<commit_after>YUI().use( "node", "io-base", "io-form", "json-parse", "node-event-simulate", function(Y) {
    var form = Y.one('#commentForm');
    var formError = Y.one('#formError');
    var formSuccess = Y.one('#formSuccess');
    var submitButton = Y.one( '#commentForm [name^=AddComment]');
    var commentSort = Y.one( '#comments-sort' );

    form.on( 'submit', function(evt) {
        formError.setHTML('');
        formSuccess.setHTML('');

        evt.preventDefault();
        Y.io( window.url, {
            method: 'POST',
            form: {
                id: form,
                useDisabled: true
            },
            on: {
                start: function( id, args ) {
                    submitButton.set('disabled', true);
                },
                success: function( id, response, args ) {
                    var data = response.responseText;
                    formSuccess.setHTML( data );
                    form.remove();
                },
                failure: function(id, response, args ) {
                    data = Y.JSON.parse( response.responseText );
                    var error = "";

                    Y.Array.each( Object.keys(data), function( key ) {
                        error += data[key] + "
";
                    });
                    formError.setHTML( error );
                    Y.one("a.captcha_reload").simulate("click");
                    submitButton.set('disabled', false);
                }
            }
        });
    });

    if( commentSort && commentSort.length){
        commentSort.on( 'change', function(evt) {
            var sort = this.get('value').split("_")[0];
            var order = this.get('value').split("_")[1];
            var url = window.full_url;

            window.location.href = url + "/(cSort)/" + sort + "/(cOrder)/" + order + "/?#comments";
        });
    }

});<|endoftext|>


<commit_before>// debug purposes only
function dump(obj) {
    var str = "";
    for (var prop in obj) {
        str += prop + "     ";
    }
    return str;
}

var app = {
    initialize: function() {
        this.bindEvents();
    },
    bindEvents: function() {
        document.addEventListener('deviceready', this.onDeviceReady, false);
    },
    onDeviceReady: function() {
        document.getElementById('serverConnect')
            .addEventListener('click', app.onServerConnect, false);
        console.log('ready');
    },
    onServerConnect: function(ev) {
        app.conn = new autobahn.Connection({
            url: 'ws://152.23.68.243:8000/ws',
            realm: 'golf_course'
        });

        console.log('go connect');
        app.conn.onopen = app.onConnEstablished;

        app.conn.open();
    },
    onConnEstablished: function(session, details) {
        console.log('connected');
        app.session = session;

        app.accelWatchID = navigator.accelerometer.watchAcceleration(
                app.onAccelSuccess, app.onAccelError, {
                    frequency: 20 // 40ms, minimum iOS freq
                });
        app.compassWatchID = navigator.compass.watchHeading(
                app.onCompassSuccess, app.onAccelError, {
                    frequency: 40
                });
        app.gyroWatchID = navigator.gyroscope.watch(
                app.onGyroSuccess, app.onAccelError, {
                    frequency: 20
                });

        document.addEventListener("volumeupbutton", app.onVolumeUp, false);

        document.body.setAttribute('style', 'background-color:green');
        alert("done");
    },
    onVolumeUp: function(ev) {
        document.body.setAttribute('style', 'background-color:red');
    },
    onAccelSuccess: function(acc) {
        document.getElementById('x').innerHTML = acc.x;
        document.getElementById('y').innerHTML = acc.y;
        document.getElementById('z').innerHTML = acc.z;
        // doesn't work?
        //document.getElementById('timestamp').innerHTML = acc.timestamp.toLocaleString();
        app.session.publish('com.forrestli.selfiegolf.pubsub.accel', [acc.x, acc.y, acc.z]);
    },
    onAccelError: function() {
        alert('Error!');
    },
    onCompassSuccess: function(heading) {
        document.getElementById('magheading').innerHTML = heading.magneticHeading;
        document.getElementById('trueheading').innerHTML = heading.trueHeading;
        app.session.publish('com.forrestli.selfiegolf.pubsub.orient',
            [heading.magneticHeading, heading.trueHeading]);
    },
    onGyroSuccess: function(speed) {
        document.getElementById('angx').innerHTML = speed.x;
        document.getElementById('angy').innerHTML = speed.y;
        document.getElementById('angz').innerHTML = speed.z;
        app.session.publish('com.forrestli.selfiegolf.pubsub.gyro', [speed.x, speed.y, speed.z]);
    }
};
<commit_msg>fix copy-n-paste stupidity<commit_after>// debug purposes only
function dump(obj) {
    var str = "";
    for (var prop in obj) {
        str += prop + "     ";
    }
    return str;
}

var app = {
    initialize: function() {
        this.bindEvents();
    },
    bindEvents: function() {
        document.addEventListener('deviceready', this.onDeviceReady, false);
    },
    onDeviceReady: function() {
        document.getElementById('serverConnect')
            .addEventListener('click', app.onServerConnect, false);
        console.log('ready');
    },
    onServerConnect: function(ev) {
        app.conn = new autobahn.Connection({
            url: 'ws://152.23.68.243:8000/ws',
            realm: 'golf_course'
        });

        console.log('go connect');
        app.conn.onopen = app.onConnEstablished;

        app.conn.open();
    },
    onConnEstablished: function(session, details) {
        console.log('connected');
        app.session = session;

        app.accelWatchID = navigator.accelerometer.watchAcceleration(
                app.onAccelSuccess, app.onAccelError, {
                    frequency: 20 // 40ms, minimum iOS freq
                });
        app.compassWatchID = navigator.compass.watchHeading(
                app.onCompassSuccess, app.onOrientError, {
                    frequency: 40
                });
        app.gyroWatchID = navigator.gyroscope.watch(
                app.onGyroSuccess, app.onGyroError, {
                    frequency: 20
                });

        document.addEventListener("volumeupbutton", app.onVolumeUp, false);

        document.body.setAttribute('style', 'background-color:green');
        alert("done");
    },
    onVolumeUp: function(ev) {
        document.body.setAttribute('style', 'background-color:red');
    },
    onAccelSuccess: function(acc) {
        document.getElementById('x').innerHTML = acc.x;
        document.getElementById('y').innerHTML = acc.y;
        document.getElementById('z').innerHTML = acc.z;
        // doesn't work?
        //document.getElementById('timestamp').innerHTML = acc.timestamp.toLocaleString();
        app.session.publish('com.forrestli.selfiegolf.pubsub.accel', [acc.x, acc.y, acc.z]);
    },
    onAccelError: function() {
        alert('Accel Error!');
    },
    onOrientError: function() {
        alert('orient Error!');
    },
    onGyroError: function() {
        alert('gyro Error!');
    },
    onCompassSuccess: function(heading) {
        document.getElementById('magheading').innerHTML = heading.magneticHeading;
        document.getElementById('trueheading').innerHTML = heading.trueHeading;
        app.session.publish('com.forrestli.selfiegolf.pubsub.orient',
            [heading.magneticHeading, heading.trueHeading]);
    },
    onGyroSuccess: function(speed) {
        document.getElementById('angx').innerHTML = speed.x;
        document.getElementById('angy').innerHTML = speed.y;
        document.getElementById('angz').innerHTML = speed.z;
        app.session.publish('com.forrestli.selfiegolf.pubsub.gyro', [speed.x, speed.y, speed.z]);
    }
};
<|endoftext|>


<commit_before>/**
 *
 * @authors liwb (you@example.org)
 * @date    2016/10/24 17:35
 * @version $ 考虑到所有的API都放到这里
 */

/* name module */
import _Axios from '../utils/_axios';

export function login(data) {
  return _Axios('/usercenter/user/mobile_login', {data});
}
<commit_msg>修复bug<commit_after>/**
 *
 * @authors liwb (you@example.org)
 * @date    2016/10/24 17:35
 * @version $ 考虑到所有的API都放到这里
 */

/* name module */
import _Axios from './_axios';

export function login(data) {
  return _Axios('/usercenter/user/mobile_login', {data});
}
<|endoftext|>