<commit_before>// Version 1.0
// Script to retreive the watchlist from a friend's trakt account,
// compare it to movies in my radarr library and
// generate a symlink for matches into handbrake watch folder

const config = require('./config');

var { exec } = require('child_process');
var request = require('request');
var fs = require('fs');

// TODO: add start time to log
main();

function main(){
	getTraktMovies( (traktMovies) => {
		getRadarrMovies( (radarrMovies) => {
      compareResults(traktMovies, radarrMovies, (movieMatches) => { // TODO: add count of files to process
				createSymlinkForHandbrake(movieMatches);
				console.log("Movie processing completed");
				});
      });
		});
	}

function getTraktMovies(callback){
  request({
    method: 'GET',
    url: 'https://api.trakt.tv/users/' + config.trakt.traktFriendID +'/watchlist/movies',
    headers: {
      'Content-Type': 'application/json',
      'trakt-api-version': '2',
      'trakt-api-key': config.trakt.traktClientID
    }}, function (error, response, body) {
      // console.log('Status:', response.statusCode);
      // console.log('Headers:', JSON.stringify(response.headers));
      // console.log('Response:', body);
  	  callback(JSON.parse(body));
    });
}

function getRadarrMovies(callback){
  request({
    method: 'GET',
    url: 'http://' + config.radarr.ip + ':' + config.radarr.port + '/api/v3/movie',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': config.radarr.apikey
    }}, function (error, response, body) {
      // console.log('Status:', response.statusCode);
      // console.log('Headers:', JSON.stringify(response.headers));
      // console.log('Response:', body);
      // callback(new Error('bad resp.'));
      callback(JSON.parse(body));
    });
}

function compareResults(traktMovies, radarrMovies, callback){
	var movieMatches = []; // array of imdbID and file path for movies matches between trakt and radarr that has not been previously processed
	// get array of previously processed movies to avoid double-processing
	if (fs.existsSync(config.script.movieHistory)) {
		try {
			var data = fs.readFileSync(config.script.movieHistory);
			var movieHistory = data.toString().split("\n");
			movieHistory.splice(-1,1);

			// iterate through items in traktMovies that have not been previously processed and store the imdbIDs
			for (var i = 0; i < traktMovies.length; i++) {
				if (traktMovies[i].movie.ids.imdb != null && !(movieHistory.indexOf(traktMovies[i].movie.ids.imdb) > -1)) {

					// match traktImdbIDs to items in radarrMovies where downloaded = true
					for (var j = 0; j < radarrMovies.length; j++) {
						if ( traktMovies[i].movie.ids.imdb == radarrMovies[j].imdbId && radarrMovies[j].downloaded == true) {
							var movieDetails = {};
							movieDetails["imdbId"] = traktMovies[i].movie.ids.imdb;
							movieDetails["folderPath"] = radarrMovies[j].folderName;
							movieDetails["fileName"] = radarrMovies[j].movieFile.relativePath;
							movieMatches.push(movieDetails);
						}
					}
				}
			};
			callback(movieMatches);
		} catch (err) {
			console.error(err);
		}
	}
}

function createSymlinkForHandbrake(movies){
	// create symlink in Handbrake watch folder with volume mapping substitution
	// then add imdb of movie to history log to prevent re-processing
	var completedSymlinks = "";
  for (var i = 0; i < movies.length; i++) {
		try {
			var destFile = config.handbrake.hbWatchFolder + "/" + movies[i].fileName;
	    var remappedSourceFile = movies[i].folderPath.replace(config.handbrake.hbVolumeMappingRadarr, config.handbrake.hbVolumeMappingHandbrake) + "/" + movies[i].fileName;
	    fs.symlinkSync(remappedSourceFile, destFile);
			console.log("symlink created: " + destFile);
			completedSymlinks += destFile + "\n";
			fs.appendFileSync(config.script.movieHistory, movies[i].imdbId + "\n"); // log processed movies to file
		} catch (err) {
			console.log(err);
		}
  };
	// send unraid notification with list of created symlinks
	if (completedSymlinks) {
		var unraidNotification = "/usr/local/emhttp/webGui/scripts/notify -e 'unRAID Server Notice' -s 'Handbrake Symlink creation' -d '" + completedSymlinks + "' -i 'normal'";
		exec(unraidNotification, (err, stdout, stderr) => {
			if (err) {
				console.log(err);
				return;
			}
			// the *entire* stdout and stderr (buffered)
	    // console.log(`stdout: ${stdout}`);
	    // console.log(`stderr: ${stderr}`);
		});
	}
}
<commit_msg>Radarr API v3 schema change downloaded -> hasFile<commit_after>// Version 1.0
// Script to retreive the watchlist from a friend's trakt account,
// compare it to movies in my radarr library and
// generate a symlink for matches into handbrake watch folder

const config = require('./config');

var { exec } = require('child_process');
var request = require('request');
var fs = require('fs');

// TODO: add start time to log
main();

function main(){
	getTraktMovies( (traktMovies) => {
		getRadarrMovies( (radarrMovies) => {
      compareResults(traktMovies, radarrMovies, (movieMatches) => { // TODO: add count of files to process
				createSymlinkForHandbrake(movieMatches);
				console.log("Movie processing completed");
				});
      });
		});
	}

function getTraktMovies(callback){
  request({
    method: 'GET',
    url: 'https://api.trakt.tv/users/' + config.trakt.traktFriendID +'/watchlist/movies',
    headers: {
      'Content-Type': 'application/json',
      'trakt-api-version': '2',
      'trakt-api-key': config.trakt.traktClientID
    }}, function (error, response, body) {
      // console.log('Status:', response.statusCode);
      // console.log('Headers:', JSON.stringify(response.headers));
      // console.log('Response:', body);
  	  callback(JSON.parse(body));
    });
}

function getRadarrMovies(callback){
  request({
    method: 'GET',
    url: 'http://' + config.radarr.ip + ':' + config.radarr.port + '/api/v3/movie',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': config.radarr.apikey
    }}, function (error, response, body) {
      // console.log('Status:', response.statusCode);
      // console.log('Headers:', JSON.stringify(response.headers));
      // console.log('Response:', body);
      // callback(new Error('bad resp.'));
      callback(JSON.parse(body));
    });
}

function compareResults(traktMovies, radarrMovies, callback){
	var movieMatches = []; // array of imdbID and file path for movies matches between trakt and radarr that has not been previously processed
	// get array of previously processed movies to avoid double-processing
	if (fs.existsSync(config.script.movieHistory)) {
		try {
			var data = fs.readFileSync(config.script.movieHistory);
			var movieHistory = data.toString().split("\n");
			movieHistory.splice(-1,1);

			// iterate through items in traktMovies that have not been previously processed and store the imdbIDs
			for (var i = 0; i < traktMovies.length; i++) {
				if (traktMovies[i].movie.ids.imdb != null && !(movieHistory.indexOf(traktMovies[i].movie.ids.imdb) > -1)) {

					// match traktImdbIDs to items in radarrMovies where downloaded = true
					for (var j = 0; j < radarrMovies.length; j++) {
						if ( traktMovies[i].movie.ids.imdb == radarrMovies[j].imdbId && radarrMovies[j].hasFile == true) {
							var movieDetails = {};
							movieDetails["imdbId"] = traktMovies[i].movie.ids.imdb;
							movieDetails["folderPath"] = radarrMovies[j].folderName;
							movieDetails["fileName"] = radarrMovies[j].movieFile.relativePath;
							movieMatches.push(movieDetails);
						}
					}
				}
			};
			callback(movieMatches);
		} catch (err) {
			console.error(err);
		}
	}
}

function createSymlinkForHandbrake(movies){
	// create symlink in Handbrake watch folder with volume mapping substitution
	// then add imdb of movie to history log to prevent re-processing
	var completedSymlinks = "";
  for (var i = 0; i < movies.length; i++) {
		try {
			var destFile = config.handbrake.hbWatchFolder + "/" + movies[i].fileName;
	    var remappedSourceFile = movies[i].folderPath.replace(config.handbrake.hbVolumeMappingRadarr, config.handbrake.hbVolumeMappingHandbrake) + "/" + movies[i].fileName;
	    fs.symlinkSync(remappedSourceFile, destFile);
			console.log("symlink created: " + destFile);
			completedSymlinks += destFile + "\n";
			fs.appendFileSync(config.script.movieHistory, movies[i].imdbId + "\n"); // log processed movies to file
		} catch (err) {
			console.log(err);
		}
  };
	// send unraid notification with list of created symlinks
	if (completedSymlinks) {
		var unraidNotification = "/usr/local/emhttp/webGui/scripts/notify -e 'unRAID Server Notice' -s 'Handbrake Symlink creation' -d '" + completedSymlinks + "' -i 'normal'";
		exec(unraidNotification, (err, stdout, stderr) => {
			if (err) {
				console.log(err);
				return;
			}
			// the *entire* stdout and stderr (buffered)
	    // console.log(`stdout: ${stdout}`);
	    // console.log(`stderr: ${stderr}`);
		});
	}
}
<|endoftext|>


<commit_before>$(document).ready(function () {
    new WOW().init();
    $("[data-toggle=popover]").popover({ trigger: "hover" });
    $('.counter').counterUp();
    $.stellar();
});

function selectorCallback(id, event) {
    url = window.location.origin + window.location.pathname + '?bra_id='+id;
    window.location = url;
}

function getParameterByName(name, url) {
    if (!url) url = window.location.href;
    url = url.toLowerCase();
    name = name.replace(/[\[\]]/g, "\\$&").toLowerCase();

    var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
        results = regex.exec(url);
    if (!results) return null;
    if (!results[2]) return '';
    return decodeURIComponent(results[2].replace(/\+/g, " "));
}
<commit_msg>Adds facebook comments<commit_after>(function(d, s, id) {
    var js, fjs = d.getElementsByTagName(s)[0];
    if (d.getElementById(id)) return;
    js = d.createElement(s); js.id = id;
    js.src = "//connect.facebook.net/pt_BR/sdk.js#xfbml=1&version=v2.5&appId=222520191136295";
    fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));

