<commit_before>var React = require('react-native');
var moment = require('moment');
var Dimensions = require('Dimensions');

var {
  AppRegistry,
  ScrollView,
  StyleSheet,
  Text,
  TouchableOpacity,
  TouchableWithoutFeedback,
  View
} = React;

const DAYS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
  MAX_COLUMNS = 7,
  MAX_ROWS = 7

class CalendarSwiper extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      calendarDates: [moment().add(5, 'month').format(), moment().add(6, 'month').format(),moment().add(7, 'month').format(), moment().add(8, 'month').format()],
      selectedDate: null,
    }
  }

  renderMonthView(date) {

    var dayStart = moment(date).startOf('month').format(),
      daysInMonth = moment(dayStart).daysInMonth(),
      offset = moment(dayStart).get('day'),
      preFiller = 0,
      postFiller = 7 - (moment(dayStart).endOf('month').get('day') + 1),
      currentDay = 0,
      weekRows = [];

    for (var i = 0; i < MAX_COLUMNS; i++) {
      var days = [];
      for (var j = 0; j < MAX_ROWS; j++) {
        if (preFiller >= offset) {
          if(currentDay < daysInMonth) {
            days.push((
              <TouchableOpacity
                onPress={this._selectDate.bind(this, moment(dayStart).set('date', currentDay + 1))}>
                <Text style={styles.dayListDay}>{currentDay+1}</Text>
              </TouchableOpacity>
            ));
            currentDay++;
          }
        } else {
            days.push(<TouchableWithoutFeedback><Text style={styles.dayListDay}></Text></TouchableWithoutFeedback>);
          }
        preFiller++;
      }

      if(weekRows.length < Math.ceil((daysInMonth + offset) / 7) && days.length < 7) {
        for (var x = 0; x < postFiller; x++) {
          days.push(<TouchableWithoutFeedback><Text style={styles.dayListDay}></Text></TouchableWithoutFeedback>);
        }
        weekRows.push(<View style={[styles.dayList, styles.lastRow]}>{days}</View>);
      } else {
        weekRows.push(<View style={styles.dayList}>{days}</View>);
      }
    }

    return (
      <View ref="InnerScrollView" style={styles.calendarContainer} ref={moment(dayStart).format('YYYY-MM')}>

        <View style={styles.calendarControls}>
          <TouchableOpacity style={styles.controlButton}>
            <Text>Prev</Text>
          </TouchableOpacity>

          <Text style={styles.title}>
            {moment(date).format('MMMM YYYY')}
          </Text>

          <TouchableOpacity style={styles.controls}>
            <Text>Next</Text>
          </TouchableOpacity>
        </View>

        <View style={styles.calendarHeading}>
          {DAYS.map((day) => {
            return (<Text style={styles.dayListDay}>{day}</Text>) })}
        </View>

        {weekRows}
      </View>
    );
  }

  _selectDate(date) {
    console.log(date.format());
  }

  render() {
    return (
      <ScrollView
        horizontal={true}
        bounces={false}
        pagingEnabled={true}
        scrollEventThrottle={300}
        onMomentumScrollEnd={() => { console.log(this.refs)}}>
        {this.state.calendarDates.map((date) => { return this.renderMonthView(date) })}
      </ScrollView>
    )
  }
};
  var styles = StyleSheet.create({
    calendarContainer: {
      marginTop: 20,
      width: Dimensions.get('window').width
    },
    title: {
      textAlign: 'center',
      flex: 2,
    },
    calendarControls: {
      flexDirection: 'row',
      alignItems: 'center',
      margin: 10
    },
    controlButton: {
      flex: 0.1
    },
    title: {
      flex: 0.8,
      textAlign: 'center'
    },
    calendarHeading: {
      flex: 1,
      flexDirection: 'row',
      alignItems: 'center',
      borderTopWidth: 2,
      borderBottomWidth: 2
    },
    dayList: {
      flex: 1,
      flexDirection: 'row',
      alignItems: 'center'
    },
    lastRow: {
      backgroundColor: 'red'
    },
    dayListDay: {
      padding: 5,
      flex: 1,
      textAlign: 'center',
      fontSize: 20,
      justifyContent: 'flex-start'
    },
    currentDay: {
      color: '#FF3333'
    }
  });

AppRegistry.registerComponent('CalendarSwiper', () => CalendarSwiper);<commit_msg>commit solid state. lunch time<commit_after>var React = require('react-native');
var moment = require('moment');
var Dimensions = require('Dimensions');

var {
  AppRegistry,
  ScrollView,
  StyleSheet,
  Text,
  TouchableOpacity,
  TouchableWithoutFeedback,
  View
} = React;

const DAYS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
  MAX_COLUMNS = 7,
  MAX_ROWS = 7

class CalendarSwiper extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      calendarDates: [moment().subtract(3, 'months').format()],
      selectedDate: null,
    }
  }

  renderMonthView(date) {

    var dayStart = moment(date).startOf('month').format(),
      daysInMonth = moment(dayStart).daysInMonth(),
      offset = moment(dayStart).get('day'),
      preFiller = 0,
      currentDay = 0,
      weekRows = [];

    for (var i = 0; i < MAX_COLUMNS; i++) {
      var days = [];
      for (var j = 0; j < MAX_ROWS; j++) {
        if (preFiller < offset) {
          days.push(<TouchableWithoutFeedback><Text style={styles.dayListDay}></Text></TouchableWithoutFeedback>);
        } else {
          if(currentDay < daysInMonth) {
            days.push((
              <TouchableOpacity
                onPress={this._selectDate.bind(this, moment(dayStart).set('date', currentDay + 1))}>
                <Text style={styles.dayListDay}>{currentDay+1}</Text>
              </TouchableOpacity>
            ));
            currentDay++;
          }
        }
        preFiller++;
      } // row

      if(days.length > 0 && days.length < 7) {
        for (var x = days.length; x < 7; x++) {
          days.push(<TouchableWithoutFeedback><Text style={styles.dayListDay}></Text></TouchableWithoutFeedback>);
        }
        weekRows.push(<View style={styles.dayList}>{days}</View>);
      } else {
        weekRows.push(<View style={styles.dayList}>{days}</View>);
      }
    } // column

    return (
      <View ref="InnerScrollView" style={styles.calendarContainer}>

        <View style={styles.calendarControls}>
          <TouchableOpacity style={styles.controlButton}>
            <Text>Prev</Text>
          </TouchableOpacity>

          <Text style={styles.title}>
            {moment(date).format('MMMM YYYY')}
          </Text>

          <TouchableOpacity style={styles.controls}>
            <Text>Next</Text>
          </TouchableOpacity>
        </View>

        <View style={styles.calendarHeading}>
          {DAYS.map((day) => {
            return (<Text style={styles.dayListDay}>{day}</Text>) })}
        </View>

        {weekRows}
      </View>
    );
  }

  _selectDate(date) {
    console.log(date.format());
  }
  _prependMonth(){
    var calendarDates = this.state.calendarDates;
    calendarDates.unshift(moment(calendarDates[0]).subtract(1, 'month').format());
    this.setState({calendarDates: calendarDates});
  }
  _appendMonth(){
    var calendarDates = this.state.calendarDates;
    calendarDates.push(moment(calendarDates[calendarDates.length - 1]).add(1, 'month').format());
    this.setState({calendarDates: calendarDates});
  }

  render() {
    return (
      <View>
        <ScrollView
          ref='calendar'
          horizontal={true}
          bounces={false}
          pagingEnabled={true}
          scrollEventThrottle={300}
          showsHorizontalScrollIndicator={false}
          onMomentumScrollEnd={() => { console.dir(this.refs.calendar)}}>
          {this.state.calendarDates.map((date) => { return this.renderMonthView(date) })}
        </ScrollView>
        <TouchableOpacity onPress={this._prependMonth.bind(this)}>
          <Text>Prepend</Text>
        </TouchableOpacity>
        <TouchableOpacity onPress={this._appendMonth.bind(this)}>
          <Text>Append</Text>
        </TouchableOpacity>
      </View>
    )
  }
};
  var styles = StyleSheet.create({
    calendarContainer: {
      marginTop: 20,
      width: Dimensions.get('window').width,
    },
    title: {
      textAlign: 'center',
      flex: 2,
    },
    calendarControls: {
      flexDirection: 'row',
      alignItems: 'center',
      margin: 10
    },
    controlButton: {
      flex: 0.1
    },
    title: {
      flex: 0.8,
      textAlign: 'center'
    },
    calendarHeading: {
      flex: 1,
      flexDirection: 'row',
      alignItems: 'center',
      borderTopWidth: 2,
      borderBottomWidth: 2
    },
    dayList: {
      flex: 1,
      flexDirection: 'row',
      alignItems: 'center'
    },
    dayListDay: {
      padding: 5,
      flex: 1,
      textAlign: 'center',
      fontSize: 20,
      justifyContent: 'flex-start'
    },
    currentDay: {
      color: '#FF3333'
    }
  });

AppRegistry.registerComponent('CalendarSwiper', () => CalendarSwiper);<|endoftext|>


<commit_before>/**
 * React Native Starter App
 * https://github.com/mcnamee/react-native-starter-app
 */
'use strict';

/* ==============================
  Initialise App
  =============================== */
  // React
  var React = require('react-native');

  // 3rd Party Components
  var NavigationBar = require('react-native-navbar');
  var SideMenu = require('react-native-side-menu');

  // App Globals
  var AppStyles = require('./ReactApp/styles.ios');
  var AppConfig = require('./ReactApp/config.ios');

  // Components
  var Menu = require('./ReactApp/components/menu.ios');

  // Screens / Pages
  var Index = require('./ReactApp/screens/tabbar.ios');

  var {
    AppRegistry,
    Component,
    StyleSheet,
    Navigator,
    Text,
    View,
    TouchableOpacity,
    Image,
  } = React;