$(document).ready(function () {
    new WOW().init();
    $("[data-toggle=popover]").popover({ trigger: "hover" });
    $('.counter').counterUp();
    $.stellar();
});

function selectorCallback(id, event) {
    url = window.location.origin + window.location.pathname + '?bra_id='+id;
    window.location = url;
}

function getParameterByName(name, url) {
    if (!url) url = window.location.href;
    url = url.toLowerCase();
    name = name.replace(/[\[\]]/g, "\\$&").toLowerCase();

    var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
        results = regex.exec(url);
    if (!results) return null;
    if (!results[2]) return '';
    return decodeURIComponent(results[2].replace(/\+/g, " "));
}
<|endoftext|>


<commit_before>import React from 'react';
import { Button, Grid, Row, Col } from 'react-bootstrap';

import * as storage from '../../services/localStorage';

class HeroList extends React.Component {
    constructor() {
        super();
        this.player = storage.get('player');
    }
    selectHero(id, updatePlayer) {
        this.player.activeHeroId = id;
        storage.set('player', this.player);
        updatePlayer(this.player);
    }
    render() {
        const heroStyle = {
            marginBottom: 10
        };
        const btnStyle = {
            marginLeft: 5
        };
        const heroes = this.props.heroes.map( hero => {
            return

                {hero.name} ({hero.exp} lvl)
                <Button bsSize="xsmall" bsStyle="primary" style={btnStyle} value={hero}
                        onClick={this.selectHero.bind(this, hero.id, this.props.updatePlayer)}>select</Button>

        });

        return (

                <Grid>
                    <Row className="show-grid">

{heroes}

                    </Row>
                </Grid>

        );
    }
}

export default HeroList
<commit_msg>HeroList refactoring<commit_after>import React from 'react';
import { Button, Grid, Row } from 'react-bootstrap';

import * as storage from '../../services/localStorage';

export default class HeroList extends React.Component {

    constructor() {
        super();

        this.player = storage.get('player');
    }

    selectHero(id, updatePlayer) {
        this.player.activeHeroId = id;

        storage.set('player', this.player);

        updatePlayer(this.player);
    }

    _createHeroesList(heroes) {
        const result = heroes.map(hero => {
            return (

                    {hero.name}{' '}
                    ({hero.exp} lvl)
                    <Button
                        bsSize="xsmall"
                        bsStyle="primary"
                        style={{ marginLeft: 5 }}
                        value={hero}
                        onClick={this.selectHero.bind(this, hero.id, this.props.updatePlayer)}
                    >
                        select
                    </Button>

            )
        });

        return result;
    }

    render() {
        const heroes = this._createHeroesList(this.props.heroes);

        return (

                <Grid>
                    <Row className="show-grid">

{heroes}

                    </Row>
                </Grid>

        );
    }
}
<|endoftext|>


<commit_before>import React, {PropTypes} from 'react';
import {NavLink} from 'fluxible-router';

class Carousel extends React.Component {
    constructor(props) {
        super(props);
        this.slider = null;
        this.state = {paused: 0};
    }
    componentDidMount(){
        this.slider = $('.glide').glide({
            type: 'slideshow',
            autoplay: 6000,
            centered: true,
            keyboard: true,
            autoheight: true,
            centered: true,
            afterTransition: function(data){
                $('.gslide-header').removeClass('active');
                $('.gh' + data.index).addClass('active');
            },
        });
        //display carousel
        $('.hide-element').removeClass('hide-element');
    }
    togglePause() {
        if(this.state.paused){
            this.slider.data('glide_api').start(4000);
        }else{
            this.slider.data('glide_api').pause();
        }
        this.setState({paused: !this.state.paused});
    }
    render() {
        return (

                                            <button className="glide__arrow prev ui basic icon button" data-glide-dir="<" tabIndex="-1"></button>
                                            <button className="glide__arrow next ui basic icon button" data-glide-dir=">" tabIndex="-1"></button>

                                        {this.state.paused ?  : }
                                        {this.state.paused ? 'Play' : 'Pause'}

Discover SlideWiki

                                                    Create Online Slide Decks

description

                                            Repurpose and Reuse Educational Content

                                            Collaborative Content Authoring

                                            Supporting Knowledge Communities

        );
    }
}

export default Carousel;
<commit_msg>image resizing<commit_after>import React, {PropTypes} from 'react';
import {NavLink} from 'fluxible-router';

class Carousel extends React.Component {
    constructor(props) {
        super(props);
        this.slider = null;
        this.state = {paused: 0};
    }
    componentDidMount(){
        this.slider = $('.glide').glide({
            type: 'slideshow',
            autoplay: 6000,
            centered: true,
            keyboard: true,
            autoheight: true,
            centered: true,
            afterTransition: function(data){
                $('.gslide-header').removeClass('active');
                $('.gh' + data.index).addClass('active');
            },
        });
        //display carousel
        $('.hide-element').removeClass('hide-element');
    }
    togglePause() {
        if(this.state.paused){
            this.slider.data('glide_api').start(4000);
        }else{
            this.slider.data('glide_api').pause();
        }
        this.setState({paused: !this.state.paused});
    }
    render() {
        return (

                                            <button className="glide__arrow prev ui basic icon button" data-glide-dir="<" tabIndex="-1"></button>
                                            <button className="glide__arrow next ui basic icon button" data-glide-dir=">" tabIndex="-1"></button>

                                        {this.state.paused ?  : }
                                        {this.state.paused ? 'Play' : 'Pause'}

Discover SlideWiki

                                                    Create Online Slide Decks

description

                                            Repurpose and Reuse Educational Content

                                            Collaborative Content Authoring

                                            Supporting Knowledge Communities

        );
    }
}

export default Carousel;
<|endoftext|>


<commit_before>
/**
 * router.js
 *
 * Setup routing table
 */

var api = require('koa-router')();

var getUserInfo = require('../handlers/get-user-info');
var getRoomInfo = require('../handlers/get-room-info');
var getRoomUsers = require('../handlers/get-room-users');
var enterRoom = require('../handlers/enter-room');
var exitRoom = require('../handlers/exit-room');

module.exports = myRouter;

/**
 * Internal router
 *
 * @param   Object  app  Koa object
 * @return  MW
 */
function myRouter(app) {
	if (!app) {
		return;
	}

	api.get('/', function *() {
		this.body = 'hello world';
	});

	api.get('/api', function *() {
		this.body = 'hello world2';
	});

	api.get('/api/users/:uid', getUserInfo());
	api.get('/api/rooms/:rid', getRoomInfo());
	api.get('/api/rooms/:rid/users', getRoomUsers());
	api.put('/api/rooms/:rid/users/:uid', enterRoom());
	api.del('/api/rooms/:rid/users/:uid', exitRoom());

	app.use(api.routes())
	app.use(api.allowedMethods());
};
<commit_msg>clean up test route<commit_after>
/**
 * router.js
 *
 * Setup routing table
 */

var api = require('koa-router')();

var getUserInfo = require('../handlers/get-user-info');
var getRoomInfo = require('../handlers/get-room-info');
var getRoomUsers = require('../handlers/get-room-users');
var enterRoom = require('../handlers/enter-room');
var exitRoom = require('../handlers/exit-room');

module.exports = myRouter;

/**
 * Internal router
 *
 * @param   Object  app  Koa object
 * @return  MW
 */
function myRouter(app) {
	if (!app) {
		return;
	}

	api.get('/', function *() {
		this.body = 'hello world';
	});

	api.get('/api/users/:uid', getUserInfo());
	api.get('/api/rooms/:rid', getRoomInfo());
	api.get('/api/rooms/:rid/users', getRoomUsers());
	api.put('/api/rooms/:rid/users/:uid', enterRoom());
	api.del('/api/rooms/:rid/users/:uid', exitRoom());

	app.use(api.routes())
	app.use(api.allowedMethods());
};
<|endoftext|>


<commit_before>const xss = require('xss')

module.exports = {
  async init(input, config) {
    if (config.safeHTML) {
      input = xss(input, {
        whiteList: {
          ...xss.whiteList,
          a: ['class', 'id', 'href', 'style', 'target', 'title'],
          blockquote: ['class', 'id', 'style'],
          code: ['class', 'style'],
          div: ['class', 'id', 'style'],
          em: ['class', 'style'],
          h1: ['class', 'id', 'style'],
          h2: ['class', 'id', 'style'],
          h3: ['class', 'id', 'style'],
          h4: ['class', 'id', 'style'],
          h5: ['class', 'id', 'style'],
          h6: ['class', 'id', 'style'],
          img: ['alt', 'class', 'draggable', 'height', 'src', 'style', 'width'],
          kbd: ['class'],
          li: ['class', 'style'],
          mark: ['class', 'style'],
          ol: ['class', 'style'],
          p: ['class', 'style'],
          path: ['d', 'style'],
          pre: ['class', 'style'],
          span: ['class', 'style'],
          strong: ['class', 'style'],
          svg: ['width', 'height', 'viewBox', 'preserveAspectRatio', 'style'],
          table: ['border', 'class', 'id', 'style', 'width'],
          tbody: ['class', 'style'],
          td: ['align', 'class', 'colspan', 'rowspan', 'style', 'valign'],
          th: ['align', 'class', 'colspan', 'rowspan', 'style', 'valign'],
          thead: ['class', 'style'],
          tr: ['class', 'rowspan', 'style', 'align', 'valign'],
          ul: ['class', 'style']
        },
        css: false
      })
    }
    return input
  }
}
<commit_msg>fix: add missing html tags to whitelist<commit_after>const xss = require('xss')

module.exports = {
  async init(input, config) {
    if (config.safeHTML) {
      input = xss(input, {
        whiteList: {
          ...xss.whiteList,
          a: ['class', 'id', 'href', 'style', 'target', 'title'],
          blockquote: ['class', 'id', 'style'],
          code: ['class', 'style'],
          details: ['class', 'style'],
          div: ['class', 'id', 'style'],
          em: ['class', 'style'],
          figure: ['class', 'style'],
          h1: ['class', 'id', 'style'],
          h2: ['class', 'id', 'style'],
          h3: ['class', 'id', 'style'],
          h4: ['class', 'id', 'style'],
          h5: ['class', 'id', 'style'],
          h6: ['class', 'id', 'style'],
          img: ['alt', 'class', 'draggable', 'height', 'src', 'style', 'width'],
          kbd: ['class'],
          li: ['class', 'style'],
          mark: ['class', 'style'],
          ol: ['class', 'style'],
          p: ['class', 'style'],
          path: ['d', 'style'],
          pre: ['class', 'style'],
          section: ['class', 'style'],
          span: ['class', 'style'],
          strong: ['class', 'style'],
          summary: ['class', 'style'],
          svg: ['width', 'height', 'viewBox', 'preserveAspectRatio', 'style'],
          table: ['border', 'class', 'id', 'style', 'width'],
          tbody: ['class', 'style'],
          td: ['align', 'class', 'colspan', 'rowspan', 'style', 'valign'],
          th: ['align', 'class', 'colspan', 'rowspan', 'style', 'valign'],
          thead: ['class', 'style'],
          tr: ['class', 'rowspan', 'style', 'align', 'valign'],
          ul: ['class', 'style']
        },
        css: false
      })
    }
    return input
  }
}
<|endoftext|>


<commit_before>const xss = require('xss')

module.exports = {
  async init(input, config) {
    if (config.safeHTML) {
      input = xss(input, {
        whiteList: {
          ...xss.whiteList,
          a: ['class', 'id', 'href', 'style', 'target', 'title'],
          blockquote: ['class', 'id', 'style'],
          code: ['class', 'style'],
          details: ['class', 'style'],
          div: ['class', 'id', 'style'],
          em: ['class', 'style'],
          figcaption: ['class', 'style'],
          figure: ['class', 'style'],
          h1: ['class', 'id', 'style'],
          h2: ['class', 'id', 'style'],
          h3: ['class', 'id', 'style'],
          h4: ['class', 'id', 'style'],
          h5: ['class', 'id', 'style'],
          h6: ['class', 'id', 'style'],
          img: ['alt', 'class', 'draggable', 'height', 'src', 'style', 'width'],
          input: ['class', 'disabled', 'type', 'checked', 'id'],
          kbd: ['class'],
          label: ['class', 'id', 'for'],
          li: ['class', 'style'],
          mark: ['class', 'style'],
          ol: ['class', 'style'],
          p: ['class', 'style'],
          path: ['d', 'style'],
          pre: ['class', 'style'],
          section: ['class', 'style'],
          span: ['class', 'style', 'aria-hidden'],
          strong: ['class', 'style'],
          summary: ['class', 'style'],
          svg: ['width', 'height', 'viewbox', 'preserveaspectratio', 'style'],
          table: ['border', 'class', 'id', 'style', 'width'],
          tbody: ['class', 'style'],
          td: ['align', 'class', 'colspan', 'rowspan', 'style', 'valign'],
          th: ['align', 'class', 'colspan', 'rowspan', 'style', 'valign'],
          thead: ['class', 'style'],
          tr: ['class', 'rowspan', 'style', 'align', 'valign'],
          ul: ['class', 'style']
        },
        css: false
      })
    }
    return input
  }
}
<commit_msg>fix: html sanitizer - whitelist i tag<commit_after>const xss = require('xss')

module.exports = {
  async init(input, config) {
    if (config.safeHTML) {
      input = xss(input, {
        whiteList: {
          ...xss.whiteList,
          a: ['class', 'id', 'href', 'style', 'target', 'title'],
          blockquote: ['class', 'id', 'style'],
          code: ['class', 'style'],
          details: ['class', 'style'],
          div: ['class', 'id', 'style'],
          em: ['class', 'style'],
          figcaption: ['class', 'style'],
          figure: ['class', 'style'],
          h1: ['class', 'id', 'style'],
          h2: ['class', 'id', 'style'],
          h3: ['class', 'id', 'style'],
          h4: ['class', 'id', 'style'],
          h5: ['class', 'id', 'style'],
          h6: ['class', 'id', 'style'],
          i: ['class', 'style'],
          img: ['alt', 'class', 'draggable', 'height', 'src', 'style', 'width'],
          input: ['class', 'disabled', 'type', 'checked', 'id'],
          kbd: ['class'],
          label: ['class', 'id', 'for'],
          li: ['class', 'style'],
          mark: ['class', 'style'],
          ol: ['class', 'style'],
          p: ['class', 'style'],
          path: ['d', 'style'],
          pre: ['class', 'style'],
          section: ['class', 'style'],
          span: ['class', 'style', 'aria-hidden'],
          strong: ['class', 'style'],
          summary: ['class', 'style'],
          svg: ['width', 'height', 'viewbox', 'preserveaspectratio', 'style'],
          table: ['border', 'class', 'id', 'style', 'width'],
          tbody: ['class', 'style'],
          td: ['align', 'class', 'colspan', 'rowspan', 'style', 'valign'],
          th: ['align', 'class', 'colspan', 'rowspan', 'style', 'valign'],
          thead: ['class', 'style'],
          tr: ['class', 'rowspan', 'style', 'align', 'valign'],
          ul: ['class', 'style']
        },
        css: false
      })
    }
    return input
  }
}
<|endoftext|>


<commit_before>/*
 * Live view display of the output of the Onyx
 *
 * (c) 2014 Edouard Lafargue, ed@lafargue.name
 * All rights reserved.
 */

define(function(require) {
    "use strict";

    var $       = require('jquery'),
        _       = require('underscore'),
        Backbone = require('backbone'),
        utils    = require('app/utils'),
        simpleplot = require('app/lib/flotplot'),
        template = require('js/tpl/instruments/OnyxLiveView.js');

    // Load the flot library & flot time plugin:
    require('flot');
    require('flot_time');
    require('flot_resize');

    return Backbone.View.extend({

        initialize:function (options) {

            this.currentDevice = null;
            this.showstream = settings.get('showstream');

            this.deviceinitdone = false;
            this.plotavg = false;

            // Get frequency and span if specified:
            var span = this.model.get('liveviewspan');     // In seconds
            var period = this.model.get('liveviewperiod'); // Polling frequency

            var livepoints = 300; // 5 minutes @ 1 Hz
            if (span && period) {
                livepoints = span/period;
            }

            // We will pass this when we create plots, this is the global
            // config for the look and feel of the plot
            this.plotoptions = {
                points: livepoints
            };

            // Keep an array for moving average over the last X samples
            // In Live view, we fix this at 1 minute. In log management, we will
            // make this configurable
            this.movingAvgPoints = 60;
            this.movingAvgData = [];  // Note: used for the graph, this stores the result of the moving average

            this.prevStamp = 0;

            linkManager.on('status', this.updatestatus, this);
            linkManager.on('input', this.showInput, this);

        },

        events: {
        },

        render:function () {
            var self = this;
            console.log('Main render of Onyx live view');
            $(this.el).html(template());

            // Hide the raw data stream if we don't want it
            if (!this.showstream) {
                $('#showstream',this.el).css('visibility', 'hidden');
            }

            linkManager.requestStatus();
            this.addPlot();
            return this;
        },

        addPlot: function() {
            var self = this;

            this.plot = new simpleplot({model: this.model, settings:this.plotoptions});
            if (this.plot != null) {
                  $('.geigerchart', this.el).append(this.plot.el);
                  this.plot.render();
              }

            // Make sure the chart takes all the window height:
            var rsc = function() {
                var chartheight = window.innerHeight - $('#control-area').height() - $('.header .container').height() - 45;
                if (self.showstream)
                    chartheight -= $('#showstream').height() + 20;

                $('.geigerchart').css('height',
                                           chartheight + 'px'
                                                );
                // The simpleplot lib embeds the chart into .geigerchart
                $('.geigerchart .chart').css('height',
                                           chartheight + 'px'
                                                );

            }

            $(window).resize(rsc);
            rsc();
        },

        onClose: function() {
            console.log("Onyx live view closing...");

            linkManager.off('status', this.updatestatus);
            linkManager.off('input', this.showInput);

            /*
            if (!linkManager.isRecording())
                linkManager.stopLiveStream();
            */
        },

        movingAverager: function(newpoint) {

            this.movingAvgData.push(newpoint);

            // Keep our data to the length we want
            if (this.movingAvgData.length >= this.movingAvgPoints)
                this.movingAvgData = this.movingAvgData.slice(1);

            // Now compute the average
            var avg = 0;
            for (var i= 0; i < this.movingAvgData.length; i++) {
                avg += this.movingAvgData[i];
            }
            return avg/this.movingAvgData.length;

        },

        setdevicetag: function() {
            var tag = $('#devicetagfield',this.el).val();
            linkManager.driver.setdevicetag(tag);
            $('#dtModal',this.el).modal('hide');
        },

        updatestatus: function(data) {
            console.log("Onyx live display: serial status update");

            // Either the port is open and we have not done our device init,
            // or the port is closed and we have to reset the device init status
            if (data.portopen && !this.deviceinitdone) {
                linkManager.driver.ping();
            } else if (!data.portopen) {
                this.deviceinitdone = false;
            }
        },

        // We get there whenever we receive something from the serial port
        showInput: function(data) {
            var self = this;

            if (this.showstream) {
                // Update our raw data monitor
                var i = $('#input',this.el);
                var scroll = (i.val() + JSON.stringify(data) + '\n').split('\n');
                // Keep max 50 lines:
                if (scroll.length > 50) {
                    scroll = scroll.slice(scroll.length-50);
                }
                i.val(scroll.join('\n'));
                // Autoscroll:
                i.scrollTop(i[0].scrollHeight - i.height());
            }

            // Have we read all we need from the device?
            if (!this.deviceinitdone) {
                linkManager.driver.devicetag();
            }

            if (data.devicetag != undefined) {
                if (data.devicetag == "No device tag set") {
                    // Show the device tag set dialog
                    $('#dtModal',this.el).modal('show');
                } else {
                    linkManager.startLiveStream(this.model.get('liveviewperiod'));
                    this.deviceinitdone = true;
                }
            } else {
                if (data.cpm != undefined) {
                    var cpm = parseFloat(data.cpm.value);

                    this.plot.appendPoint({'name': "CPM", 'value': cpm});
                    this.plot.appendPoint({'name': "AVG", 'value': this.movingAverager(cpm) });

                }
            }
        },
    });

});<commit_msg>Correct a bug with Onyx asset tag init<commit_after>/*
 * Live view display of the output of the Onyx
 *
 * (c) 2014 Edouard Lafargue, ed@lafargue.name
 * All rights reserved.
 */