/* ==============================
  Main Navigator with Sidemenu
  =============================== */

  /**
   * Custom Navbar Title component
   */
  var NavbarTitle = React.createClass({
    render: function() {
      return (
        <Text style={[AppStyles.baseText, AppStyles.strong, AppStyles.navbarTitle]}>{this.props.title}</Text>
      );
    }
  });

  /**
    * Custom Navbar Button component
    */
  var NavbarButton = React.createClass({
    /**
      * On Icon Press
      */
    onPress: function() { if(this.props.onPress) this.props.onPress(); },

    render: function() {
      return (
        <TouchableOpacity onPress={this.onPress} activeOpacity={0.6}>
          <Image
            source={this.props.image}
            style={AppStyles.navbarButton} />
        </TouchableOpacity>
      );
    }
  });

  /**
   *  Main View w/ Sidebar
   */
  var Application = React.createClass({

    /**
      * Initial State
      */
    getInitialState: function() {
      return {
        menuIsOpen: false,
      };
    },

    /**
      * On Load
      */
    /*componentWillMount: function() {
    },*/

    /**
      * Navigates to page from menu
      */
    navigate: function(title, link) {
      // Toggle Menu
      this.setState({
        menuIsOpen: !this.state.menuIsOpen,
      });

      // Navigate to Screen
      this.refs.rootNavigator.replace({
        title: title,
        component: link,
        navigator: this.refs.rootNavigator,
      });
    },

    /**
      * Generate Custom Navbar
      */
    renderScene: function(route, navigator) {
      var self = this;

      var Component = route.component;

      // Default Navbar Title
      var title = 'Starter App';
      if(route.title) title = route.title;

      // Determine which Icon component - hamburger or back?
      var leftButton = (
        <NavbarButton
          image={require('./ReactApp/images/icons/hamburger.png')}
          onPress={()=>self.setState({menuIsOpen:true})} />
      );

      if (route.index > 0) {
        leftButton = (
          <NavbarButton
            image={require('./ReactApp/images/icons/back_button.png')}
            onPress={self.refs.rootNavigator.pop} />
        );
      }

      // Done
      return (
        <View style={[AppStyles.appContainer, AppStyles.container]}>
          <NavigationBar
            title={<NavbarTitle title={title} />}
            statusBar={{style: 'light-content', hidden: false}}
            style={AppStyles.navbar}
            tintColor={AppConfig.primaryColor}
            leftButton={leftButton} />

          <Component navigator={navigator} route={route} />
        </View>
      );
    },

    /**
      * RENDER
      */
    render: function() {
      return (
        <SideMenu
          menu={<Menu navigate={this.navigate} />}
          isOpen={this.state.menuIsOpen}>

          <Navigator
            ref="rootNavigator"
            style={[AppStyles.container, AppStyles.appContainer]}
            renderScene={this.renderScene}
            initialRoute={{
              component: Index,
              index: 0,
              navigator: this.refs.rootNavigator,
            }} />

        </SideMenu>
      );
    }
  });

/* ==============================
  Styles
  =============================== */
  var styles = StyleSheet.create({
  });

/* ==============================
  Done!
  =============================== */
  AppRegistry.registerComponent('StarterKit', () => Application);<commit_msg>Added ability to passProps between routes<commit_after>/**
 * React Native Starter App
 * https://github.com/mcnamee/react-native-starter-app
 */
'use strict';

/* ==============================
  Initialise App
  =============================== */
  // React
  var React = require('react-native');

  // 3rd Party Components
  var NavigationBar = require('react-native-navbar');
  var SideMenu = require('react-native-side-menu');

  // App Globals
  var AppStyles = require('./ReactApp/styles.ios');
  var AppConfig = require('./ReactApp/config.ios');

  // Components
  var Menu = require('./ReactApp/components/menu.ios');

  // Screens / Pages
  var Index = require('./ReactApp/screens/tabbar.ios');

  var {
    AppRegistry,
    Component,
    StyleSheet,
    Navigator,
    Text,
    View,
    TouchableOpacity,
    Image,
  } = React;

/* ==============================
  Main Navigator with Sidemenu
  =============================== */

  /**
   * Custom Navbar Title component
   */
  var NavbarTitle = React.createClass({
    render: function() {
      return (
        <Text style={[AppStyles.baseText, AppStyles.strong, AppStyles.navbarTitle]}>{this.props.title}</Text>
      );
    }
  });

  /**
    * Custom Navbar Button component
    */
  var NavbarButton = React.createClass({
    /**
      * On Icon Press
      */
    onPress: function() { if(this.props.onPress) this.props.onPress(); },

    render: function() {
      return (
        <TouchableOpacity onPress={this.onPress} activeOpacity={0.6}>
          <Image
            source={this.props.image}
            style={AppStyles.navbarButton} />
        </TouchableOpacity>
      );
    }
  });

  /**
   *  Main View w/ Sidebar
   */
  var Application = React.createClass({

    /**
      * Initial State
      */
    getInitialState: function() {
      return {
        menuIsOpen: false,
      };
    },

    /**
      * On Load
      */
    /*componentWillMount: function() {
    },*/

    /**
      * Navigates to page from menu
      */
    navigate: function(title, link) {
      // Toggle Menu
      this.setState({
        menuIsOpen: !this.state.menuIsOpen,
      });

      // Navigate to Screen
      this.refs.rootNavigator.replace({
        title: title,
        component: link,
        navigator: this.refs.rootNavigator,
      });
    },

    /**
      * Generate Custom Navbar
      */
    renderScene: function(route, navigator) {
      var self = this;

      var Component = route.component;

      // Default Navbar Title
      var title = 'Starter App';
      if(route.title) title = route.title;

      // Determine which Icon component - hamburger or back?
      var leftButton = (
        <NavbarButton
          image={require('./ReactApp/images/icons/hamburger.png')}
          onPress={()=>self.setState({menuIsOpen:true})} />
      );

      if (route.index > 0) {
        leftButton = (
          <NavbarButton
            image={require('./ReactApp/images/icons/back_button.png')}
            onPress={self.refs.rootNavigator.pop} />
        );
      }

      // Done
      return (
        <View style={[AppStyles.appContainer, AppStyles.container]}>
          <NavigationBar
            title={<NavbarTitle title={title} />}
            statusBar={{style: 'light-content', hidden: false}}
            style={AppStyles.navbar}
            tintColor={AppConfig.primaryColor}
            leftButton={leftButton} />

          <Component navigator={navigator} route={route} {...route.passProps} />
        </View>
      );
    },

    /**
      * RENDER
      */
    render: function() {
      return (
        <SideMenu
          menu={<Menu navigate={this.navigate} />}
          isOpen={this.state.menuIsOpen}>

          <Navigator
            ref="rootNavigator"
            style={[AppStyles.container, AppStyles.appContainer]}
            renderScene={this.renderScene}
            initialRoute={{
              component: Index,
              index: 0,
              navigator: this.refs.rootNavigator,
            }} />

        </SideMenu>
      );
    }
  });

/* ==============================
  Styles
  =============================== */
  var styles = StyleSheet.create({
  });

/* ==============================
  Done!
  =============================== */
  AppRegistry.registerComponent('StarterKit', () => Application);
<|endoftext|>


<commit_before>import React from "react-native";

const {
    AppRegistry,
    StyleSheet,
    Text,
    View
} = React;

const styles = StyleSheet.create({
    container: {
        flex: 1,
        justifyContent: "center",
        alignItems: "center",
        backgroundColor: "#F5FCFF"
    },
    welcome: {
        fontSize: 20,
        textAlign: "center",
        margin: 10
    },
    instructions: {
        textAlign: "center",
        color: "#333333",
        marginBottom: 5
    }
});