define(function(require) {
    "use strict";

    var $       = require('jquery'),
        _       = require('underscore'),
        Backbone = require('backbone'),
        utils    = require('app/utils'),
        simpleplot = require('app/lib/flotplot'),
        template = require('js/tpl/instruments/OnyxLiveView.js');

    // Load the flot library & flot time plugin:
    require('flot');
    require('flot_time');
    require('flot_resize');

    return Backbone.View.extend({

        initialize:function (options) {

            this.currentDevice = null;
            this.showstream = settings.get('showstream');

            this.deviceinitdone = false;
            this.plotavg = false;

            // Get frequency and span if specified:
            var span = this.model.get('liveviewspan');     // In seconds
            var period = this.model.get('liveviewperiod'); // Polling frequency

            var livepoints = 300; // 5 minutes @ 1 Hz
            if (span && period) {
                livepoints = span/period;
            }

            // We will pass this when we create plots, this is the global
            // config for the look and feel of the plot
            this.plotoptions = {
                points: livepoints
            };

            // Keep an array for moving average over the last X samples
            // In Live view, we fix this at 1 minute. In log management, we will
            // make this configurable
            this.movingAvgPoints = 60;
            this.movingAvgData = [];  // Note: used for the graph, this stores the result of the moving average

            this.prevStamp = 0;

            linkManager.on('status', this.updatestatus, this);
            linkManager.on('input', this.showInput, this);

        },

        events: {
            "click #setdevicetag": "setdevicetag",
        },

        render:function () {
            var self = this;
            console.log('Main render of Onyx live view');
            $(this.el).html(template());

            // Hide the raw data stream if we don't want it
            if (!this.showstream) {
                $('#showstream',this.el).css('visibility', 'hidden');
            }

            linkManager.requestStatus();
            this.addPlot();
            return this;
        },

        addPlot: function() {
            var self = this;

            this.plot = new simpleplot({model: this.model, settings:this.plotoptions});
            if (this.plot != null) {
                  $('.geigerchart', this.el).append(this.plot.el);
                  this.plot.render();
              }

            // Make sure the chart takes all the window height:
            var rsc = function() {
                var chartheight = window.innerHeight - $('#control-area').height() - $('.header .container').height() - 45;
                if (self.showstream)
                    chartheight -= $('#showstream').height() + 20;

                $('.geigerchart').css('height',
                                           chartheight + 'px'
                                                );
                // The simpleplot lib embeds the chart into .geigerchart
                $('.geigerchart .chart').css('height',
                                           chartheight + 'px'
                                                );

            }

            $(window).resize(rsc);
            rsc();
        },

        onClose: function() {
            console.log("Onyx live view closing...");

            linkManager.off('status', this.updatestatus);
            linkManager.off('input', this.showInput);

            /*
            if (!linkManager.isRecording())
                linkManager.stopLiveStream();
            */
        },

        movingAverager: function(newpoint) {

            this.movingAvgData.push(newpoint);

            // Keep our data to the length we want
            if (this.movingAvgData.length >= this.movingAvgPoints)
                this.movingAvgData = this.movingAvgData.slice(1);

            // Now compute the average
            var avg = 0;
            for (var i= 0; i < this.movingAvgData.length; i++) {
                avg += this.movingAvgData[i];
            }
            return avg/this.movingAvgData.length;

        },

        setdevicetag: function() {
            var tag = $('#devicetagfield',this.el).val();
            linkManager.driver.setdevicetag(tag);
            $('#dtModal',this.el).modal('hide');
        },

        updatestatus: function(data) {
            console.log("Onyx live display: serial status update");

            // Either the port is open and we have not done our device init,
            // or the port is closed and we have to reset the device init status
            if (data.portopen && !this.deviceinitdone) {
                linkManager.driver.ping();
            } else if (!data.portopen) {
                this.deviceinitdone = false;
            }
        },

        // We get there whenever we receive something from the serial port
        showInput: function(data) {
            var self = this;

            if (this.showstream) {
                // Update our raw data monitor
                var i = $('#input',this.el);
                var scroll = (i.val() + JSON.stringify(data) + '\n').split('\n');
                // Keep max 50 lines:
                if (scroll.length > 50) {
                    scroll = scroll.slice(scroll.length-50);
                }
                i.val(scroll.join('\n'));
                // Autoscroll:
                i.scrollTop(i[0].scrollHeight - i.height());
            }

            // Have we read all we need from the device?
            if (!this.deviceinitdone) {
                linkManager.driver.devicetag();
            }

            if (data.devicetag != undefined) {
                if (data.devicetag == "No device tag set") {
                    // Show the device tag set dialog
                    $('#dtModal',this.el).modal('show');
                } else {
                    linkManager.startLiveStream(this.model.get('liveviewperiod'));
                    this.deviceinitdone = true;
                }
            } else {
                if (data.cpm != undefined) {
                    var cpm = parseFloat(data.cpm.value);

                    this.plot.appendPoint({'name': "CPM", 'value': cpm});
                    this.plot.appendPoint({'name': "AVG", 'value': this.movingAverager(cpm) });

                }
            }
        },
    });

});<|endoftext|>


<commit_before>/*
    ***** BEGIN LICENSE BLOCK *****

    Copyright © 2015 Center for History and New Media
                     George Mason University, Fairfax, Virginia, USA
                     http://zotero.org

    This file is part of Zotero.

    Zotero is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Zotero is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with Zotero.  If not, see <http://www.gnu.org/licenses/>.

    ***** END LICENSE BLOCK *****
*/

"use strict";

Components.utils.import("resource://zotero/config.js");
Components.utils.import("resource:///modules/CustomizableUI.jsm");

var Zotero = Components.classes["@zotero.org/Zotero;1"]
	.getService(Components.interfaces.nsISupports)
	.wrappedJSObject;
var comboButtonsID = 'zotero-toolbar-buttons';
addIcon();

function addIcon() {
	if (Zotero.toolbarIconAdded) {
		return;
	}

	CustomizableUI.addListener({
		onWidgetAdded: function (id, area, position) {
			if (id == comboButtonsID) {
				// When dropping combo button into panel, add two independent buttons instead
				if (area == CustomizableUI.AREA_PANEL) {
					let mainID = getSingleID('main');
					let saveID = getSingleID('save');
					CustomizableUI.removeWidgetFromArea(id);
					// Remove independent main and save buttons first if they're already in panel
					CustomizableUI.removeWidgetFromArea(mainID);
					CustomizableUI.removeWidgetFromArea(saveID);
					CustomizableUI.addWidgetToArea(mainID, area, position);
					let placement = CustomizableUI.getPlacementOfWidget(mainID)
					let mainPos = placement.position;
					CustomizableUI.addWidgetToArea(saveID, area, mainPos + 1);
					return;
				}

				var isUpgrade = false;
				try {
					isUpgrade = Zotero.Prefs.get("firstRunGuidanceShown.saveIcon");
				} catch(e) {}
				var property = "firstRunGuidance.toolbarButton." + (isUpgrade ? "upgrade" : "new");
				var shortcut = Zotero.getString(
						Zotero.isMac ? "general.keys.cmdShift" : "general.keys.ctrlShift"
					) + Zotero.Prefs.get("keys.openZotero");

				let widget = CustomizableUI.getWidget(id);
				for (let instance of widget.instances) {
					let doc = instance.node.ownerDocument;

					updateItemForArea(instance.node, area);

					doc.getElementById("zotero-main-button-guidance").show({
						text: Zotero.getString(property, shortcut)
					});
					doc.getElementById("zotero-save-button-guidance").show();
				}
			}
			else if (id == getSingleID('save')) {
				let widget = CustomizableUI.getWidget(id);
				for (let instance of widget.instances) {
					instance.node.ownerDocument.defaultView.Zotero_Browser.updateStatus();
				}
			}
		},

		onWidgetOverflow: function (node, container) {
			if (node.id == comboButtonsID) {
				node.classList.add("toolbarbutton-1");
			}
		},

		onWidgetUnderflow: function (node, container) {
			if (node.id == comboButtonsID) {
				node.classList.remove("toolbarbutton-1");
			}
		},

		// Save icon in panel isn't in DOM until menu is shown once and therefore isn't updated
		// on page loads, so update the icon status when the panel is first shown so that it
		// doesn't remain disabled
		onAreaNodeRegistered: function (area, node) {
			if (area == CustomizableUI.AREA_PANEL) {
				var placement = CustomizableUI.getPlacementOfWidget(comboButtonsID)
				var update = false;
				let singleID = getSingleID('save');
				if (placement && placement.area == CustomizableUI.AREA_PANEL) {
					update = true;
				}
				else {
					placement = CustomizableUI.getPlacementOfWidget(singleID);
					if (placement && placement.area == CustomizableUI.AREA_PANEL) {
						update = true;
					}
				}
				if (update) {
					let widget = CustomizableUI.getWidget(singleID);
					for (let instance of widget.instances) {
						instance.node.ownerDocument.defaultView.Zotero_Browser.updateStatus();
					}
				}
			}
		}
	})

	// Create the combo buttons, which go in the toolbar by default
	CustomizableUI.createWidget({
		id: comboButtonsID,
		type: 'custom',
		label: ZOTERO_CONFIG.CLIENT_NAME,
		tooltiptext: ZOTERO_CONFIG.CLIENT_NAME,
		defaultArea: CustomizableUI.AREA_NAVBAR,
		onBuild: function (document) {
			const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";

			var item = document.createElementNS(kNSXUL, "toolbaritem");
			item.setAttribute("id", comboButtonsID);
			item.setAttribute("label", "Zotero (Combo)"); // TODO: localize
			// Set this as an attribute in addition to the property to make sure we can style correctly.
			item.setAttribute("removable", "true");
			item.classList.add("chromeclass-toolbar-additional");

			['main', 'save'].map(button => {
				return {
					name: button,
					id: getID(button),
					tooltiptext: getTooltipText(button),
					oncommand: getCommand(button)
				};
			}).forEach(function(attribs, index) {
				if (index != 0) {
					item.appendChild(document.createElementNS(kNSXUL, "separator"));
				}
				let button = document.createElementNS(kNSXUL, "toolbarbutton");
				if (attribs.name == 'main') {
					button.setAttribute('label', Zotero.clientName);
				}
				else if (attribs.name == 'save') {
					button.setAttribute('label', Zotero.getString('ingester.saveToZotero'));
					button.setAttribute('disabled', 'true');
					button.setAttribute('type', 'menu-button');
					let menupopup = document.createElementNS(kNSXUL, "menupopup");
					menupopup.setAttribute('onpopupshowing', "Zotero_Browser.onStatusPopupShowing(event)");
					button.appendChild(menupopup);
				}
				delete attribs.name;
				setAttributes(button, attribs);
				item.appendChild(button);
			});

			updateItemForArea(item, this.currentArea)

			return item;
		}
	});

	// Create the independent Z button, which isn't shown by default
	CustomizableUI.createWidget({
		id: getSingleID('main'),
		label: Zotero.clientName,
		tooltiptext: getTooltipText('main'),
		defaultArea: false,
		onCommand: function (event) {
			event.target.ownerDocument.defaultView.ZoteroOverlay.toggleDisplay();
		}
	});

	// Create the independent save button, which isn't shown by default
	CustomizableUI.createWidget({
		id: getSingleID('save'),
		label: Zotero.getString('ingester.saveToZotero'),
		tooltiptext: getTooltipText('save'),
		defaultArea: false,
		onCommand: function (event) {
			event.target.ownerDocument.defaultView.Zotero_Browser.scrapeThisPage(null, event);
		},
		onCreated: function (button) {
			const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
			button.setAttribute('disabled', 'true');
			button.setAttribute('type', 'menu-button');
			let menupopup = document.createElementNS(kNSXUL, "menupopup");
			menupopup.setAttribute('onpopupshowing', "Zotero_Browser.onStatusPopupShowing(event)");
			button.appendChild(menupopup);
		}
	});

	Zotero.toolbarIconAdded = true;
}