class HeyNeighbor extends React.Component {
    render() {
        return (
            <View style={styles.container}>
                <Text style={styles.welcome}>
                    Hey there!
                </Text>
                <Text style={styles.instructions}>
                    iOS version is not implemented yet ;(
                </Text>
            </View>
        );
    }
}

AppRegistry.registerComponent("HeyNeighbor", () => HeyNeighbor);
<commit_msg>Show same UI for iOS<commit_after>import React from "react-native";
import Home from "./views/home";

const {
    AppRegistry,
    Navigator
} = React;

class HeyNeighbor extends React.Component {
    render() {
        return (
            <Navigator
                initialRoute={{ name: "Home", index: 0 }}
                renderScene={(route, navigator) => <Home navigator={navigator} />}
            />
        );
    }
}

AppRegistry.registerComponent("HeyNeighbor", () => HeyNeighbor);
<|endoftext|>


<commit_before><commit_msg>Wiped existing views before saving new template<commit_after><|endoftext|>


<commit_before>
//isolate from global scope
(function() {
	/**
	 * Finds the salesforce viewstate string, if any, base64 decodes it, and return's it's length.
	 * The length returned is the blob's lenght, NOT the base64 string - which is how SFDC calculates it
	 * @return {integer|null}
	 */
	var calculateViewstateSize = function(){
	    var restult;
	    try{
	        result = atob(document.getElementById('com.salesforce.visualforce.ViewState').value).length;
	    }catch(ex){
	        result = null;
	    }
	    return result;
	}

	/**
	 * Get cookie value
	 * @param key
	 * @return {String|null}
	 */
	var getCookie = function(key) {
		var decode = function(value) {return decodeURIComponent(value.replace(/\+/g, ' '));};
		var cookies = document.cookie.split('; ');
		for (var i = 0, l = cookies.length; i < l; i++) {
			var parts = cookies[i].split('=');
			if (decode(parts.shift()) === key) {
				//success; found the key!
				return decode(parts.join('='));
			}
		}
		//failure; no such key
		return null;
	}

    /**
     * Takes any of the various forms of SFDC hostnames and spits out a "standard" format
     * @return {String}
     */

	/**
	 * Get URL parameters
	 * @return {Array}
	 */
	var getUrlParam = function(param) {
		var hash, params = [];
		var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
		for(var i = 0; i < hashes.length; i++)    {
			hash = hashes[i].split('=');
			params.push(hash[0]);
			params[hash[0]] = hash[1];
		}
		return params[param] || null;
	};

	/**
	 * Good ol Carlos - get record Id
	 * @param url
	 */
	var getCurrentRecordId = function(url) {
		var href, iframehtml, id, theMatch, startParam;
		try{
			startParam = getUrlParam('timetracker_start');
		}catch(err){
			console.log(err);
		}

		var match;
		if (match = url.match(/\.com\/\w{15}|\.com\/\w{18}/)) {
			//success; captured id from salesforce.com/000xxxxxxxxxxxxXXX)
			return match[0].substr(5);
		} else if (match = url.match(/id\=\w{15}|id\=\w{18}/)) {
			//success; captured id from salesforce.com/id=000xxxxxxxxxxxxXXX
			return match[0].substr(3);
		} else {
			//failure; not on a page with an id
			return null;
		}
	};

	var context = {
		currentRecord : getCurrentRecordId(window.location.href),
		sessionId     : getCookie('sid'),
		orgId         : getCookie('oid'),
		userId        : '005E' + getCookie('sid_Client').substring(0,11),
		sid_Client    : getCookie('sid_Client'),
		pod           : null,
		sfhost        : null
	};

	( function() {
        var instance = null;
        var hostname = window.location.host;
        //modified from http://stackoverflow.com/a/9722468/740787
        var parts = hostname.split("\.");
        if (parts.length == 3)
            instance = parts[0];
        else if (parts.length == 5)
            instance = parts[1];
        else if (parts.length == 4 && parts[1] === "my")
            instance = parts[0]+".my";

        if(instance === null)
            throw new Error("Unable to determine salesforce instance");
        context.pod = instance;

        var isVf = hostname.indexOf(".visual.force.com") > 0;
        if(parts[0].indexOf("--") > 0 && isVf){ //using my domain & this is sandbox or managed vf page
            var subparts = parts[0].split("--");
            context.sfhost = hostname.replace("--"+subparts[subparts.length-1],"").replace(".visual.force.com",".salesforce.com").replace(instance,"my");
        }else{
            context.sfhost = context.pod + ".salesforce.com";
        }

	}());

	chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
		if(request.command == 'getContext')
		    sendResponse(context);
		else if(request.command == 'getViewstateSize')
		    sendResponse(calculateViewstateSize());
		else
		    throw 'Unknown command ' + request.command;
	});

}());<commit_msg>De-isolating from global scrope<commit_after>/**
 * Finds the salesforce viewstate string, if any, base64 decodes it, and return's it's length.
 * The length returned is the blob's lenght, NOT the base64 string - which is how SFDC calculates it
 * @return {integer|null}
 */
var calculateViewstateSize = function(){
    var restult;
    try{
        result = atob(document.getElementById('com.salesforce.visualforce.ViewState').value).length;
    }catch(ex){
        result = null;
    }
    return result;
}

/**
 * Get cookie value
 * @param key
 * @return {String|null}
 */
var getCookie = function(key) {
	var decode = function(value) {return decodeURIComponent(value.replace(/\+/g, ' '));};
	var cookies = document.cookie.split('; ');
	for (var i = 0, l = cookies.length; i < l; i++) {
		var parts = cookies[i].split('=');
		if (decode(parts.shift()) === key) {
			//success; found the key!
			return decode(parts.join('='));
		}
	}
	//failure; no such key
	return null;
}

/**
 * Takes any of the various forms of SFDC hostnames and spits out a "standard" format
 * @return {String}
 */

/**
 * Get URL parameters
 * @return {Array}
 */
var getUrlParam = function(param) {
	var hash, params = [];
	var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
	for(var i = 0; i < hashes.length; i++)    {
		hash = hashes[i].split('=');
		params.push(hash[0]);
		params[hash[0]] = hash[1];
	}
	return params[param] || null;
};

/**
 * Good ol Carlos - get record Id
 * @param url
 */
var getCurrentRecordId = function(url) {
	var href, iframehtml, id, theMatch, startParam;
	try{
		startParam = getUrlParam('timetracker_start');
	}catch(err){
		console.log(err);
	}

	var match;
	if (match = url.match(/\.com\/\w{15}|\.com\/\w{18}/)) {
		//success; captured id from salesforce.com/000xxxxxxxxxxxxXXX)
		return match[0].substr(5);
	} else if (match = url.match(/id\=\w{15}|id\=\w{18}/)) {
		//success; captured id from salesforce.com/id=000xxxxxxxxxxxxXXX
		return match[0].substr(3);
	} else {
		//failure; not on a page with an id
		return null;
	}
};

var context = {
	currentRecord : getCurrentRecordId(window.location.href),
	sessionId     : getCookie('sid'),
	orgId         : getCookie('oid'),
	userId        : '005E' + getCookie('sid_Client').substring(0,11),
	sid_Client    : getCookie('sid_Client'),
	pod           : null,
	sfhost        : null
};

( function() {
    var instance = null;
    var hostname = window.location.host;
    //modified from http://stackoverflow.com/a/9722468/740787
    var parts = hostname.split("\.");
    if (parts.length == 3)
        instance = parts[0];
    else if (parts.length == 5)
        instance = parts[1];
    else if (parts.length == 4 && parts[1] === "my")
        instance = parts[0]+".my";

    if(instance === null)
        throw new Error("Unable to determine salesforce instance");
    context.pod = instance;

    var isVf = hostname.indexOf(".visual.force.com") > 0;
    if(parts[0].indexOf("--") > 0 && isVf){ //using my domain & this is sandbox or managed vf page
        var subparts = parts[0].split("--");
        context.sfhost = hostname.replace("--"+subparts[subparts.length-1],"").replace(".visual.force.com",".salesforce.com").replace(instance,"my");
    }else{
        context.sfhost = context.pod + ".salesforce.com";
    }

}());

chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
	if(request.command == 'getContext')
	    sendResponse(context);
	else if(request.command == 'getViewstateSize')
	    sendResponse(calculateViewstateSize());
	else
	    throw 'Unknown command ' + request.command;
});<|endoftext|>


<commit_before>#!/usr/bin/env node
'use strict'

var fs = require('fs-extra');
var path = require('path');
var decompress = require('inly');
var spawn = require('cross-spawn');
var uncompress = require('unpack-all');
var macuncompress = require('xar');
var node_wget = require('node-wget');

const macosversion = (process.platform == "darwin") ? require('macos-release').version : '';
const _7zipData = getDataForPlatform();
const whattocopy = _7zipData.binaryfiles;

const _7zAppfile = '7z1604-extra.7z';
const _7zApptocopy = [ '7za.dll','7za.exe','7zxa.dll' ];
const _7zAppurl = 'http://7-zip.org/a/';

const unarAppfile = (process.platform == "darwin") ? 'unar1.8.1.zip' : 'unar1.8.1_win.zip' ;
const unarApptocopy = [ 'lsar.exe','unar.exe','Foundation.1.0.dll' ];
const unarAppurl = 'https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/theunarchiver/';

const cwd = process.cwd();
const destination = path.join(cwd, process.platform);
const source = path.join(cwd, _7zipData.filename);

const binarydestination = path.join(__dirname,'binaries', (macosversion=='') ? process.platform : process.platform, macosversion );
const extrasource = path.join(cwd, _7zipData.extraname);
const _7zcommand = path.join(binarydestination, process.platform === "win32" ? '7za.exe' : '7za' );

if ((_7zipData.url != null) && (process.platform != "darwin"))   {
    fs.mkdir(destination, (err) => { if (err) {}});
    wget({ url: _7zipData.url + _7zipData.filename, dest: source })
    .then(function () {
        platformUnpacker(source, destination)
        .then(function (mode){
            whattocopy.forEach(function(s) {
                fs.moveSync(path.join(destination, _7zipData.extractfolder, _7zipData.applocation,s),
                    path.join(binarydestination,s),
                    { overwrite: true });
                });
            console.log('Binaries copied successfully!');
            if (mode=='darwin') {
                var whattodelete = unarApptocopy.concat(_7zApptocopy).concat( [unarAppfile, _7zAppfile] );
                whattodelete.forEach(function (s) { fs.unlink(path.join(cwd, s), (err) => { if (err) console.error(err); }); });
            } else if (mode=='win32') {
                var whattodelete = unarApptocopy.concat( unarAppfile );
                whattodelete.forEach(function (s) { fs.unlink(path.join(cwd, s), (err) => { if (err) console.error(err); }); });
            }
            fs.unlink(source, (err) => { if (err) console.error(err); });
            fs.remove(destination, (err) => { if (err) console.error(err); });
            var result = extraunpack(_7zcommand, extrasource, binarydestination, _7zipData.sfxmodules);
            console.log(result);
            console.log('Sfx modules copied successfully!');
            fs.unlink(extrasource, (err) => { if (err) console.error(err); });
        }).catch(function (err) { console.log(err); });
    }).catch(function (err) { console.log(err); });
} else if (process.platform == "darwin") {
    node_wget({ url: _7zipData.url + _7zipData.extraname, dest: extrasource }, function (err) {
        if (err) { console.error('Error downloading file: ' + err);   return reject(err); }  });
    extraunpack(_7zcommand, extrasource, binarydestination, _7zipData.sfxmodules);
    fs.unlink(extrasource, (err) => { if (err) console.error(err); });
    console.log('Sfx modules copied successfully!');
}

function getDataForPlatform(){
    switch (process.platform) {
        // Windows version
        case "win32": return { url: 'http://d.7-zip.org/a/',
        filename: '7z1801-extra.7z',
        extraname: 'lzma1801.7z',
        extractfolder: '',
        applocation: '',
        binaryfiles: ['Far','x64','7za.dll','7za.exe','7zxa.dll'],
        sfxmodules: ['7zr.exe','7zS2.sfx','7zS2con.sfx','7zSD.sfx'] };
        // Linux version
        case "linux": return { url: 'http://cfhcable.dl.sourceforge.net/project/p7zip/p7zip/16.02/',
        filename: 'p7zip_16.02_x86_linux_bin.tar.bz2',
        extraname: 'lzma1604.7z',
        extractfolder: 'p7zip_16.02',
        applocation: 'bin',
        binaryfiles: ['Codecs','7z','7z.so','7za','7zCon.sfx','7zr'],
        sfxmodules: ['7zS2.sfx','7zS2con.sfx','7zSD.sfx'] };
        // Mac version
        case "darwin": return { url: 'https://raw.githubusercontent.com/rudix-mac/packages/master/' + macosversion + '/',
        filename: 'p7zip-9.20.1-1.pkg',
        extraname: '7z920_extra.7z',
        extractfolder: '',
        applocation: 'usr/local/lib/p7zip',
        binaryfiles: ['7z','7z.so','7za','7zCon.sfx','7zr','Codecs'],
        sfxmodules: ['7zS.sfx','7zS2.sfx','7zS2con.sfx','7zSD.sfx'] };
    }
}

function wget(path) {
  console.log('Downloading ' + path.url);
  return new Promise(function (resolve, reject) {
    require('node-wget')(path, function (err) {
      if (err) {
        console.error('Error downloading file: ' + err);
        return reject(err);
      }
      resolve();
    });
  });
}

function platformUnpacker(source, destination){
  return new Promise(function (resolve, reject) {
    node_wget({ url: _7zipData.url + _7zipData.extraname, dest: extrasource }, function (err) {
        if (err) { console.error('Error downloading file: ' + err);   return reject(err); }  });
    if ((process.platform == "win32") || (process.platform == "darwin_not_ready")) {
        wget({ url: unarAppurl + unarAppfile, dest: path.join(cwd,unarAppfile) })
        .then(function () {
            console.log('Extracting: ' + unarAppfile + ', to decompress: ' + ((process.platform == "win32") ? _7zipData.filename : _7zAppfile ));
            const extract = decompress(path.join(cwd,unarAppfile), cwd);
            extract.on('file', (name) => { console.log(name); });
            extract.on('error', (error) => { return reject(error); });
            extract.on('end', () => {
                if (process.platform == "darwin") {
                    wget({ url: _7zAppurl + _7zAppfile, dest: path.join(cwd,_7zAppfile) })
                    .then(function () {
                        console.log('Extracting: ' + _7zAppfile + ', to decompress: ' + _7zipData.filename );
                        unpack(path.join(cwd, _7zAppfile), '.', _7zApptocopy)
                        .then(function() {
                            console.log('Decompressing ' + _7zipData.filename);
                            macunpack(source, destination)
                            //winunpack(source, destination)
                            .then(function(data) {
                                //console.log('Decompressing: p7zip-9.20.1-1');
                                //unpack(path.join(destination,'p7zip-9.20.1-1'), process.platform, _7zipData.applocation + path.sep +'*')
                                console.log('Decompressing: p7zipinstall.pkg/Payload');
                                unpack(path.join(destination,'p7zipinstall.pkg','Payload'), process.platform, _7zipData.applocation + path.sep + '*')
                                .then( function(result) {
                                    console.log(result);
                                    resolve('darwin'); })
                                .catch(function (err) { return reject(err); });
                            })
                            .catch(function (err) { return reject(err); });
                        })
                        .catch(function (err) { return reject(err); });
                    })
                    .catch(function (err) { return reject(err); });
                } else {
                    unpack(source, process.platform)
                    .then(function (result) {
                        console.log(result);
                        resolve('win32'); })
                    .catch(function (err) { return reject(err); });
                }
            });
        })
        .catch(function (err) { return reject(err); });
    } else if (process.platform == "linux") {
        console.log('Decompressing ' + _7zipData.filename);
        const extract = decompress(source, destination);
        extract.on('file', (name) => { console.log(name); });
        extract.on('error', (error) => { return reject(error); });
        extract.on('end', () => { resolve('linux'); });
    }
  });
}

function unpack(source, destination, tocopy) {
  return new Promise(function (resolve, reject) {
    uncompress.unpack(source, {  files: (tocopy==null ) ? '' : tocopy,
        targetDir: destination, forceOverwrite: true, noDirectory: true },
          function(err, files, text) {
            if (err) return reject(err);
            resolve(text);
        });
    });
}

function macunpack(source,destination){
    var content = fs.readFileSync(source)
  return new Promise(function (resolve, reject) {
    macuncompress.unpack(content, function (err, file, content) {
        if (err) return reject(err);
        if (file.type[0] === 'directory'){
            console.log('mkdir', file.path);
            fs.mkdirSync(path.join(destination, file.path));
        } else {
            console.log('extract', file.path);
            if (file.path == 'p7zipinstall.pkg/Payload') {
                fs.writeFileSync(path.join(destination, file.path), content);
                // need to find way to extract Payload file, xar module creating unknown format
                // fs.createReadStream(path.join(destination, file.path)).pipe(gunzip()).pipe(cpio.extract(destination));
                resolve();
            } else {
                fs.writeFileSync(path.join(destination, file.path), content);
            }
        }
        });
    });
}

function winunpack(source, destination){
     var cmd = '7za.exe';
     var args = [ 'x',source,'-o' + destination,'-y'];
     console.log('Running: ' + cmd);
  return new Promise(function (resolve, reject) {
    var winunpacker = spawn.sync(cmd, args, { stdio: 'pipe' });
        if (winunpacker.error) {
          console.error('7za exited with code ' + winunpacker.error);
          console.log('resolve the problem and re-install using:');
          console.log('npm install');
          return reject(winunpacker.error);
        }
        if (winunpacker.stdout.toString()) {
            resolve(winunpacker.stdout.toString());
        }
    });
}

function extraunpack(cmd, source, destination, tocopy) {
    var args = [ 'e',source,'-o' + destination ];
    var extraargs = args.concat(tocopy).concat( ['-r','-aos'] );
    console.log('Running: ' + cmd );
    var winunpacker = spawn.sync(cmd, extraargs, { stdio: 'pipe' });
    if (winunpacker.error) {
        console.error('7za exited with code ' + winunpacker.error);
        console.log('resolve the problem and re-install using:');
        console.log('npm install');
        return rwinunpacker.error;
    } else if (winunpacker.stdout.toString()) {
        return winunpacker.stdout.toString();
    }
}
<commit_msg>fixed linux installer build errors and exec<commit_after>#!/usr/bin/env node
'use strict'

var fs = require('fs-extra');
var path = require('path');
var decompress = require('inly');
var spawn = require('cross-spawn');
var uncompress = require('unpack-all');
var macuncompress = require('xar');
var node_wget = require('node-wget');

const macosversion = (process.platform == "darwin") ? require('macos-release').version : '';
const _7zipData = getDataForPlatform();
const whattocopy = _7zipData.binaryfiles;

const _7zAppfile = '7z1604-extra.7z';
const _7zApptocopy = [ '7za.dll','7za.exe','7zxa.dll' ];
const _7zAppurl = 'http://7-zip.org/a/';

const unarAppfile = (process.platform == "darwin") ? 'unar1.8.1.zip' : 'unar1.8.1_win.zip' ;
const unarApptocopy = [ 'lsar.exe','unar.exe','Foundation.1.0.dll' ];
const unarAppurl = 'https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/theunarchiver/';

const cwd = process.cwd();
const destination = path.join(cwd, process.platform);
const source = path.join(cwd, _7zipData.filename);

const binarydestination = path.join(__dirname,'binaries', (macosversion=='') ? process.platform : process.platform, macosversion );
const extrasource = path.join(cwd, _7zipData.extraname);
const _7zcommand = path.join(binarydestination, process.platform === "win32" ? '7za.exe' : '7za' );