function getID(button) {
	switch (button) {
	case 'main':
		return "zotero-toolbar-main-button";

	case 'save':
		return "zotero-toolbar-save-button";
	}
}

function getSingleID(button) {
	return getID(button) + '-single';
}

function getCommand(button) {
	switch (button) {
	case 'main':
		return "ZoteroOverlay.toggleDisplay()";

	case 'save':
		return "Zotero_Browser.scrapeThisPage(null, event)";
	}
}

function getTooltipText(button) {
	var text;
	switch (button) {
	case 'main':
		if (Zotero && Zotero.initialized) {
			text = Zotero.clientName;
			let key = Zotero.Keys.getKeyForCommand('openZotero');
			if (key) {
				// Add RLE mark in RTL mode to make shortcut render the right way
				text += (Zotero.rtl ? ' \u202B' : ' ') + '('
					+ (Zotero.isMac ? '⇧⌘' : Zotero.getString('general.keys.ctrlShift'))
					+ key
					+ ')';
			}

		}
		else {
			if (Zotero) {
				text = Zotero.startupError;
			}

			// Use defaults if necessary
			if (!text) {
				// Get the stringbundle manually
				let src = 'chrome://zotero/locale/zotero.properties';
				let localeService = Components.classes['@mozilla.org/intl/nslocaleservice;1']
					.getService(Components.interfaces.nsILocaleService);
				let appLocale = localeService.getApplicationLocale();
				let stringBundleService = Components.classes["@mozilla.org/intl/stringbundle;1"]
					.getService(Components.interfaces.nsIStringBundleService);
				let stringBundle = stringBundleService.createBundle(src, appLocale);
				text = stringBundle.GetStringFromName('startupError');
			}
		}
		break;

	case 'save':
		text = Zotero.getString('ingester.saveToZotero');
		break;
	}
	return text;
}

/**
 * Set various attributes that allow treeitem and subelements to be styled properly
 * in the different areas
 */
function updateItemForArea(item, area) {
	if (area) {
		var areaType = CustomizableUI.getAreaType(area);
		var inPanel = area == CustomizableUI.AREA_PANEL;
		var classes = inPanel ? "panel-combined-button" : "toolbarbutton-1 toolbarbutton-combined";
		item.setAttribute("cui-areatype", areaType);
		item.classList.add("toolbaritem-combined-buttons");
		if (inPanel) {
			item.classList.add("panel-wide-item");
		}
		var buttons = item.getElementsByTagName('toolbarbutton');
		for (let i = 0; i < buttons.length; i++) {
			let button = buttons[i];
			button.setAttribute("class", classes);
			button.setAttribute("cui-areatype", areaType);
		}
	}
	// In customization palette pretend it's a single icon
	else {
		item.classList.remove("toolbaritem-combined-buttons");
		item.classList.remove("panel-wide-item");
		var buttons = item.getElementsByTagName('toolbarbutton');
		for (let i = 0; i < buttons.length; i++) {
			let button = buttons[i];
			button.setAttribute("class", "toolbarbutton-1");
			button.removeAttribute("cui-areatype");
		}
	}
}

function setAttributes(elem, attrs) {
	for (let i in attrs) {
		elem.setAttribute(i, attrs[i]);
	}
}
<commit_msg>Fix error creating context menu for independent save button<commit_after>/*
    ***** BEGIN LICENSE BLOCK *****

    Copyright © 2015 Center for History and New Media
                     George Mason University, Fairfax, Virginia, USA
                     http://zotero.org

    This file is part of Zotero.

    Zotero is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Zotero is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with Zotero.  If not, see <http://www.gnu.org/licenses/>.

    ***** END LICENSE BLOCK *****
*/

"use strict";

Components.utils.import("resource://zotero/config.js");
Components.utils.import("resource:///modules/CustomizableUI.jsm");

var Zotero = Components.classes["@zotero.org/Zotero;1"]
	.getService(Components.interfaces.nsISupports)
	.wrappedJSObject;
var comboButtonsID = 'zotero-toolbar-buttons';
addIcon();

function addIcon() {
	if (Zotero.toolbarIconAdded) {
		return;
	}

	CustomizableUI.addListener({
		onWidgetAdded: function (id, area, position) {
			if (id == comboButtonsID) {
				// When dropping combo button into panel, add two independent buttons instead
				if (area == CustomizableUI.AREA_PANEL) {
					let mainID = getSingleID('main');
					let saveID = getSingleID('save');
					CustomizableUI.removeWidgetFromArea(id);
					// Remove independent main and save buttons first if they're already in panel
					CustomizableUI.removeWidgetFromArea(mainID);
					CustomizableUI.removeWidgetFromArea(saveID);
					CustomizableUI.addWidgetToArea(mainID, area, position);
					let placement = CustomizableUI.getPlacementOfWidget(mainID)
					let mainPos = placement.position;
					CustomizableUI.addWidgetToArea(saveID, area, mainPos + 1);
					return;
				}

				var isUpgrade = false;
				try {
					isUpgrade = Zotero.Prefs.get("firstRunGuidanceShown.saveIcon");
				} catch(e) {}
				var property = "firstRunGuidance.toolbarButton." + (isUpgrade ? "upgrade" : "new");
				var shortcut = Zotero.getString(
						Zotero.isMac ? "general.keys.cmdShift" : "general.keys.ctrlShift"
					) + Zotero.Prefs.get("keys.openZotero");

				let widget = CustomizableUI.getWidget(id);
				for (let instance of widget.instances) {
					let doc = instance.node.ownerDocument;

					updateItemForArea(instance.node, area);

					doc.getElementById("zotero-main-button-guidance").show({
						text: Zotero.getString(property, shortcut)
					});
					doc.getElementById("zotero-save-button-guidance").show();
				}
			}
			else if (id == getSingleID('save')) {
				let widget = CustomizableUI.getWidget(id);
				for (let instance of widget.instances) {
					instance.node.ownerDocument.defaultView.Zotero_Browser.updateStatus();
				}
			}
		},

		onWidgetOverflow: function (node, container) {
			if (node.id == comboButtonsID) {
				node.classList.add("toolbarbutton-1");
			}
		},

		onWidgetUnderflow: function (node, container) {
			if (node.id == comboButtonsID) {
				node.classList.remove("toolbarbutton-1");
			}
		},

		// Save icon in panel isn't in DOM until menu is shown once and therefore isn't updated
		// on page loads, so update the icon status when the panel is first shown so that it
		// doesn't remain disabled
		onAreaNodeRegistered: function (area, node) {
			if (area == CustomizableUI.AREA_PANEL) {
				var placement = CustomizableUI.getPlacementOfWidget(comboButtonsID)
				var update = false;
				let singleID = getSingleID('save');
				if (placement && placement.area == CustomizableUI.AREA_PANEL) {
					update = true;
				}
				else {
					placement = CustomizableUI.getPlacementOfWidget(singleID);
					if (placement && placement.area == CustomizableUI.AREA_PANEL) {
						update = true;
					}
				}
				if (update) {
					let widget = CustomizableUI.getWidget(singleID);
					for (let instance of widget.instances) {
						instance.node.ownerDocument.defaultView.Zotero_Browser.updateStatus();
					}
				}
			}
		}
	})

	// Create the combo buttons, which go in the toolbar by default
	CustomizableUI.createWidget({
		id: comboButtonsID,
		type: 'custom',
		label: ZOTERO_CONFIG.CLIENT_NAME,
		tooltiptext: ZOTERO_CONFIG.CLIENT_NAME,
		defaultArea: CustomizableUI.AREA_NAVBAR,
		onBuild: function (document) {
			const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";

			var item = document.createElementNS(kNSXUL, "toolbaritem");
			item.setAttribute("id", comboButtonsID);
			item.setAttribute("label", "Zotero (Combo)"); // TODO: localize
			// Set this as an attribute in addition to the property to make sure we can style correctly.
			item.setAttribute("removable", "true");
			item.classList.add("chromeclass-toolbar-additional");

			['main', 'save'].map(button => {
				return {
					name: button,
					id: getID(button),
					tooltiptext: getTooltipText(button),
					oncommand: getCommand(button)
				};
			}).forEach(function(attribs, index) {
				if (index != 0) {
					item.appendChild(document.createElementNS(kNSXUL, "separator"));
				}
				let button = document.createElementNS(kNSXUL, "toolbarbutton");
				if (attribs.name == 'main') {
					button.setAttribute('label', Zotero.clientName);
				}
				else if (attribs.name == 'save') {
					button.setAttribute('label', Zotero.getString('ingester.saveToZotero'));
					button.setAttribute('disabled', 'true');
					button.setAttribute('type', 'menu-button');
					let menupopup = document.createElementNS(kNSXUL, "menupopup");
					menupopup.setAttribute('onpopupshowing', "Zotero_Browser.onStatusPopupShowing(event)");
					button.appendChild(menupopup);
				}
				delete attribs.name;
				setAttributes(button, attribs);
				item.appendChild(button);
			});

			updateItemForArea(item, this.currentArea)

			return item;
		}
	});

	// Create the independent Z button, which isn't shown by default
	CustomizableUI.createWidget({
		id: getSingleID('main'),
		label: Zotero.clientName,
		tooltiptext: getTooltipText('main'),
		defaultArea: false,
		onCommand: function (event) {
			event.target.ownerDocument.defaultView.ZoteroOverlay.toggleDisplay();
		}
	});

	// Create the independent save button, which isn't shown by default
	CustomizableUI.createWidget({
		id: getSingleID('save'),
		label: Zotero.getString('ingester.saveToZotero'),
		tooltiptext: getTooltipText('save'),
		defaultArea: false,
		onCommand: function (event) {
			event.target.ownerDocument.defaultView.Zotero_Browser.scrapeThisPage(null, event);
		},
		onCreated: function (button) {
			const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
			button.setAttribute('disabled', 'true');
			button.setAttribute('type', 'menu-button');
			let menupopup = button.ownerDocument.createElementNS(kNSXUL, "menupopup");
			menupopup.setAttribute('onpopupshowing', "Zotero_Browser.onStatusPopupShowing(event)");
			button.appendChild(menupopup);
		}
	});

	Zotero.toolbarIconAdded = true;
}

function getID(button) {
	switch (button) {
	case 'main':
		return "zotero-toolbar-main-button";

	case 'save':
		return "zotero-toolbar-save-button";
	}
}

function getSingleID(button) {
	return getID(button) + '-single';
}

function getCommand(button) {
	switch (button) {
	case 'main':
		return "ZoteroOverlay.toggleDisplay()";

	case 'save':
		return "Zotero_Browser.scrapeThisPage(null, event)";
	}
}

function getTooltipText(button) {
	var text;
	switch (button) {
	case 'main':
		if (Zotero && Zotero.initialized) {
			text = Zotero.clientName;
			let key = Zotero.Keys.getKeyForCommand('openZotero');
			if (key) {
				// Add RLE mark in RTL mode to make shortcut render the right way
				text += (Zotero.rtl ? ' \u202B' : ' ') + '('
					+ (Zotero.isMac ? '⇧⌘' : Zotero.getString('general.keys.ctrlShift'))
					+ key
					+ ')';
			}

		}
		else {
			if (Zotero) {
				text = Zotero.startupError;
			}

			// Use defaults if necessary
			if (!text) {
				// Get the stringbundle manually
				let src = 'chrome://zotero/locale/zotero.properties';
				let localeService = Components.classes['@mozilla.org/intl/nslocaleservice;1']
					.getService(Components.interfaces.nsILocaleService);
				let appLocale = localeService.getApplicationLocale();
				let stringBundleService = Components.classes["@mozilla.org/intl/stringbundle;1"]
					.getService(Components.interfaces.nsIStringBundleService);
				let stringBundle = stringBundleService.createBundle(src, appLocale);
				text = stringBundle.GetStringFromName('startupError');
			}
		}
		break;

	case 'save':
		text = Zotero.getString('ingester.saveToZotero');
		break;
	}
	return text;
}

/**
 * Set various attributes that allow treeitem and subelements to be styled properly
 * in the different areas
 */
function updateItemForArea(item, area) {
	if (area) {
		var areaType = CustomizableUI.getAreaType(area);
		var inPanel = area == CustomizableUI.AREA_PANEL;
		var classes = inPanel ? "panel-combined-button" : "toolbarbutton-1 toolbarbutton-combined";
		item.setAttribute("cui-areatype", areaType);
		item.classList.add("toolbaritem-combined-buttons");
		if (inPanel) {
			item.classList.add("panel-wide-item");
		}
		var buttons = item.getElementsByTagName('toolbarbutton');
		for (let i = 0; i < buttons.length; i++) {
			let button = buttons[i];
			button.setAttribute("class", classes);
			button.setAttribute("cui-areatype", areaType);
		}
	}
	// In customization palette pretend it's a single icon
	else {
		item.classList.remove("toolbaritem-combined-buttons");
		item.classList.remove("panel-wide-item");
		var buttons = item.getElementsByTagName('toolbarbutton');
		for (let i = 0; i < buttons.length; i++) {
			let button = buttons[i];
			button.setAttribute("class", "toolbarbutton-1");
			button.removeAttribute("cui-areatype");
		}
	}
}

function setAttributes(elem, attrs) {
	for (let i in attrs) {
		elem.setAttribute(i, attrs[i]);
	}
}
<|endoftext|>


<commit_before>/* Copyright 2012 Will Shanks.
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

'use strict';
/* global gBrowser, window, document, Components */
/* global Zotero, ZoteroPane, Zotero_Browser */
/* global Zutilo, ZutiloChrome, gKeys */

/********************************************/
// Include core modules and built-in modules
/********************************************/
Components.utils.import('resource://gre/modules/AddonManager.jsm');
Components.utils.import('resource://gre/modules/Services.jsm');
Components.utils.import('chrome://zutilo/content/zutilo.jsm');

/********************************************/
// Define keys object
/********************************************/
var keys = {
    getKey: function(keyLabel) {
        return JSON.parse(Zutilo.Prefs.get('shortcut.' + keyLabel))
    },

    setKey: function(keyLabel, key) {
        Zutilo.Prefs.set('shortcut.' + keyLabel, JSON.stringify(key))
    },

    keyName: function(keyLabel) {
        var name = Zutilo._bundle.GetStringFromName('zutilo.shortcuts.name.' +
                                                    keyLabel)
        return name
    },

    keyID: function(keyLabel) {
        return 'zutilo-key-' + keyLabel
    },

    keysEqual: function(key1, key2) {
        var keyEquality =
            (key1.modifiers == key2.modifiers && key1.key == key2.key &&
             key1.keycode == key2.keycode);
        return keyEquality
    },

    getLabels: function() {
        var labels = [];

        for (var shortcut in Zutilo.keys.shortcuts) {
            gKeys.push(shortcut)
        }
    },

    shortcuts: {}
};

/********************************************/
// Define shortcuts
/********************************************/

/********************************************/
// Zutilo's Zotero item menu functions
/********************************************/
keys.shortcuts.copyTags = function(win) {
    win.ZutiloChrome.zoteroOverlay.copyTags()
};
keys.shortcuts.removeTags = function(win) {
    win.ZutiloChrome.zoteroOverlay.removeTags()
};
keys.shortcuts.copyCreators = function(win) {
    win.ZutiloChrome.zoteroOverlay.copyCreators()
};
keys.shortcuts.pasteTags = function(win) {
    win.ZutiloChrome.zoteroOverlay.pasteTags()
};
keys.shortcuts.relateItems = function(win) {
    win.ZutiloChrome.zoteroOverlay.relateItems()
};
keys.shortcuts.showAttachments = function(win) {
    win.ZutiloChrome.zoteroOverlay.showAttachments()
};
keys.shortcuts.modifyAttachments = function(win) {
    win.ZutiloChrome.zoteroOverlay.modifyAttachments()
};
keys.shortcuts.copyItems = function(win) {
    win.ZutiloChrome.zoteroOverlay.copyItems()
};
keys.shortcuts.copyZoteroSelectLink = function(win) {
    win.ZutiloChrome.zoteroOverlay.copyZoteroSelectLink()
};
keys.shortcuts.copyZoteroItemURI = function(win) {
    win.ZutiloChrome.zoteroOverlay.copyZoteroItemURI()
};
keys.shortcuts.createBookItem = function(win) {
    win.ZutiloChrome.zoteroOverlay.createBookItem()
};
keys.shortcuts.createBookSection = function(win) {
    win.ZutiloChrome.zoteroOverlay.createBookSection()
};
keys.shortcuts.copyChildIDs = function(win) {
    win.ZutiloChrome.zoteroOverlay.copyChildIDs()
};
keys.shortcuts.relocateChildren = function(win) {
    win.ZutiloChrome.zoteroOverlay.relocateChildren()
};