if ((_7zipData.url != null) && (process.platform != "darwin"))   {
    fs.mkdir(destination, (err) => { if (err) {}});
    wget({ url: _7zipData.url + _7zipData.filename, dest: source })
    .then(function () {
        platformUnpacker(source, destination)
        .then(function (mode){
            whattocopy.forEach(function(s) {
                fs.moveSync(path.join(destination, _7zipData.extractfolder, _7zipData.applocation,s),
                    path.join(binarydestination,s),
                    { overwrite: true });
                });
            if (process.platform !== "win32") whattocopy.forEach(function(s) { fs.chmodSync(path.join(binarydestination,s), 757) });
            console.log('Binaries copied successfully!');
            if (mode=='darwin') {
                var whattodelete = unarApptocopy.concat(_7zApptocopy).concat( [unarAppfile, _7zAppfile] );
                whattodelete.forEach(function (s) { fs.unlink(path.join(cwd, s), (err) => { if (err) console.error(err); }); });
            } else if (mode=='win32') {
                var whattodelete = unarApptocopy.concat( unarAppfile );
                whattodelete.forEach(function (s) { fs.unlink(path.join(cwd, s), (err) => { if (err) console.error(err); }); });
            }
            fs.unlink(source, (err) => { if (err) console.error(err); });
            fs.remove(destination, (err) => { if (err) console.error(err); });
            var result = extraunpack(_7zcommand, extrasource, binarydestination, _7zipData.sfxmodules);
            console.log(result);
            console.log('Sfx modules copied successfully!');
            fs.unlink(extrasource, (err) => { if (err) console.error(err); });
        }).catch(function (err) { console.log(err); });
    }).catch(function (err) { console.log(err); });
} else if (process.platform == "darwin") {
    node_wget({ url: _7zipData.url + _7zipData.extraname, dest: extrasource }, function (err) {
        if (err) { console.error('Error downloading file: ' + err);   return reject(err); }  });
    extraunpack(_7zcommand, extrasource, binarydestination, _7zipData.sfxmodules);
    fs.unlink(extrasource, (err) => { if (err) console.error(err); });
    console.log('Sfx modules copied successfully!');
}

function getDataForPlatform(){
    switch (process.platform) {
        // Windows version
        case "win32": return { url: 'http://d.7-zip.org/a/',
        filename: '7z1801-extra.7z',
        extraname: 'lzma1801.7z',
        extractfolder: '',
        applocation: '',
        binaryfiles: ['Far','x64','7za.dll','7za.exe','7zxa.dll'],
        sfxmodules: ['7zr.exe','7zS2.sfx','7zS2con.sfx','7zSD.sfx'] };
        // Linux version
        case "linux": return { url: 'http://cfhcable.dl.sourceforge.net/project/p7zip/p7zip/16.02/',
        filename: 'p7zip_16.02_x86_linux_bin.tar.bz2',
        extraname: 'lzma1604.7z',
        extractfolder: 'p7zip_16.02',
        applocation: 'bin',
        binaryfiles: ['Codecs','7z','7z.so','7za','7zCon.sfx','7zr'],
        sfxmodules: ['7zS2.sfx','7zS2con.sfx','7zSD.sfx'] };
        // Mac version
        case "darwin": return { url: 'https://raw.githubusercontent.com/rudix-mac/packages/master/' + macosversion + '/',
        filename: 'p7zip-9.20.1-1.pkg',
        extraname: '7z920_extra.7z',
        extractfolder: '',
        applocation: 'usr/local/lib/p7zip',
        binaryfiles: ['7z','7z.so','7za','7zCon.sfx','7zr','Codecs'],
        sfxmodules: ['7zS.sfx','7zS2.sfx','7zS2con.sfx','7zSD.sfx'] };
    }
}

function wget(path) {
  console.log('Downloading ' + path.url);
  return new Promise(function (resolve, reject) {
    require('node-wget')(path, function (err) {
      if (err) {
        console.error('Error downloading file: ' + err);
        return reject(err);
      }
      resolve();
    });
  });
}

function platformUnpacker(source, destination){
  return new Promise(function (resolve, reject) {
    node_wget({ url: _7zipData.url + _7zipData.extraname, dest: extrasource }, function (err) {
        if (err) { console.error('Error downloading file: ' + err);   return reject(err); }  });
    if ((process.platform == "win32") || (process.platform == "darwin_not_ready")) {
        wget({ url: unarAppurl + unarAppfile, dest: path.join(cwd,unarAppfile) })
        .then(function () {
            console.log('Extracting: ' + unarAppfile + ', to decompress: ' + ((process.platform == "win32") ? _7zipData.filename : _7zAppfile ));
            const extract = decompress(path.join(cwd,unarAppfile), cwd);
            extract.on('file', (name) => { console.log(name); });
            extract.on('error', (error) => { return reject(error); });
            extract.on('end', () => {
                if (process.platform == "darwin") {
                    wget({ url: _7zAppurl + _7zAppfile, dest: path.join(cwd,_7zAppfile) })
                    .then(function () {
                        console.log('Extracting: ' + _7zAppfile + ', to decompress: ' + _7zipData.filename );
                        unpack(path.join(cwd, _7zAppfile), '.', _7zApptocopy)
                        .then(function() {
                            console.log('Decompressing ' + _7zipData.filename);
                            macunpack(source, destination)
                            //winunpack(source, destination)
                            .then(function(data) {
                                //console.log('Decompressing: p7zip-9.20.1-1');
                                //unpack(path.join(destination,'p7zip-9.20.1-1'), process.platform, _7zipData.applocation + path.sep +'*')
                                console.log('Decompressing: p7zipinstall.pkg/Payload');
                                unpack(path.join(destination,'p7zipinstall.pkg','Payload'), process.platform, _7zipData.applocation + path.sep + '*')
                                .then( function(result) {
                                    console.log(result);
                                    resolve('darwin'); })
                                .catch(function (err) { return reject(err); });
                            })
                            .catch(function (err) { return reject(err); });
                        })
                        .catch(function (err) { return reject(err); });
                    })
                    .catch(function (err) { return reject(err); });
                } else {
                    unpack(source, process.platform)
                    .then(function (result) {
                        console.log(result);
                        resolve('win32'); })
                    .catch(function (err) { return reject(err); });
                }
            });
        })
        .catch(function (err) { return reject(err); });
    } else if (process.platform == "linux") {
        console.log('Decompressing ' + _7zipData.filename);
        const extract = decompress(source, destination);
        extract.on('file', (name) => { console.log(name); });
        extract.on('error', (error) => { return reject(error); });
        extract.on('end', () => { resolve('linux'); });
    }
  });
}

function unpack(source, destination, tocopy) {
  return new Promise(function (resolve, reject) {
    uncompress.unpack(source, {  files: (tocopy==null ) ? '' : tocopy,
        targetDir: destination, forceOverwrite: true, noDirectory: true },
          function(err, files, text) {
            if (err) return reject(err);
            resolve(text);
        });
    });
}

function macunpack(source,destination){
    var content = fs.readFileSync(source)
  return new Promise(function (resolve, reject) {
    macuncompress.unpack(content, function (err, file, content) {
        if (err) return reject(err);
        if (file.type[0] === 'directory'){
            console.log('mkdir', file.path);
            fs.mkdirSync(path.join(destination, file.path));
        } else {
            console.log('extract', file.path);
            if (file.path == 'p7zipinstall.pkg/Payload') {
                fs.writeFileSync(path.join(destination, file.path), content);
                // need to find way to extract Payload file, xar module creating unknown format
                // fs.createReadStream(path.join(destination, file.path)).pipe(gunzip()).pipe(cpio.extract(destination));
                resolve();
            } else {
                fs.writeFileSync(path.join(destination, file.path), content);
            }
        }
        });
    });
}

function winunpack(source, destination){
     var cmd = '7za.exe';
     var args = [ 'x',source,'-o' + destination,'-y'];
     console.log('Running: ' + cmd);
  return new Promise(function (resolve, reject) {
    var winunpacker = spawn.sync(cmd, args, { stdio: 'pipe' });
        if (winunpacker.error) {
          console.error('7za exited with code ' + winunpacker.error);
          console.log('resolve the problem and re-install using:');
          console.log('npm install');
          return reject(winunpacker.error);
        }
        if (winunpacker.stdout.toString()) {
            resolve(winunpacker.stdout.toString());
        }
    });
}