/***********************************************/
// Zutilo's Zotero item pane editing functions
/***********************************************/
keys.shortcuts.itemInfo = function(win) {
    win.ZutiloChrome.zoteroOverlay.updatePaneVisibility('zotero-item', 'show');
    win.ZutiloChrome.zoteroOverlay.editItemInfoGUI();
};
keys.shortcuts.addNote = function(win) {
    win.ZutiloChrome.zoteroOverlay.updatePaneVisibility('zotero-item', 'show');
    win.ZutiloChrome.zoteroOverlay.addNoteGUI();
};
keys.shortcuts.addTag = function(win) {
    win.ZutiloChrome.zoteroOverlay.updatePaneVisibility('zotero-item', 'show');
    win.ZutiloChrome.zoteroOverlay.addTagGUI();
};
keys.shortcuts.relateDialog = function(win) {
    win.ZutiloChrome.zoteroOverlay.updatePaneVisibility('zotero-item', 'show');
    win.ZutiloChrome.zoteroOverlay.addRelatedGUI();
};

/***********************************************/
// Zotero functions (i.e. not Zutilo functions)
// Item manipulation
/***********************************************/
keys.shortcuts.newItemMenu = function(win) {
    win.document.getElementById('zotero-tb-add').firstChild.showPopup();
};
keys.shortcuts.attachLinkFile = function(win) {
    var zitems = win.ZutiloChrome.zoteroOverlay.getSelectedItems('regular');
    var selectionOkay = win.ZutiloChrome.zoteroOverlay.
        checkItemNumber(zitems, 'regularSingle')
    if (!selectionOkay) {
        return false
    }

    win.ZoteroPane.addAttachmentFromDialog(true, zitems[0].id);
};
keys.shortcuts.recognizeSelected = function(win) {
    // jscs: disable requireCamelCaseOrUpperCaseIdentifiers
    win.Zotero_RecognizePDF.recognizeSelected()
    // jscs: enable requireCamelCaseOrUpperCaseIdentifiers
};
keys.shortcuts.createParentItemsFromSelected  = function(win) {
    // jscs: disable requireCamelCaseOrUpperCaseIdentifiers
    win.ZoteroPane_Local.createParentItemsFromSelected()
    // jscs: enable requireCamelCaseOrUpperCaseIdentifiers
};
keys.shortcuts.renameSelectedAttachmentsFromParents  = function(win) {
    // jscs: disable requireCamelCaseOrUpperCaseIdentifiers
    win.ZoteroPane_Local.renameSelectedAttachmentsFromParents()
    // jscs: enable requireCamelCaseOrUpperCaseIdentifiers
};

/***********************************************/
// Zotero functions (i.e. not Zutilo functions)
// Focus selection
/***********************************************/
keys.shortcuts.duplicateItem = function(win) {
    win.ZoteroPane.duplicateSelectedItem();
};

keys.shortcuts.openStyleEditor = function(win) {
var prefs_context = {}
Services.scriptloader.loadSubScript('chrome://zotero/content/include.js', prefs_context)
Services.scriptloader.loadSubScript('chrome://zotero/content/preferences/preferences.js', prefs_context)
prefs_context.Zotero_Preferences.openInViewer('chrome://zotero/content/tools/csledit.xul', true)
}

keys.shortcuts.generateReport = function(win) {
	let context = win.ZoteroPane.document.defaultView
    if (context.document.activeElement.id == "zotero-collections-tree") {
            context.Zotero_Report_Interface.loadCollectionReport()
    } else {
        // "zotero-items-tree" whether it is the active element or not
		let zitems = win.ZoteroPane.getSelectedItems()
		if (zitems.length > 0) {
			context.Zotero_Report_Interface.loadItemReport()
		}
    }
};

keys.shortcuts.focusZoteroCollectionsTree = function(win) {
    win.ZutiloChrome.zoteroOverlay.
        updatePaneVisibility('zotero-collections', 'show');
    win.document.getElementById('zotero-collections-tree').focus();
};
keys.shortcuts.focusZoteroItemsTree = function(win) {
    win.document.getElementById('zotero-items-tree').focus();
};
keys.shortcuts.advanceTabboxTab = function(win) {
    win.ZutiloChrome.zoteroOverlay.updatePaneVisibility('zotero-item', 'show');
    win.document.getElementById('zotero-view-tabbox').
        tabs.advanceSelectedTab(1, true);
};
keys.shortcuts.reverseTabboxTab = function(win) {
    win.ZutiloChrome.zoteroOverlay.updatePaneVisibility('zotero-item', 'show');
    win.document.getElementById('zotero-view-tabbox').
        tabs.advanceSelectedTab(-1, true);
};
keys.shortcuts.selectTabboxTab0 = function(win) {
    win.ZutiloChrome.zoteroOverlay.updatePaneVisibility('zotero-item', 'show');
    win.document.getElementById('zotero-view-tabbox').tabs.selectedIndex = 0;
};
keys.shortcuts.selectTabboxTab1 = function(win) {
    win.ZutiloChrome.zoteroOverlay.updatePaneVisibility('zotero-item', 'show');
    win.document.getElementById('zotero-view-tabbox').tabs.selectedIndex = 1;
};
keys.shortcuts.selectTabboxTab2 = function(win) {
    win.ZutiloChrome.zoteroOverlay.updatePaneVisibility('zotero-item', 'show');
    win.document.getElementById('zotero-view-tabbox').tabs.selectedIndex = 2;
};
keys.shortcuts.selectTabboxTab3 = function(win) {
    win.ZutiloChrome.zoteroOverlay.updatePaneVisibility('zotero-item', 'show');
    win.document.getElementById('zotero-view-tabbox').tabs.selectedIndex = 3;
};

/***********************************************/
// Zotero functions (i.e. not Zutilo functions)
// Hide/show left/right pane
/***********************************************/
keys.shortcuts.toggleZoteroCollectionsPane = function(win) {
    win.ZutiloChrome.zoteroOverlay.updatePaneVisibility('zotero-collections',
                                                        'toggle')
};

keys.shortcuts.toggleZoteroItemPane = function(win) {
    win.ZutiloChrome.zoteroOverlay.updatePaneVisibility('zotero-item', 'toggle')
};

keys.shortcuts.toggleZoteroCollectionsPaneStickySplitter = function(win) {
    win.ZutiloChrome.zoteroOverlay.updatePaneVisibility('zotero-collections',
                                                        'toggle', true)
};

keys.shortcuts.toggleZoteroItemPaneStickySplitter = function(win) {
    win.ZutiloChrome.zoteroOverlay.updatePaneVisibility('zotero-item',
                                                        'toggle', true)
};

/********************************************/
// Firefox only shortcuts
/********************************************/
if (Zutilo.appName == 'Firefox') {

    /********************************************/
    // Zutilo's Firefox scraping functions
    /********************************************/
    keys.shortcuts.attachPage = function(win) {
        win.ZutiloChrome.firefoxOverlay.attachURLToCurrentItem(
            win.content.location.href)
    };

    keys.shortcuts.saveItemZutilo = function(win) {
        win.ZutiloChrome.firefoxOverlay.scrapeThisPage()
    };

    keys.shortcuts.saveItemWithAttachments = function(win) {
        win.ZutiloChrome.firefoxOverlay.scrapeThisPage(false, true)
    };

    keys.shortcuts.saveItemWithoutAttachments = function(win) {
        win.ZutiloChrome.firefoxOverlay.scrapeThisPage(false, false)
    };

    /***********************************************/
    // Zotero functions (i.e. not Zutilo functions)
    /***********************************************/
    keys.shortcuts.toggleZotero = function(win) {
        win.ZoteroOverlay.toggleDisplay()
    };

    keys.shortcuts.focusZotero = function(win) {
        win.ZoteroOverlay.toggleDisplay(true)
    };

    keys.shortcuts.hideZotero = function(win) {
        win.ZoteroOverlay.toggleDisplay(false)
    };

    keys.shortcuts.saveItemZotero = function(win) {
        // jscs: disable requireCamelCaseOrUpperCaseIdentifiers
        win.Zotero_Browser.scrapeThisPage()
        // jscs: enable requireCamelCaseOrUpperCaseIdentifiers
    };

    keys.shortcuts.websiteItem = function(win) {
        win.ZoteroPane.addItemFromPage()
    };

}
<commit_msg>Refactor keys<commit_after>/* Copyright 2012 Will Shanks.
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

'use strict';
/* global gBrowser, window, document, Components, Services */
/* global Zotero, ZoteroPane, Zotero_Browser */
/* global Zutilo, ZutiloChrome, gKeys */

/********************************************/
// Include core modules and built-in modules
/********************************************/
Components.utils.import('resource://gre/modules/AddonManager.jsm');
Components.utils.import('resource://gre/modules/Services.jsm');
Components.utils.import('chrome://zutilo/content/zutilo.jsm');

/********************************************/
// Define keys object
/********************************************/
var keys = {
    getKey: function(keyLabel) {
        return JSON.parse(Zutilo.Prefs.get('shortcut.' + keyLabel))
    },

    setKey: function(keyLabel, key) {
        Zutilo.Prefs.set('shortcut.' + keyLabel, JSON.stringify(key))
    },

    keyName: function(keyLabel) {
        var name = Zutilo._bundle.GetStringFromName('zutilo.shortcuts.name.' +
                                                    keyLabel)
        return name
    },

    keyID: function(keyLabel) {
        return 'zutilo-key-' + keyLabel
    },

    keysEqual: function(key1, key2) {
        var keyEquality =
            (key1.modifiers == key2.modifiers && key1.key == key2.key &&
             key1.keycode == key2.keycode);
        return keyEquality
    },

    getLabels: function() {
        var labels = [];

        for (var shortcut in Zutilo.keys.shortcuts) {
            gKeys.push(shortcut)
        }
    },

    shortcuts: {}
};

/********************************************/
// Define shortcuts
/********************************************/

/********************************************/
// Zutilo's Zotero item menu functions
/********************************************/
keys.shortcuts.copyTags = function(win) {
    win.ZutiloChrome.zoteroOverlay.copyTags()
};
keys.shortcuts.removeTags = function(win) {
    win.ZutiloChrome.zoteroOverlay.removeTags()
};
keys.shortcuts.copyCreators = function(win) {
    win.ZutiloChrome.zoteroOverlay.copyCreators()
};
keys.shortcuts.pasteTags = function(win) {
    win.ZutiloChrome.zoteroOverlay.pasteTags()
};
keys.shortcuts.relateItems = function(win) {
    win.ZutiloChrome.zoteroOverlay.relateItems()
};
keys.shortcuts.showAttachments = function(win) {
    win.ZutiloChrome.zoteroOverlay.showAttachments()
};
keys.shortcuts.modifyAttachments = function(win) {
    win.ZutiloChrome.zoteroOverlay.modifyAttachments()
};
keys.shortcuts.copyItems = function(win) {
    win.ZutiloChrome.zoteroOverlay.copyItems()
};
keys.shortcuts.copyZoteroSelectLink = function(win) {
    win.ZutiloChrome.zoteroOverlay.copyZoteroSelectLink()
};
keys.shortcuts.copyZoteroItemURI = function(win) {
    win.ZutiloChrome.zoteroOverlay.copyZoteroItemURI()
};
keys.shortcuts.createBookItem = function(win) {
    win.ZutiloChrome.zoteroOverlay.createBookItem()
};
keys.shortcuts.createBookSection = function(win) {
    win.ZutiloChrome.zoteroOverlay.createBookSection()
};
keys.shortcuts.copyChildIDs = function(win) {
    win.ZutiloChrome.zoteroOverlay.copyChildIDs()
};
keys.shortcuts.relocateChildren = function(win) {
    win.ZutiloChrome.zoteroOverlay.relocateChildren()
};

/***********************************************/
// Zutilo's Zotero item pane editing functions
/***********************************************/
keys.shortcuts.itemInfo = function(win) {
    win.ZutiloChrome.zoteroOverlay.updatePaneVisibility('zotero-item', 'show');
    win.ZutiloChrome.zoteroOverlay.editItemInfoGUI();
};
keys.shortcuts.addNote = function(win) {
    win.ZutiloChrome.zoteroOverlay.updatePaneVisibility('zotero-item', 'show');
    win.ZutiloChrome.zoteroOverlay.addNoteGUI();
};
keys.shortcuts.addTag = function(win) {
    win.ZutiloChrome.zoteroOverlay.updatePaneVisibility('zotero-item', 'show');
    win.ZutiloChrome.zoteroOverlay.addTagGUI();
};
keys.shortcuts.relateDialog = function(win) {
    win.ZutiloChrome.zoteroOverlay.updatePaneVisibility('zotero-item', 'show');
    win.ZutiloChrome.zoteroOverlay.addRelatedGUI();
};

/***********************************************/
// Zotero functions (i.e. not Zutilo functions)
// Item manipulation
/***********************************************/
keys.shortcuts.newItemMenu = function(win) {
    win.document.getElementById('zotero-tb-add').firstChild.showPopup();
};
keys.shortcuts.attachLinkFile = function(win) {
    var zitems = win.ZutiloChrome.zoteroOverlay.getSelectedItems('regular');
    var selectionOkay = win.ZutiloChrome.zoteroOverlay.
        checkItemNumber(zitems, 'regularSingle')
    if (!selectionOkay) {
        return false
    }

    win.ZoteroPane.addAttachmentFromDialog(true, zitems[0].id);
};
keys.shortcuts.recognizeSelected = function(win) {
    // jscs: disable requireCamelCaseOrUpperCaseIdentifiers
    win.Zotero_RecognizePDF.recognizeSelected()
    // jscs: enable requireCamelCaseOrUpperCaseIdentifiers
};
keys.shortcuts.createParentItemsFromSelected  = function(win) {
    // jscs: disable requireCamelCaseOrUpperCaseIdentifiers
    win.ZoteroPane_Local.createParentItemsFromSelected()
    // jscs: enable requireCamelCaseOrUpperCaseIdentifiers
};
keys.shortcuts.renameSelectedAttachmentsFromParents  = function(win) {
    // jscs: disable requireCamelCaseOrUpperCaseIdentifiers
    win.ZoteroPane_Local.renameSelectedAttachmentsFromParents()
    // jscs: enable requireCamelCaseOrUpperCaseIdentifiers
};

/***********************************************/
// Zotero functions (i.e. not Zutilo functions)
// Focus selection
/***********************************************/
keys.shortcuts.duplicateItem = function(win) {
    win.ZoteroPane.duplicateSelectedItem();
};

keys.shortcuts.openStyleEditor = function(win) {
	var prefs_context = {}
	Services.scriptloader.
		loadSubScript('chrome://zotero/content/include.js', prefs_context)
	Services.scriptloader.
		loadSubScript('chrome://zotero/content/preferences/preferences.js',
					  prefs_context)
	prefs_context.Zotero_Preferences.
		openInViewer('chrome://zotero/content/tools/csledit.xul', true)
}

keys.shortcuts.generateReport = function(win) {
	let context = win.ZoteroPane.document.defaultView
    if (context.document.activeElement.id == "zotero-collections-tree") {
            context.Zotero_Report_Interface.loadCollectionReport()
    } else {
        // "zotero-items-tree" whether it is the active element or not
		let zitems = win.ZoteroPane.getSelectedItems()
		if (zitems.length > 0) {
			context.Zotero_Report_Interface.loadItemReport()
		}
    }
};

keys.shortcuts.focusZoteroCollectionsTree = function(win) {
    win.ZutiloChrome.zoteroOverlay.
        updatePaneVisibility('zotero-collections', 'show');
    win.document.getElementById('zotero-collections-tree').focus();
};
keys.shortcuts.focusZoteroItemsTree = function(win) {
    win.document.getElementById('zotero-items-tree').focus();
};
keys.shortcuts.advanceTabboxTab = function(win) {
    win.ZutiloChrome.zoteroOverlay.updatePaneVisibility('zotero-item', 'show');
    win.document.getElementById('zotero-view-tabbox').
        tabs.advanceSelectedTab(1, true);
};
keys.shortcuts.reverseTabboxTab = function(win) {
    win.ZutiloChrome.zoteroOverlay.updatePaneVisibility('zotero-item', 'show');
    win.document.getElementById('zotero-view-tabbox').
        tabs.advanceSelectedTab(-1, true);
};
keys.shortcuts.selectTabboxTab0 = function(win) {
    win.ZutiloChrome.zoteroOverlay.updatePaneVisibility('zotero-item', 'show');
    win.document.getElementById('zotero-view-tabbox').tabs.selectedIndex = 0;
};
keys.shortcuts.selectTabboxTab1 = function(win) {
    win.ZutiloChrome.zoteroOverlay.updatePaneVisibility('zotero-item', 'show');
    win.document.getElementById('zotero-view-tabbox').tabs.selectedIndex = 1;
};
keys.shortcuts.selectTabboxTab2 = function(win) {
    win.ZutiloChrome.zoteroOverlay.updatePaneVisibility('zotero-item', 'show');
    win.document.getElementById('zotero-view-tabbox').tabs.selectedIndex = 2;
};
keys.shortcuts.selectTabboxTab3 = function(win) {
    win.ZutiloChrome.zoteroOverlay.updatePaneVisibility('zotero-item', 'show');
    win.document.getElementById('zotero-view-tabbox').tabs.selectedIndex = 3;
};

/***********************************************/
// Zotero functions (i.e. not Zutilo functions)
// Hide/show left/right pane
/***********************************************/
keys.shortcuts.toggleZoteroCollectionsPane = function(win) {
    win.ZutiloChrome.zoteroOverlay.updatePaneVisibility('zotero-collections',
                                                        'toggle')
};

keys.shortcuts.toggleZoteroItemPane = function(win) {
    win.ZutiloChrome.zoteroOverlay.updatePaneVisibility('zotero-item', 'toggle')
};

keys.shortcuts.toggleZoteroCollectionsPaneStickySplitter = function(win) {
    win.ZutiloChrome.zoteroOverlay.updatePaneVisibility('zotero-collections',
                                                        'toggle', true)
};

keys.shortcuts.toggleZoteroItemPaneStickySplitter = function(win) {
    win.ZutiloChrome.zoteroOverlay.updatePaneVisibility('zotero-item',
                                                        'toggle', true)
};

/********************************************/
// Firefox only shortcuts
/********************************************/
if (Zutilo.appName == 'Firefox') {

    /********************************************/
    // Zutilo's Firefox scraping functions
    /********************************************/
    keys.shortcuts.attachPage = function(win) {
        win.ZutiloChrome.firefoxOverlay.attachURLToCurrentItem(
            win.content.location.href)
    };

    keys.shortcuts.saveItemZutilo = function(win) {
        win.ZutiloChrome.firefoxOverlay.scrapeThisPage()
    };

    keys.shortcuts.saveItemWithAttachments = function(win) {
        win.ZutiloChrome.firefoxOverlay.scrapeThisPage(false, true)
    };

    keys.shortcuts.saveItemWithoutAttachments = function(win) {
        win.ZutiloChrome.firefoxOverlay.scrapeThisPage(false, false)
    };

    /***********************************************/
    // Zotero functions (i.e. not Zutilo functions)
    /***********************************************/
    keys.shortcuts.toggleZotero = function(win) {
        win.ZoteroOverlay.toggleDisplay()
    };

    keys.shortcuts.focusZotero = function(win) {
        win.ZoteroOverlay.toggleDisplay(true)
    };

    keys.shortcuts.hideZotero = function(win) {
        win.ZoteroOverlay.toggleDisplay(false)
    };

    keys.shortcuts.saveItemZotero = function(win) {
        // jscs: disable requireCamelCaseOrUpperCaseIdentifiers
        win.Zotero_Browser.scrapeThisPage()
        // jscs: enable requireCamelCaseOrUpperCaseIdentifiers
    };

    keys.shortcuts.websiteItem = function(win) {
        win.ZoteroPane.addItemFromPage()
    };

}
<|endoftext|>