function extraunpack(cmd, source, destination, tocopy) {
    var args = [ 'e',source,'-o' + destination ];
    var extraargs = args.concat(tocopy).concat( ['-r','-aos'] );
    console.log('Running: ' + cmd );
    var extraunpacker = spawn.sync(cmd, extraargs, { stdio: 'pipe' });
    if (extraunpacker.error) {
        console.error('7za exited with code ' + extraunpacker.error);
        console.log('resolve the problem and re-install using:');
        console.log('npm install');
        return extraunpacker.error;
    } else if (extraunpacker.stdout.toString()) {
        return extraunpacker.stdout.toString();
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright 2011-2014 Jiří Janoušek <janousek.jiri@gmail.com>
 * Copyright 2014 Martin Pöhlmann <martin.deimos@gmx.de>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

(function(Nuvola)
{

var C_ = Nuvola.Translate.pgettext;
var ngettext = Nuvola.Translate.ngettext;

var State = Nuvola.PlaybackState;
var PlayerAction = Nuvola.PlayerAction;
var player = Nuvola.$object(Nuvola.MediaPlayer);

var ACTION_THUMBS_UP = "thumbs-up";
var ACTION_THUMBS_DOWN = "thumbs-down";
var ACTION_RATING = "rating";
var THUMBS_ACTIONS = [ACTION_THUMBS_UP, ACTION_THUMBS_DOWN];
var STARS_ACTIONS = [];
for (var i=0; i <= 5; i++)
    STARS_ACTIONS.push(ACTION_RATING + "::" + i);

var WebApp = Nuvola.$WebApp();

WebApp._onInitAppRunner = function(emitter)
{
    Nuvola.WebApp._onInitAppRunner.call(this, emitter);

    Nuvola.actions.addAction("playback", "win", ACTION_THUMBS_UP, C_("Action", "Thumbs up"), null, null, null, true);
    Nuvola.actions.addAction("playback", "win", ACTION_THUMBS_DOWN,C_("Action", "Thumbs down"), null, null, null, true);
    var ratingOptions = [];
    for (var stars = 0; stars < 6; stars++)
        ratingOptions.push([
            stars, // stateId, label, mnemo_label, icon, keybinding
            /// Star rating, {1} is a placeholder for a number
            Nuvola.format(ngettext("Rating: {1} star", "Rating: {1} stars", stars), stars), // label
            null, // mnemo_label
            null, // icon
            null  // keybinding
            ]);
    Nuvola.actions.addRadioAction("playback", "win", ACTION_RATING, 0, ratingOptions);
}

WebApp._onInitWebWorker = function(emitter)
{
    Nuvola.WebApp._onInitWebWorker.call(this, emitter);

    Nuvola.actions.connect("ActionActivated", this);
    this.thumbsUp = undefined;
    this.thumbsDown = undefined;
    this.starRating = undefined;
    this.starRatingEnabled = undefined;
    this.thumbRatingEnabled = undefined;
    this.state = State.UNKNOWN;
    document.addEventListener("DOMContentLoaded", this._onPageReady.bind(this));
}

/**
 * Signal handler for @link{Core::UriChanged}
 */
WebApp._onUriChanged = function(emitter, uri)
{
    /*
     * Users that use the queue page a lot might end up with it as a start-up page. However, this page is always empty
     * and not useful at all, so load Listen now page instead. https://bugs.launchpad.net/nuvola-player/+bug/1306678
     */
    if (uri === "https://play.google.com/music/listen#/ap/queue")
        uri = this.meta.home_url;

    Nuvola.WebApp._onUriChanged.call(this, emitter, uri);
}

WebApp._onPageReady = function()
{
    this.addNavigationButtons();
    this.update();
}

WebApp.update = function()
{
    var track = {};
    try
    {
        track.artLocation = document.getElementById('playingAlbumArt').src;
    }
    catch(e)
    {
        track.artLocation =  null;
    }

    try
    {
        var elm = document.getElementById('playerSongTitle').firstChild;
        track.title = elm.innerText || elm.textContent;
    }
    catch(e)
    {
        track.title = null;
    }

    try
    {
        var elm = document.getElementById('player-artist').firstChild;
        track.artist = elm.innerText || elm.textContent;
    }
    catch (e)
    {
        track.artist = null;
    }

    try
    {
        var elm = document.querySelector("#playerSongInfo .player-album");
        track.album = elm.innerText || elm.textContent;
    }
    catch (e)
    {
        track.album = null;
    }

    player.setTrack(track);

    this.state = State.UNKNOWN;
    var prevSong, nextSong, canPlay, canPause;
    try
    {
        var buttons = document.querySelector("#player .player-middle");
        var pp = buttons.childNodes[2];
        if (pp.disabled === true)
            this.state = State.UNKNOWN;
        else if (pp.className == "flat-button playing")
            this.state = State.PLAYING;
        else
            this.state = State.PAUSED;

        if (this.state !== State.UNKNOWN)
        {
            prevSong = buttons.childNodes[1].disabled === false;
            nextSong = buttons.childNodes[3].disabled === false;
        }
        else
        {
            prevSong = nextSong = false;
        }
    }
    catch (e)
    {
        prevSong = nextSong = false;
    }

    player.setPlaybackState(this.state);
    player.setCanPause(this.state === State.PLAYING);
    player.setCanPlay(this.state === State.PAUSED);
    player.setCanGoPrev(prevSong);
    player.setCanGoNext(nextSong);

    // Extract enabled flag and state from a web page
    var actionsEnabled = {};
    var actionsStates = {};
    try
    {
        actionsEnabled[ACTION_THUMBS_UP] = false;
        actionsEnabled[ACTION_THUMBS_DOWN] = false;
        var thumbs = this.getThumbs();
        if (thumbs[0].style.visibility !== "hidden")
        {
            this.toggleThumbRating(true);
            actionsStates[ACTION_THUMBS_UP] = thumbs[1].className === "selected";
            actionsStates[ACTION_THUMBS_DOWN] = thumbs[2].className === "selected";
            actionsEnabled[ACTION_THUMBS_UP] = true;
            actionsEnabled[ACTION_THUMBS_DOWN] = true;
        }
    }
    catch (e)
    {
    }
    try
    {
        actionsEnabled[ACTION_RATING] = false;
        var stars = this.getStars();
        if (stars.style.visibility !== "hidden")
        {
            this.toggleStarRating(true);
            actionsStates[ACTION_RATING] = stars.childNodes[0].getAttribute("data-rating") * 1;
            actionsEnabled[ACTION_RATING] = true;
        }
    }
    catch (e)
    {
    }

    // Compare with previous values and update if necessary
    Nuvola.actions.updateEnabledFlags(actionsEnabled);
    Nuvola.actions.updateStates(actionsStates);

    setTimeout(this.update.bind(this), 500);
}

WebApp.getPlayerButtons = function()
{
    var elm = document.querySelector("#player .player-middle");
    return elm ? elm.childNodes : null;
}

WebApp._onActionActivated = function(emitter, name, param)
{
    var buttons = this.getPlayerButtons();
    if (buttons)
    {
        var prev_song = buttons[1];
        var next_song = buttons[3];
        var play_pause = buttons[2];
    }
    else
    {
        var prev_song = null;
        var next_song = null;
        var play_pause = null;
    }

    switch (name)
    {
    /* Base media player actions */
    case PlayerAction.TOGGLE_PLAY:
        Nuvola.clickOnElement(play_pause);
        break;
    case PlayerAction.PLAY:
        if (this.state != State.PLAYING)
            Nuvola.clickOnElement(play_pause);
        break;
    case PlayerAction.PAUSE:
    case PlayerAction.STOP:
        if (this.state == State.PLAYING)
            Nuvola.clickOnElement(play_pause);
        break;
    case PlayerAction.PREV_SONG:
        if (prev_song)
            Nuvola.clickOnElement(prev_song);
        break;
    case PlayerAction.NEXT_SONG:
        if (next_song)
            Nuvola.clickOnElement(next_song);
        break;

    /* Custom actions */
    case ACTION_THUMBS_UP:
        Nuvola.clickOnElement(this.getThumbs()[1]);
        break;
    case ACTION_THUMBS_DOWN:
        Nuvola.clickOnElement(this.getThumbs()[2]);
        break;
    case ACTION_RATING:
        var stars = this.getStars().childNodes;
        var i = stars.length;
        while (i--)
        {
            var star = stars[i];
            if (star.getAttribute("data-rating") === ("" + param))
            {
                Nuvola.clickOnElement(star);
                break;
            }
        }
        break;
    }
}

WebApp.addNavigationButtons = function()
{
    /* Loading in progress? */
    var loading = document.getElementById("loading-progress");
    if (loading && loading.style.display != "none")
    {
        setTimeout(this.addNavigationButtons.bind(this), 250);
        return;
    }

    var queryBar = document.getElementById("gbq2");
    if (!queryBar)
    {
        console.log("Could not find the query bar.");
        return;
    }

    var queryBarFirstChild = queryBar.firstChild;

    var navigateBack = Nuvola.makeElement("button", null, "<");
    navigateBack.className = "button small vertical-align";
    navigateBack.style.float = "left";
    navigateBack.style.marginRight = "0px";
    navigateBack.style.borderTopRightRadius = "2px";
    navigateBack.style.borderBottomRightRadius = "2px";
    queryBar.insertBefore(navigateBack, queryBarFirstChild);

    var navigateForward = Nuvola.makeElement("button", null, ">");
    navigateForward.className = "button small vertical-align";
    navigateForward.style.float = "left";
    navigateForward.style.marginRight = "15px";
    navigateForward.style.borderLeft = "none";
    navigateForward.style.borderTopLeftRadius = "2px";
    navigateForward.style.borderLeftRightRadius = "2px";
    queryBar.insertBefore(navigateForward, queryBarFirstChild);

    Nuvola.actions.attachButton(Nuvola.BrowserAction.GO_BACK, navigateBack);
    Nuvola.actions.attachButton(Nuvola.BrowserAction.GO_FORWARD, navigateForward);
}

WebApp.getThumbs = function()
{
    var elm = document.querySelector("#player-right-wrapper .thumbs.rating-container");
    return [elm, elm.childNodes[0], elm.childNodes[1]];
}

WebApp.getStars = function()
{
    return document.querySelector("#player-right-wrapper .stars.rating-container");
}

WebApp.toggleStarRating = function(enabled)
{
    if (enabled && this.starRatingEnabled !== true)
    {
        player.addExtraActions(STARS_ACTIONS);
        this.starRatingEnabled = true;
    }
}

WebApp.toggleThumbRating = function(enabled)
{
    if (enabled && this.thumbRatingEnabled !== true)
    {
        player.addExtraActions(THUMBS_ACTIONS);
        this.thumbRatingEnabled = true;
    }
}

WebApp.start();

})(this);  // function(Nuvola)
<commit_msg>Play action triggers I'm feeling lucky mix<commit_after>/*
 * Copyright 2011-2014 Jiří Janoušek <janousek.jiri@gmail.com>
 * Copyright 2014 Martin Pöhlmann <martin.deimos@gmx.de>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

(function(Nuvola)
{

var C_ = Nuvola.Translate.pgettext;
var ngettext = Nuvola.Translate.ngettext;

var State = Nuvola.PlaybackState;
var PlayerAction = Nuvola.PlayerAction;
var player = Nuvola.$object(Nuvola.MediaPlayer);

var ACTION_THUMBS_UP = "thumbs-up";
var ACTION_THUMBS_DOWN = "thumbs-down";
var ACTION_RATING = "rating";
var THUMBS_ACTIONS = [ACTION_THUMBS_UP, ACTION_THUMBS_DOWN];
var STARS_ACTIONS = [];
for (var i=0; i <= 5; i++)
    STARS_ACTIONS.push(ACTION_RATING + "::" + i);

var WebApp = Nuvola.$WebApp();

WebApp._onInitAppRunner = function(emitter)
{
    Nuvola.WebApp._onInitAppRunner.call(this, emitter);

    Nuvola.actions.addAction("playback", "win", ACTION_THUMBS_UP, C_("Action", "Thumbs up"), null, null, null, true);
    Nuvola.actions.addAction("playback", "win", ACTION_THUMBS_DOWN,C_("Action", "Thumbs down"), null, null, null, true);
    var ratingOptions = [];
    for (var stars = 0; stars < 6; stars++)
        ratingOptions.push([
            stars, // stateId, label, mnemo_label, icon, keybinding
            /// Star rating, {1} is a placeholder for a number
            Nuvola.format(ngettext("Rating: {1} star", "Rating: {1} stars", stars), stars), // label
            null, // mnemo_label
            null, // icon
            null  // keybinding
            ]);
    Nuvola.actions.addRadioAction("playback", "win", ACTION_RATING, 0, ratingOptions);
}

WebApp._onInitWebWorker = function(emitter)
{
    Nuvola.WebApp._onInitWebWorker.call(this, emitter);

    Nuvola.actions.connect("ActionActivated", this);
    this.thumbsUp = undefined;
    this.thumbsDown = undefined;
    this.starRating = undefined;
    this.starRatingEnabled = undefined;
    this.thumbRatingEnabled = undefined;
    this.state = State.UNKNOWN;
    document.addEventListener("DOMContentLoaded", this._onPageReady.bind(this));
}

/**
 * Signal handler for @link{Core::UriChanged}
 */
WebApp._onUriChanged = function(emitter, uri)
{
    /*
     * Users that use the queue page a lot might end up with it as a start-up page. However, this page is always empty
     * and not useful at all, so load Listen now page instead. https://bugs.launchpad.net/nuvola-player/+bug/1306678
     */
    if (uri === "https://play.google.com/music/listen#/ap/queue")
        uri = this.meta.home_url;

    Nuvola.WebApp._onUriChanged.call(this, emitter, uri);
}

WebApp._onPageReady = function()
{
    this.addNavigationButtons();
    this.update();
}

WebApp.update = function()
{
    var track = {};
    try
    {
        track.artLocation = document.getElementById('playingAlbumArt').src;
    }
    catch(e)
    {
        track.artLocation =  null;
    }

    try
    {
        var elm = document.getElementById('playerSongTitle').firstChild;
        track.title = elm.innerText || elm.textContent;
    }
    catch(e)
    {
        track.title = null;
    }

    try
    {
        var elm = document.getElementById('player-artist').firstChild;
        track.artist = elm.innerText || elm.textContent;
    }
    catch (e)
    {
        track.artist = null;
    }

    try
    {
        var elm = document.querySelector("#playerSongInfo .player-album");
        track.album = elm.innerText || elm.textContent;
    }
    catch (e)
    {
        track.album = null;
    }

    player.setTrack(track);

    this.state = State.UNKNOWN;
    var prevSong, nextSong, canPlay, canPause;
    try
    {
        var buttons = document.querySelector("#player .player-middle");
        var pp = buttons.childNodes[2];
        if (pp.disabled === true)
            this.state = State.UNKNOWN;
        else if (pp.className == "flat-button playing")
            this.state = State.PLAYING;
        else
            this.state = State.PAUSED;

        if (this.state !== State.UNKNOWN)
        {
            prevSong = buttons.childNodes[1].disabled === false;
            nextSong = buttons.childNodes[3].disabled === false;
        }
        else
        {
            prevSong = nextSong = false;
        }
    }
    catch (e)
    {
        prevSong = nextSong = false;
    }

    player.setPlaybackState(this.state);
    player.setCanPause(this.state === State.PLAYING);
    player.setCanPlay(this.state === State.PAUSED || this.state === State.UNKNOWN && this._luckyMix());
    player.setCanGoPrev(prevSong);
    player.setCanGoNext(nextSong);

    // Extract enabled flag and state from a web page
    var actionsEnabled = {};
    var actionsStates = {};
    try
    {
        actionsEnabled[ACTION_THUMBS_UP] = false;
        actionsEnabled[ACTION_THUMBS_DOWN] = false;
        var thumbs = this.getThumbs();
        if (thumbs[0].style.visibility !== "hidden")
        {
            this.toggleThumbRating(true);
            actionsStates[ACTION_THUMBS_UP] = thumbs[1].className === "selected";
            actionsStates[ACTION_THUMBS_DOWN] = thumbs[2].className === "selected";
            actionsEnabled[ACTION_THUMBS_UP] = true;
            actionsEnabled[ACTION_THUMBS_DOWN] = true;
        }
    }
    catch (e)
    {
    }
    try
    {
        actionsEnabled[ACTION_RATING] = false;
        var stars = this.getStars();
        if (stars.style.visibility !== "hidden")
        {
            this.toggleStarRating(true);
            actionsStates[ACTION_RATING] = stars.childNodes[0].getAttribute("data-rating") * 1;
            actionsEnabled[ACTION_RATING] = true;
        }
    }
    catch (e)
    {
    }

    // Compare with previous values and update if necessary
    Nuvola.actions.updateEnabledFlags(actionsEnabled);
    Nuvola.actions.updateStates(actionsStates);

    setTimeout(this.update.bind(this), 500);
}

WebApp.getPlayerButtons = function()
{
    var elm = document.querySelector("#player .player-middle");
    return elm ? elm.childNodes : null;
}

WebApp._onActionActivated = function(emitter, name, param)
{
    var buttons = this.getPlayerButtons();
    if (buttons)
    {
        var prev_song = buttons[1];
        var next_song = buttons[3];
        var play_pause = buttons[2];
    }
    else
    {
        var prev_song = null;
        var next_song = null;
        var play_pause = null;
    }

    switch (name)
    {
    /* Base media player actions */
    case PlayerAction.TOGGLE_PLAY:
        var luckyMix = this._luckyMix();
        if (this.state === State.UNKNOWN && luckyMix)
            Nuvola.clickOnElement(luckyMix);
        else
            Nuvola.clickOnElement(play_pause);
        break;
    case PlayerAction.PLAY:
        var luckyMix = this._luckyMix();
        if (this.state === State.UNKNOWN && luckyMix)
            Nuvola.clickOnElement(luckyMix);
        else if (this.state != State.PLAYING)
            Nuvola.clickOnElement(play_pause);
        break;
    case PlayerAction.PAUSE:
    case PlayerAction.STOP:
        if (this.state == State.PLAYING)
            Nuvola.clickOnElement(play_pause);
        break;
    case PlayerAction.PREV_SONG:
        if (prev_song)
            Nuvola.clickOnElement(prev_song);
        break;
    case PlayerAction.NEXT_SONG:
        if (next_song)
            Nuvola.clickOnElement(next_song);
        break;

    /* Custom actions */
    case ACTION_THUMBS_UP:
        Nuvola.clickOnElement(this.getThumbs()[1]);
        break;
    case ACTION_THUMBS_DOWN:
        Nuvola.clickOnElement(this.getThumbs()[2]);
        break;
    case ACTION_RATING:
        var stars = this.getStars().childNodes;
        var i = stars.length;
        while (i--)
        {
            var star = stars[i];
            if (star.getAttribute("data-rating") === ("" + param))
            {
                Nuvola.clickOnElement(star);
                break;
            }
        }
        break;
    }
}

WebApp.addNavigationButtons = function()
{
    /* Loading in progress? */
    var loading = document.getElementById("loading-progress");
    if (loading && loading.style.display != "none")
    {
        setTimeout(this.addNavigationButtons.bind(this), 250);
        return;
    }

    var queryBar = document.getElementById("gbq2");
    if (!queryBar)
    {
        console.log("Could not find the query bar.");
        return;
    }

    var queryBarFirstChild = queryBar.firstChild;

    var navigateBack = Nuvola.makeElement("button", null, "<");
    navigateBack.className = "button small vertical-align";
    navigateBack.style.float = "left";
    navigateBack.style.marginRight = "0px";
    navigateBack.style.borderTopRightRadius = "2px";
    navigateBack.style.borderBottomRightRadius = "2px";
    queryBar.insertBefore(navigateBack, queryBarFirstChild);

    var navigateForward = Nuvola.makeElement("button", null, ">");
    navigateForward.className = "button small vertical-align";
    navigateForward.style.float = "left";
    navigateForward.style.marginRight = "15px";
    navigateForward.style.borderLeft = "none";
    navigateForward.style.borderTopLeftRadius = "2px";
    navigateForward.style.borderLeftRightRadius = "2px";
    queryBar.insertBefore(navigateForward, queryBarFirstChild);

    Nuvola.actions.attachButton(Nuvola.BrowserAction.GO_BACK, navigateBack);
    Nuvola.actions.attachButton(Nuvola.BrowserAction.GO_FORWARD, navigateForward);
}

WebApp.getThumbs = function()
{
    var elm = document.querySelector("#player-right-wrapper .thumbs.rating-container");
    return [elm, elm.childNodes[0], elm.childNodes[1]];
}

WebApp.getStars = function()
{
    return document.querySelector("#player-right-wrapper .stars.rating-container");
}

WebApp.toggleStarRating = function(enabled)
{
    if (enabled && this.starRatingEnabled !== true)
    {
        player.addExtraActions(STARS_ACTIONS);
        this.starRatingEnabled = true;
    }
}

WebApp.toggleThumbRating = function(enabled)
{
    if (enabled && this.thumbRatingEnabled !== true)
    {
        player.addExtraActions(THUMBS_ACTIONS);
        this.thumbRatingEnabled = true;
    }
}

WebApp._luckyMix = function()
{
    return location.hash === "#/now" ? document.querySelector("div.ifl-group div.card[data-type=imfl] div.radio-icon") || false : false;
}

WebApp.start();

})(this);  // function(Nuvola)
<|endoftext|>


<commit_before>/*
 * Copyright 2015 Jason Day <jason@jlogday.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

"use strict";

(function(Nuvola)
{

// Create media player component
var player = Nuvola.$object(Nuvola.MediaPlayer);

// Handy aliases
var PlaybackState = Nuvola.PlaybackState;
var PlayerAction = Nuvola.PlayerAction;

// Create new WebApp prototype
var WebApp = Nuvola.$WebApp();

// Initialization routines
WebApp._onInitWebWorker = function(emitter)
{
    Nuvola.WebApp._onInitWebWorker.call(this, emitter);

    var state = document.readyState;
    if (state === "interactive" || state === "complete") {
        this._onPageReady();
    }
    else {
        document.addEventListener("DOMContentLoaded", this._onPageReady.bind(this));
    }
}

// Page is ready for magic
WebApp._onPageReady = function()
{
    // Connect handler for signal ActionActivated
    Nuvola.actions.connect("ActionActivated", this);

    // Start update routine
    this.update();
}

function fetchTrackInfo(className) {
    var rval = null;
    var nl = document.getElementsByClassName(className);
    if (nl.length > 0) {
        rval = nl[0].innerText;
    }

    return rval;
}

/*function fetchTrackInfo() {
    var track = {
        title: null,
        artist: null,
        album: null,
        artLocation: null // always null
    }
    var elmt = document.querySelector('div.media-poster');
    console.log('elmt: ' + elmt);
    if (elmt) {
        track['title'] = elmt.getAttribute('data-title') || 'Unknown Title';
        track['artist'] = elmt.getAttribute('data-grandparent-title') || 'Unknown Artist';
        track['album'] = elmt.getAttribute('data-image-title') || 'Unknown Album';
    }

    return track;
}*/

// Extract data from the web page
WebApp.update = function()
{
    var track = {
        title: null,
        artist: null,
        album: null,
        artLocation: null // always null
    }

    /*var idMap = { title: "track", artist: "artist", album: "album" }
    for (var key in idMap) {
        try {
            track[key] = document.getElementById(idMap[key]).innerText || null;
        }
        catch (e) {
            track[key] = null;
        }
    }

    track['title'] = "Oigen Boigen!";*/
    /*var elmt = document.getElementsByClassName("grandparent-title");
    console.log("elmt: " + elmt);
    if (elmt) {
        console.log("len: " + elmt.length);
        if (elmt.length >= 1) {
            var artist = elmt[0].innerText;
            console.log("artist: " + artist);
            track['artist'] = artist;
        }
    }
    */
    //var artist = fetchTrackInfo('grandparent-title');
    //track['artist'] = artist || 'Unknown Artist';
    track['artist'] = fetchTrackInfo('grandparent-title') || 'Unknown Artist';
    track['title'] = fetchTrackInfo('item-title') || 'Unknown Title';
    //var track = fetchTrackInfo();

    player.setTrack(track);

    try {
        switch (document.getElementById("status").innerText) {
            case "Playing":
                var state = PlaybackState.PLAYING;
                break;
            case "Paused":
                var state = PlaybackState.PAUSED;
                break;
            default:
                var state = PlaybackState.UNKNOWN;
                break;
        }
    }
    catch (e) {
        var state = PlaybackState.UNKNOWN;
    }

    player.setPlaybackState(state);

    var enabled;
    try {
        enabled = !document.getElementById("prev").disabled;
    }
    catch(e) {
        enabled = false;
    }
    player.setCanGoPrev(enabled);

    try {
        enabled  = !document.getElementById("next").disabled;
    }
    catch(e) {
        enabled = false;
    }
    player.setCanGoNext(enabled);

    var playPause = document.getElementById("pp");
    try {
        enabled  = playPause.innerText == "Play";
    }
    catch(e) {
        enabled = false;
    }
    player.setCanPlay(enabled);

    try {
        enabled  = playPause.innerText == "Pause";
    }
    catch(e) {
        enabled = false;
    }
    player.setCanPause(enabled);

    // Schedule the next update
    setTimeout(this.update.bind(this), 500);
}

// Handler of playback actions
WebApp._onActionActivated = function(emitter, name, param) {
    switch (name) {
        case PlayerAction.TOGGLE_PLAY:
            var button = document.getElementsByClassName("pause-btn");
            console.log("button: " + button);
            if (button) {
                Nuvola.clickOnElement(button);
            }
            break;
        case PlayerAction.PLAY:
        case PlayerAction.PAUSE:
        case PlayerAction.STOP:
            Nuvola.clickOnElement(document.getElementById("pp"));
            break;
        case PlayerAction.PREV_SONG:
            Nuvola.clickOnElement(document.getElementById("prev"));
            break;
        case PlayerAction.PREV_SONG:
            Nuvola.clickOnElement(document.getElementById("next"));
            break;
    }
}

WebApp.start();

})(this);  // function(Nuvola)
<commit_msg>Remove unused code, add button code<commit_after>/*
 * Copyright 2015 Jason Day <jason@jlogday.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

"use strict";

(function(Nuvola)
{

// Create media player component
var player = Nuvola.$object(Nuvola.MediaPlayer);

// Handy aliases
var PlaybackState = Nuvola.PlaybackState;
var PlayerAction = Nuvola.PlayerAction;

// Create new WebApp prototype
var WebApp = Nuvola.$WebApp();

// Initialization routines
WebApp._onInitWebWorker = function(emitter)
{
    Nuvola.WebApp._onInitWebWorker.call(this, emitter);

    var state = document.readyState;
    if (state === "interactive" || state === "complete") {
        this._onPageReady();
    }
    else {
        document.addEventListener("DOMContentLoaded", this._onPageReady.bind(this));
    }
}

// Page is ready for magic
WebApp._onPageReady = function()
{
    // Connect handler for signal ActionActivated
    Nuvola.actions.connect("ActionActivated", this);

    // Start update routine
    this.update();
}

function fetchTrackInfo(className) {
    var rval = null;
    var nl = document.getElementsByClassName(className);
    if (nl.length > 0) {
        rval = nl[0].innerText;
    }

    return rval;
}

// Extract data from the web page
WebApp.update = function()
{
    var track = {
        title: null,
        artist: null,
        album: null,
        artLocation: null // always null
    }

    // album only appears to be stored as an attribute in a different element
    track['artist'] = fetchTrackInfo('grandparent-title') || 'Unknown Artist';
    track['title'] = fetchTrackInfo('item-title') || 'Unknown Title';

    player.setTrack(track);

    try {
        switch (document.getElementById("status").innerText) {
            case "Playing":
                var state = PlaybackState.PLAYING;
                break;
            case "Paused":
                var state = PlaybackState.PAUSED;
                break;
            default:
                var state = PlaybackState.UNKNOWN;
                break;
        }
    }
    catch (e) {
        var state = PlaybackState.UNKNOWN;
    }

    player.setPlaybackState(state);

    var enabled;
    try {
        enabled = !document.getElementById("prev").disabled;
        var nl = document.getElementsByClassName("previous-btn");
        if (nl.length > 0) {
            enabled = !nl[0].disabled;
        }
    }
    catch(e) {
        enabled = false;
    }
    player.setCanGoPrev(enabled);

    try {
        enabled  = !document.getElementById("next").disabled;
    }
    catch(e) {
        enabled = false;
    }
    player.setCanGoNext(enabled);

    var playPause = document.getElementById("pp");
    try {
        enabled  = playPause.innerText == "Play";
    }
    catch(e) {
        enabled = false;
    }
    player.setCanPlay(true);

    try {
        enabled  = playPause.innerText == "Pause";
    }
    catch(e) {
        enabled = false;
    }
    player.setCanPause(true);

    // Schedule the next update
    setTimeout(this.update.bind(this), 500);
}

// Handler of playback actions
WebApp._onActionActivated = function(emitter, name, param) {
    switch (name) {
        case PlayerAction.TOGGLE_PLAY:
            var nl = document.getElementsByClassName("pause-btn");
            if (nl.length > 0) {
                Nuvola.clickOnElement(nl[0]);
            }
            break;
        case PlayerAction.PLAY:
            var nl = document.getElementsByClassName("play-btn");
            if (nl.length > 0) {
                Nuvola.clickOnElement(nl[0]);
            }
            break;
        case PlayerAction.PAUSE:
            var nl = document.getElementsByClassName("pause-btn");
            if (nl.length > 0) {
                Nuvola.clickOnElement(nl[0]);
            }
            break;
        case PlayerAction.STOP:
            var nl = document.getElementsByClassName("stop-btn");
            if (nl.length > 0) {
                Nuvola.clickOnElement(nl[0]);
            }
            break;
        case PlayerAction.PREV_SONG:
            Nuvola.clickOnElement(document.getElementById("prev"));
            break;
        case PlayerAction.PREV_SONG:
            Nuvola.clickOnElement(document.getElementById("next"));
            break;
    }
}

WebApp.start();

})(this);  // function(Nuvola)
<|endoftext|>