<commit_before>import React from 'react'
import elementType from 'react-prop-types/lib/elementType'

import fabricComponent from '../fabricComponent.js'

import style from './Link.scss'

const Link = ({
  children,
  componentClass: Component,
  ...props
}) => (
  <Component data-fabric="Link"
    {...props}
    styleName={'ms-Link'}>
    { children }
  </Component>
)
Link.propTypes = {
  children: React.PropTypes.node,
  componentClass: elementType,
  styles: React.PropTypes.object
}
Link.defaultProps = {
  componentClass: 'a'
}

export default fabricComponent(Link, style)
<commit_msg>fix(Link): remove unused prop from propTypes<commit_after>import React from 'react'
import elementType from 'react-prop-types/lib/elementType'

import fabricComponent from '../fabricComponent.js'

import style from './Link.scss'

const Link = ({
  children,
  componentClass: Component,
  ...props
}) => (
  <Component data-fabric="Link"
    {...props}
    styleName={'ms-Link'}>
    { children }
  </Component>
)
Link.propTypes = {
  children: React.PropTypes.node,
  componentClass: elementType
}
Link.defaultProps = {
  componentClass: 'a'
}

export default fabricComponent(Link, style)
<|endoftext|>


<commit_before>const exec = require('child_process').exec;
const command = "vncsnapshot 192.168.0.3:6 export.jpg";

module.exports = function(message) {
	if (!message.guild) return message.channel.send("You are not in a guild!");
	let moderator = message.guild.members.filter((user)=>{
		return (user.hasPermission(0x00000008) || user.hasPermission(0x00000004) || user.hasPermission(0x00000002)) && user.presence.status === "online" && !user.bot
	}).random().id || message.guild.ownerID;
	message.words.shift();
	message.words.shift();
	let report = message.words.join(" ") || "No report provided :shrug:";

	if(message.guild.id === "110373943822540800" /*&& message.channel.id === "110373943822540800"*/) {
		return message.channel.send(`Report by <@${message.author.id}> to ${moderator}:\n${report}\nAuto Screenshot:`, {
			files: [
				"./export.jpg"
			]
		});
	}

	message.channel.send(`Report by <@${message.author.id}> to ${moderator}:\n${report}`);
}
<commit_msg>never actually added exec<commit_after>const exec = require('child_process').exec;
const command = "vncsnapshot 192.168.0.3:6 screenshot.jpg";

module.exports = function(message) {
	if (!message.guild) return message.channel.send("You are not in a guild!");
	let moderator = message.guild.members.filter((user)=>{
		return (user.hasPermission(0x00000008) || user.hasPermission(0x00000004) || user.hasPermission(0x00000002)) && user.presence.status === "online" && !user.bot
	}).random().id || message.guild.ownerID;
	message.words.shift();
	message.words.shift();
	let report = message.words.join(" ") || "No report provided :shrug:";

	if(message.guild.id === "110373943822540800" /*&& message.channel.id === "110373943822540800"*/) {
		exec(command, function(error, stdout, stderr) {
			return message.channel.send(`Report by <@${message.author.id}> to ${moderator}:\n${report}\nAuto Screenshot:`, {
				files: [
					"./screenshot.jpg"
				]
			});
		});
	}

	message.channel.send(`Report by <@${message.author.id}> to ${moderator}:\n${report}`);
}
<|endoftext|>


<commit_before>'use strict';

const chalk = require('chalk');
const logSymbols = require('log-symbols');

class LintIssue {

  /**
   * constructor
   * @param  {String} lintId      Unique, lowercase, hyphen-separate name for the lint
   * @param  {String} lintType    error or warning
   * @param  {String} node        Name of the node in the JSON the lint audits
   * @param  {String} lintMessage Human-friendly message to users
   */
  constructor(lintId, lintType, node, lintMessage) {
    this.lintId = lintId;
    this.lintType = lintType;
    this.node = node;
    this.lintMessage = lintMessage;
  }

  /**
   * Helper to convert the LintIssue to a printable string
   * @return {String} Human-friendly message about the lint issue
   */
  toString() {
    const logSymbol = this.lintType === 'error' ? logSymbols.error : logSymbols.warning;
    const formattedLintId = chalk.gray.dim(this.lintId);
    const formattedNode = chalk.gray.bold(this.node);
    const formattedMessage = this.lintType === 'error' ? chalk.bold.red(this.lintMessage) : chalk.yellow(this.lintMessage);

    return `${logSymbol} ${formattedLintId} - node: ${formattedNode} - ${formattedMessage}`;
  }

}

module.exports = LintIssue;
<commit_msg>Change lintType to severity<commit_after>'use strict';

const chalk = require('chalk');
const logSymbols = require('log-symbols');

class LintIssue {

  /**
   * constructor
   * @param  {String} lintId      Unique, lowercase, hyphen-separate name for the lint
   * @param  {String} severity    'error' or 'warning'
   * @param  {String} node        Name of the node in the JSON the lint audits
   * @param  {String} lintMessage Human-friendly message to users
   */
  constructor(lintId, severity, node, lintMessage) {
    this.lintId = lintId;
    this.severity = severity;
    this.node = node;
    this.lintMessage = lintMessage;
  }

  /**
   * Helper to convert the LintIssue to a printable string
   * @return {String} Human-friendly message about the lint issue
   */
  toString() {
    const logSymbol = this.severity === 'error' ? logSymbols.error : logSymbols.warning;
    const formattedLintId = chalk.gray.dim(this.lintId);
    const formattedNode = chalk.gray.bold(this.node);
    const formattedMessage = this.severity === 'error' ? chalk.bold.red(this.lintMessage) : chalk.yellow(this.lintMessage);

    return `${logSymbol} ${formattedLintId} - node: ${formattedNode} - ${formattedMessage}`;
  }

}

module.exports = LintIssue;
<|endoftext|>


<commit_before>export default list

import Entry from '../entry'
import {getOutputs} from './output'
import moment from 'moment'
import _ from 'lodash'
import chalk from 'chalk'
import format from '../time'
import db from '../db'

function list (yargs) {
  let argv = yargs
  .usage('Usage: tick list [options]')
  .option('t', {
    alias: 'tag',
    describe: 'tags to filter as boolean AND (no # symbol - e.g. -t tag1 tag2)',
    type: 'array'
  })
  .option('d', {
    alias: 'date',
    describe: 'date range to filter entries',
    type: 'string'
  })
  .help('h')
  .alias('h', 'help')
  .argv

  db.query(mapDate, {
    include_docs: true,
    descending: true
  }).then(_.partial(writeEntries, hashTags(argv.tag)))

}

function hashTags(tags = []) {
  // add a # before the tag if it doesn't already exist
  return tags.map(tag => tag.startsWith('#') ? tag : '#' + tag)
}

function mapDate (doc) {
  emit(doc.fromArr)
}

function writeEntries (tags = [], results) {
  let prevDate = null
  let dat = _.chain(results.rows)
  .filter(_.partial(filterTags, tags))
  .map(row => { return Entry.fromJSON(row.doc) })
  .groupBy(e => { return moment(e.from).startOf('day').format('YYYY-MM-DD') })
  .map((group, d) => {
    return {
      ticks: group,
      date: moment(d, 'YYYY-MM-DD').toDate(),
      minutes: _.reduce(group, (sum, e) => { return sum + e.duration.minutes }, 0)
    }
  })
  .each(group => {
    const date = moment(group.date).format('ddd, MMM DD, YYYY')
    const time = format(group.minutes)
    console.log(`${chalk.yellow(date)} ${chalk.green(time)}`)
    group.ticks.forEach(t => { console.log(getOutputs(t).simple) })
  })
  .value()

  if (dat.length === 0)
    console.log('You have no entries in tickbin. Create some with \'tick log\'')
}

function filterTags (tags = [], row) {
  if (!tags) // no tags provided, filter nothing
    return true

  const rtags = row.doc.tags || []

  const found = _.every(tags, t => _.includes(rtags, t))
  return found
}
<commit_msg>tick list for a date range with a chrono range<commit_after>export default list

import Entry from '../entry'
import {getOutputs} from './output'
import moment from 'moment'
import _ from 'lodash'
import chalk from 'chalk'
import format from '../time'
import chrono from 'chrono-node'
import db from '../db'

function list (yargs) {
  let argv = yargs
  .usage('Usage: tick list [options]')
  .option('t', {
    alias: 'tag',
    describe: 'tags to filter as boolean AND (no # symbol - e.g. -t tag1 tag2)',
    type: 'array'
  })
  .option('d', {
    alias: 'date',
    describe: 'date range to filter entries',
    type: 'string'
  })
  .help('h')
  .alias('h', 'help')
  .argv

  let dates = chrono.parse(argv.date)[0] || [{}]
  // default to most recent 7 days
  let start = moment().subtract(6, 'days').startOf('day').toArray()
  let end   = moment().endOf('day').toArray();
  if (dates.start && dates.end) {
    start = moment(dates.start.date()).startOf('day').toArray()
    end   = moment(dates.end.date()).endOf('day').toArray()
  }

  db.query(mapDate, {
    include_docs: true,
    descending: true,
    startkey: end, // decending, so we start at recent dates
    endkey: start
  }).then(_.partial(writeEntries, hashTags(argv.tag)))

}

function hashTags(tags = []) {
  // add a # before the tag if it doesn't already exist
  return tags.map(tag => tag.startsWith('#') ? tag : '#' + tag)
}

function mapDate (doc) {
  emit(doc.fromArr)
}

function writeEntries (tags = [], results) {
  let prevDate = null
  let dat = _.chain(results.rows)
  .filter(_.partial(filterTags, tags))
  .map(row => { return Entry.fromJSON(row.doc) })
  .groupBy(e => { return moment(e.from).startOf('day').format('YYYY-MM-DD') })
  .map((group, d) => {
    return {
      ticks: group,
      date: moment(d, 'YYYY-MM-DD').toDate(),
      minutes: _.reduce(group, (sum, e) => { return sum + e.duration.minutes }, 0)
    }
  })
  .each(group => {
    const date = moment(group.date).format('ddd, MMM DD, YYYY')
    const time = format(group.minutes)
    console.log(`${chalk.yellow(date)} ${chalk.green(time)}`)
    group.ticks.forEach(t => { console.log(getOutputs(t).simple) })
  })
  .value()

  if (dat.length === 0)
    console.log('You have no entries in tickbin. Create some with \'tick log\'')
}

function filterTags (tags = [], row) {
  if (!tags) // no tags provided, filter nothing
    return true

  const rtags = row.doc.tags || []

  const found = _.every(tags, t => _.includes(rtags, t))
  return found
}
<|endoftext|>


<commit_before>/* eslint global-require: 0, no-console: 0, import/no-unresolved: 0, import/no-extraneous-dependencies: 0, import/no-dynamic-require: 0, max-len: 0 */
const path = require('path');
const utils = require('../commands-utils');
const initConfig = require('../config/webdriver-config');

const webdriver = {
  command: 'webdriver <config>',
  desc: 'Run webdriver',
  builder(yargs) {
    return yargs
      .usage('webdriver <config>')
      .config(utils.config.webdriver)
      .option('glob', {
        description: 'Glob pattern',
        type: 'string',
        default: [],
      })
      .option('coverage', {
        description: 'Generate coverage',
        type: 'boolean',
        default: false,
      })
      .option('artifactsPath', {
        description: 'Path to artifacts',
        type: 'string',
        default: 'test/component/artifacts',
      })
      .argv;
  },
  handler(argv) {
    let launcher;
    try {
      launcher = require('protractor/built/launcher');
    } catch (_) {
      console.log('Could not load protractor/built/launcher');
      const p = `${path.resolve(process.cwd())}/node_modules/protractor/built/launcher`;
      console.log(`Trying: ${p}`);
      try {
        launcher = require(p);
      } catch (__) {
        console.log('Protractor could not be found by after-work.js! Please verify that it has been added as a devDependencies in your package.json');
        process.exit(0);
      }
    }
    const config = utils.getConfig('webdriver', argv.config, initConfig(argv.artifactsPath));
    const files = utils.getFiles(argv.glob);
    if (!files.length) {
      console.log('No files found for:', argv.glob);
      process.exit(0);
    }
    config.specs = [files[0]];
    launcher.init('', config);
  },
};

module.exports = webdriver;
<commit_msg>Use all `files` found in webdriver command<commit_after>/* eslint global-require: 0, no-console: 0, import/no-unresolved: 0, import/no-extraneous-dependencies: 0, import/no-dynamic-require: 0, max-len: 0 */
const path = require('path');
const utils = require('../commands-utils');
const initConfig = require('../config/webdriver-config');

const webdriver = {
  command: 'webdriver <config>',
  desc: 'Run webdriver',
  builder(yargs) {
    return yargs
      .usage('webdriver <config>')
      .config(utils.config.webdriver)
      .option('glob', {
        description: 'Glob pattern',
        type: 'string',
        default: [],
      })
      .option('coverage', {
        description: 'Generate coverage',
        type: 'boolean',
        default: false,
      })
      .option('artifactsPath', {
        description: 'Path to artifacts',
        type: 'string',
        default: 'test/component/artifacts',
      })
      .argv;
  },
  handler(argv) {
    let launcher;
    try {
      launcher = require('protractor/built/launcher');
    } catch (_) {
      console.log('Could not load protractor/built/launcher');
      const p = `${path.resolve(process.cwd())}/node_modules/protractor/built/launcher`;
      console.log(`Trying: ${p}`);
      try {
        launcher = require(p);
      } catch (__) {
        console.log('Protractor could not be found by after-work.js! Please verify that it has been added as a devDependencies in your package.json');
        process.exit(0);
      }
    }
    const config = utils.getConfig('webdriver', argv.config, initConfig(argv.artifactsPath));
    const files = utils.getFiles(argv.glob);
    if (!files.length) {
      console.log('No files found for:', argv.glob);
      process.exit(0);
    }
    config.specs = files;
    launcher.init('', config);
  },
};

module.exports = webdriver;
<|endoftext|>


<commit_before>var locastyle = locastyle || {};

locastyle.popover = (function() {
  'use strict';

  var config = {
    module       : '[data-ls-module="popover"]',
    idPopover    : '#ls-popover-',
    popoverClass : '.ls-popover',
    trigger      : 'click',
    events: {
      clickAnywhere: 'click.clickanywhere',
      opened: 'popover:opened',
      closed: 'popover:closed',
      destroyed: 'popover:destroyed'
    }
  }

  function init() {
    clickAnywhereClose();
    buildPopover();
    bindPopover();
    startOpened();
  }

  // When click or hover elements, show the popovers
  function bindPopover() {
    $(config.module).each(function(index, popoverTrigger) {
      var trigger = $(popoverTrigger).attr('data-trigger') === 'hover' ? 'mouseover' : config.trigger;

      $(popoverTrigger).on(trigger, function(event) {
        event.preventDefault();
        event.stopPropagation();

        var popoverTarget = $(popoverTrigger).data('target');

        if ($(popoverTarget).hasClass('ls-active')) {
          hide(popoverTarget);
        } else {
          show(popoverTarget);
          clickAnywhereClose(popoverTarget)
        }

        if (trigger === 'mouseover') {
          $(popoverTrigger).on('mouseout', function() {
            hide(popoverTarget);
          });
        }

      });
    });

  }

  function clickAnywhereClose(target) {
    $(document).on(config.events.clickAnywhere, function(event){
      if(!$(event.target).parents('.ls-popover').length){
        hide(target);
      }
    });
  }

  // When open page, start popover automatically
  function startOpened() {
    $(config.module+'[data-ls-popover="open"]').each(function() {
      show($(this).data('target'));
    });
  }

  // If popover was not created, we build the HTML using a template
  function buildPopover() {
    $(config.module).each(function(index, popoverTrigger) {

      // Add attr data-target to popover triggers
      $(popoverTrigger).attr('data-target', config.idPopover+index);

      if (!$(config.idPopover+index).length) {
        var data = {
          index        : index,
          title        : $(popoverTrigger).data('title'),
          content      : $(popoverTrigger).data('content'),
          placement    : $(popoverTrigger).data('placement'),
          customClasses: $(popoverTrigger).data('custom-class')
        }

        $('body').append(locastyle.templates.popover(data));

        // Define position of popovers based on his triggers
        setPosition(popoverTrigger);
      }
    });
  }

  // Define position of popovers
  function setPosition(popoverTrigger) {
    var data = {
        target    : $(popoverTrigger).data('target'),
        top       : $(popoverTrigger).offset().top,
        left      : $(popoverTrigger).offset().left,
        width     : $(popoverTrigger).outerWidth(),
        height    : $(popoverTrigger).outerHeight(),
        placement : $(popoverTrigger).data('placement')
    }

    // Define the position of popovers and your elements triggers
    switch (data.placement) {
      case 'top':
        $(data.target).css({
          top : data.top  -=  12,
          left: data.left += (data.width/2 + 4)
        });
        break;
      case 'right':
        $(data.target).css({
          top : data.top  += (data.height/2 -2),
          left: data.left += (data.width + 12)
        });
        break;
      case 'bottom':
        $(data.target).css({
          top : data.top  += (data.height + 12),
          left: data.left += (data.width/2 + 4)
        });
        break;
      case 'left':
        $(data.target).css({
          top : data.top  += (data.height/2 -2 ),
          left: data.left -= 12
        });
    }

  }

  // Show called popover
  function show(target) {
    $(target).addClass('ls-active');
    $(target).off(config.events.closed).trigger(config.events.opened);
  }

  // Hide all or visible popovers
  function hide(target) {
    $(target || '.ls-popover.ls-active').removeClass('ls-active');
    $(target).trigger(config.events.closed).off(config.events.opened)
    $(document).off(config.events.clickAnywhere)
  }

  // Destroy all created popovers
  function destroy() {
    $(config.popoverClass).remove();

    // Unbind all events.
    $.each(config.events, function(index, event) {
      $(document).unbind(event);
    });

    $(document).trigger(config.events.destroyed);
  }

  return {
    init   : init,
    show   : show,
    hide   : hide,
    destroy: destroy
  };

}());
<commit_msg>fixing bug commented by @flaviomuniz on #issuecomment-127232773<commit_after>var locastyle = locastyle || {};

locastyle.popover = (function() {
  'use strict';

  var config = {
    module       : '[data-ls-module="popover"]',
    idPopover    : '#ls-popover-',
    popoverClass : '.ls-popover',
    trigger      : 'click',
    events: {
      clickAnywhere: 'click.clickanywhere',
      opened: 'popover:opened',
      closed: 'popover:closed',
      destroyed: 'popover:destroyed'
    }
  }

  function init() {
    clickAnywhereClose();
    buildPopover();
    bindPopover();
    startOpened();
  }

  // When click or hover elements, show the popovers
  function bindPopover() {
    $(config.module).each(function(index, popoverTrigger) {
      var trigger = $(popoverTrigger).attr('data-trigger') === 'hover' ? 'mouseover' : config.trigger;

      $(popoverTrigger).on(trigger, function(event) {
        event.preventDefault();
        event.stopPropagation();

        var popoverTarget = $(popoverTrigger).data('target');

        if ($(popoverTarget).hasClass('ls-active')) {
          hide(popoverTarget);
        } else {
          show(popoverTarget);
          clickAnywhereClose(popoverTarget)
        }

        if (trigger === 'mouseover') {
          $(popoverTrigger).on('mouseout', function() {
            hide(popoverTarget);
          });
        }

      });
    });

  }

  function clickAnywhereClose(target) {
    $(document).on(config.events.clickAnywhere, function(event){
      if(!$(event.target).parents('.ls-popover').length){
        hide(target);
      }
      console.log('yeah')
    });
  }

  // When open page, start popover automatically
  function startOpened() {
    $(config.module+'[data-ls-popover="open"]').each(function() {
      show($(this).data('target'));
    });
  }

  // If popover was not created, we build the HTML using a template
  function buildPopover() {
    $(config.module).each(function(index, popoverTrigger) {

      // Add attr data-target to popover triggers
      $(popoverTrigger).attr('data-target', config.idPopover+index);

      if (!$(config.idPopover+index).length) {
        var data = {
          index        : index,
          title        : $(popoverTrigger).data('title'),
          content      : $(popoverTrigger).data('content'),
          placement    : $(popoverTrigger).data('placement'),
          customClasses: $(popoverTrigger).data('custom-class')
        }

        $('body').append(locastyle.templates.popover(data));

        // Define position of popovers based on his triggers
        setPosition(popoverTrigger);
      }
    });
  }

  // Define position of popovers
  function setPosition(popoverTrigger) {
    var data = {
        target    : $(popoverTrigger).data('target'),
        top       : $(popoverTrigger).offset().top,
        left      : $(popoverTrigger).offset().left,
        width     : $(popoverTrigger).outerWidth(),
        height    : $(popoverTrigger).outerHeight(),
        placement : $(popoverTrigger).data('placement')
    }

    // Define the position of popovers and your elements triggers
    switch (data.placement) {
      case 'top':
        $(data.target).css({
          top : data.top  -=  12,
          left: data.left += (data.width/2 + 4)
        });
        break;
      case 'right':
        $(data.target).css({
          top : data.top  += (data.height/2 -2),
          left: data.left += (data.width + 12)
        });
        break;
      case 'bottom':
        $(data.target).css({
          top : data.top  += (data.height + 12),
          left: data.left += (data.width/2 + 4)
        });
        break;
      case 'left':
        $(data.target).css({
          top : data.top  += (data.height/2 -2 ),
          left: data.left -= 12
        });
    }

  }

  // Show called popover
  function show(target) {
    $(target).addClass('ls-active');
    $(target).off(config.events.closed).trigger(config.events.opened);
  }

  // Hide all or visible popovers
  function hide(target) {
    $(target || '.ls-popover.ls-active').removeClass('ls-active');
    $(target).trigger(config.events.closed).off(config.events.opened)

    if(!$('.ls-popover.ls-active').length) {
      $(document).off(config.events.clickAnywhere)
    }

  }

  // Destroy all created popovers
  function destroy() {
    $(config.popoverClass).remove();

    // Unbind all events.
    $.each(config.events, function(index, event) {
      $(document).unbind(event);
    });

    $(document).trigger(config.events.destroyed);
  }

  return {
    init   : init,
    show   : show,
    hide   : hide,
    destroy: destroy
  };

}());
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';

import AVAILABLE_CONFIGS from 'Parser/AVAILABLE_CONFIGS';

import PatreonLink from './PatreonLink';
import Changelog from './Changelog';

import MasteryRadiusImage from './Images/mastery-radius.png';
import ItemsImage from './Images/items.png';
import SuggestionsImage from './Images/suggestions.png';
import ImportantMetricsImage from './Images/important-metrics.png';
import CooldownUsagesImage from './Images/cooldownusages.png';
import ManaBreakdownImage from './Images/mana-breakdown.png';
import OpenSourceImage from './Images/open-source.png';
import OkHandImage from './Images/ok_hand.png';

class Home extends Component {
  render() {
    return (

The World of Warcraft Analyzer

                Use this tool to analyze your performance based on important metrics for the spec.

                You will need a Warcraft Logs report with advanced combat logging enabled to start. Private logs can not be used, if your guild has private logs you will have to
                {' '}upload your own logs or change the existing logs to the
                {' '}unlisted privacy option instead.

                Feature requests (<dfn data-tip="Provided that you're not using one of Microsoft's browsers.">and bug reports*</dfn>) are welcome!{' '}
                @Zerotorescue on Discord or create an issue{' '}
                <a href={`https://github.com/MartijnHols/WoWAnalyzer/issues`}>here.

About

                Full source is available on GitHub. Contributions are extremely welcome! Add your own module or spec if you want to be able to analyze something not yet available. The repository contains information on how to contribute, if you need any more information please join our Discord (link further below).

                The following specs are available:

                  {AVAILABLE_CONFIGS.map((config) => (

{config.spec.specName} {config.spec.className} maintained by {config.maintainer}

                  ))}

                There are no plans at this time to add support for other specs. The best way to get support for a spec is to add it yourself. Adding specs is easy if you're familiar with JavaScript (ES6), see GitHub and the WoW Analyzer Discord for more information.

                If you're looking to help out development in other ways, please consider donating.

                <PatreonLink />

Discord

                I believe it's important to keep class discussion as much in class Discords as possible, so if you have spec specific questions and/or suggestions please try to discuss them in your class Discord (class Discords mods approve of this message ). The WoW Analyzer Discord is for more general questions and developers looking to contribute.

Features

                    Item performance breakdowns

                    Suggestions for improvement

                    Important spec specific metrics

                    Cooldown usage details

                    Mana breakdown

                    Open source

Changes

                <Changelog />

    );
  }
}

export default Home;
<commit_msg>Fix warning<commit_after>import React, { Component } from 'react';

import AVAILABLE_CONFIGS from 'Parser/AVAILABLE_CONFIGS';

import PatreonLink from './PatreonLink';
import Changelog from './Changelog';

import MasteryRadiusImage from './Images/mastery-radius.png';
import ItemsImage from './Images/items.png';
import SuggestionsImage from './Images/suggestions.png';
import ImportantMetricsImage from './Images/important-metrics.png';
import CooldownUsagesImage from './Images/cooldownusages.png';
import ManaBreakdownImage from './Images/mana-breakdown.png';
import OpenSourceImage from './Images/open-source.png';
import OkHandImage from './Images/ok_hand.png';

class Home extends Component {
  render() {
    return (

The World of Warcraft Analyzer

                Use this tool to analyze your performance based on important metrics for the spec.

                You will need a Warcraft Logs report with advanced combat logging enabled to start. Private logs can not be used, if your guild has private logs you will have to
                {' '}upload your own logs or change the existing logs to the
                {' '}unlisted privacy option instead.

                Feature requests (<dfn data-tip="Provided that you're not using one of Microsoft's browsers.">and bug reports*</dfn>) are welcome!{' '}
                @Zerotorescue on Discord or create an issue{' '}
                <a href={`https://github.com/MartijnHols/WoWAnalyzer/issues`}>here.

About

                Full source is available on GitHub. Contributions are extremely welcome! Add your own module or spec if you want to be able to analyze something not yet available. The repository contains information on how to contribute, if you need any more information please join our Discord (link further below).

                The following specs are available:

                  {AVAILABLE_CONFIGS.map((config) => (

{config.spec.specName} {config.spec.className} maintained by {config.maintainer}

                  ))}

                There are no plans at this time to add support for other specs. The best way to get support for a spec is to add it yourself. Adding specs is easy if you're familiar with JavaScript (ES6), see GitHub and the WoW Analyzer Discord for more information.

                If you're looking to help out development in other ways, please consider donating.

                <PatreonLink />

Discord

                I believe it's important to keep class discussion as much in class Discords as possible, so if you have spec specific questions and/or suggestions please try to discuss them in your class Discord (class Discords mods approve of this message ). The WoW Analyzer Discord is for more general questions and developers looking to contribute.

Features

                    Item performance breakdowns

                    Suggestions for improvement

                    Important spec specific metrics

                    Cooldown usage details

                    Mana breakdown

                    Open source

Changes

                <Changelog />

    );
  }
}

export default Home;
<|endoftext|>


<commit_before>/*
 * This creates a console object that somewhat replicates Firebug's console
 * object. It currently writes to dump(), but should write to the web
 * console's chrome error section (when it has one)
 */

/**
 * This is extra to the console object. It allows us to use the Node constants
 * without resorting to hardcoded numbers
 */
var Node = Components.interfaces.nsIDOMNode;

/**
 * The console object to expose
 */
var console = {};

(function() {
  /**
   * String utility to ensure that strings are a specified length. Strings
   * that are too long are truncated to the max length and the last char is
   * set to "_". Strings that are too short are left padded with spaces.
   *
   * @param {string} aStr
   *        The string to format to the correct length
   * @param {number} aMaxLen
   *        The maximum allowed length of the returned string
   * @param {number} aMinLen (optional)
   *        The minimum allowed length of the returned string. If undefined,
   *        then aMaxLen will be used
   * @param {object} aOptions (optional)
   *        An object allowing format customization. The only customization
   *        allowed currently is 'truncate' which can take the value "start" to
   *        truncate strings from the start as opposed to the end.
   * @return {string}
   *        The original string formatted to fit the specified lengths
   */
  function fmt(aStr, aMaxLen, aMinLen, aOptions) {
    if (aMinLen == undefined) {
      aMinLen = aMaxLen;
    }
    if (aStr == null) {
      aStr = "";
    }
    if (aStr.length > aMaxLen) {
      if (aOptions && aOptions.truncate == "start") {
        return "_" + aStr.substring(aStr.length - aMaxLen + 1);
      }
      else {
        return aStr.substring(0, aMaxLen - 1) + "_";
      }
    }
    if (aStr.length < aMinLen) {
      return Array(aMinLen - aStr.length + 1).join(" ") + aStr;
    }
    return aStr;
  }

  /**
   * Utility to extract the constructor name of an object.
   * Object.toString gives: "[object ?????]"; we want the "?????".
   *
   * @param {object} aObj
   *        The object from which to extract the constructor name
   * @return {string}
   *        The constructor name
   */
  function getCtorName(aObj) {
    return Object.prototype.toString.call(aObj).slice(8, -1);
  }

  /**
   * A single line stringification of an object designed for use by humans
   *
   * @param {any} aThing
   *        The object to be stringified
   * @return {string}
   *        A single line representation of aThing, which will generally be at
   *        most 60 chars long
   */
  function stringify(aThing) {
    if (aThing === undefined) {
      return "undefined";
    }

    if (aThing === null) {
      return "null";
    }

    if (typeof aThing == "object") {
      var type = getCtorName(aThing);
      if (type == "XULElement") {
        return debugElement(aThing);
      }
      type = (type == "Object" ? "" : type + " ");
      var json;
      try {
        json = JSON.stringify(aThing);
      }
      catch (ex) {
        // Can't use a real ellipsis here, because cmd.exe isn't unicode-enabled
        json = "{" + Object.keys(aThing).join(":..,") + ":.., " + "}";
      }
      return type + fmt(json, 50, 0);
    }

    var str = aThing.toString().replace(/\s+/g, " ");
    return fmt(str, 60, 0);
  }

  /**
   * Create a simple debug representation of a given element.
   *
   * @param {nsIDOMElement} aElement
   *        The element to debug
   * @return {string}
   *        A simple single line representation of aElement
   */
  function debugElement(aElement) {
    return "<" + aElement.tagName +
        (aElement.id ? "#" + aElement.id : "") +
        (aElement.className ?
            "." + aElement.className.split(" ").join(" .") :
            "") +
        ">";
  }

  /**
   * A multi line stringification of an object, designed for use by humans
   *
   * @param {any} aThing
   *        The object to be stringified
   * @return {string}
   *        A multi line representation of aThing
   */
  function log(aThing) {
    if (aThing == null) {
      return "null\n";
    }

    if (aThing == undefined) {
      return "undefined\n";
    }

    if (typeof aThing == "object") {
      var reply = "";
      var type = getCtorName(aThing);
      if (type == "Error") {
        reply += "  " + aThing.message + "\n";
        reply += logProperty("stack", aThing.stack);
      }
      else if (type == "XULElement") {
        reply += "  " + debugElement(aThing) + " (XUL)\n";
      }
      else {
        var keys = Object.getOwnPropertyNames(aThing);
        if (keys.length > 0) {
          reply += type + "\n";
          keys.forEach(function(aProp) {
            reply += logProperty(aProp, aThing[aProp]);
          }, this);
        }
        else {
          reply += type + " (enumerated with for-in)\n";
          var prop;
          for (prop in aThing) {
            reply += logProperty(prop, aThing[prop]);
          }
        }
      }

      return reply;
    }

    return "  " + aThing.toString() + "\n";
  }

  /**
   * Helper for log() which converts a property/value pair into an output
   * string
   *
   * @param {string} aProp
   *        The name of the property to include in the output string
   * @param {object} aValue
   *        Value assigned to aProp to be converted to a single line string
   * @return {string}
   *        Multi line output string describing the property/value pair
   */
  function logProperty(aProp, aValue) {
    var reply = "";
    if (aProp == "stack" && typeof value == "string") {
      var trace = parseStack(aValue);
      reply += formatTrace(trace);
    }
    else {
      reply += "    - " + aProp + " = " + stringify(aValue) + "\n";
    }
    return reply;
  }

  /**
   * Parse a stack trace, returning an array of stack frame objects, where
   * each has file/line/call members
   *
   * @param {string} aStack
   *        The serialized stack trace
   * @return {object[]}
   *        Array of { file: "...", line: NNN, call: "..." } objects
   */
  function parseStack(aStack) {
    var trace = [];
    aStack.split("\n").forEach(function(line) {
      if (!line) {
        return;
      }
      var at = line.lastIndexOf("@");
      var posn = line.substring(at + 1);
      trace.push({
        file: posn.split(":")[0],
        line: posn.split(":")[1],
        call: line.substring(0, at)
      });
    }, this);
    return trace;
  }

  /**
   * parseStack() takes output from an exception from which it creates the an
   * array of stack frame objects, this has the same output but using data from
   * Components.stack
   *
   * @param {string} aFrame
   *        The stack frame from which to begin the walk
   * @return {object[]}
   *        Array of { file: "...", line: NNN, call: "..." } objects
   */
  function getStack(aFrame) {
    if (!aFrame) {
      aFrame = Components.stack.caller;
    }
    var trace = [];
    while (aFrame) {
      trace.push({
        file: aFrame.filename,
        line: aFrame.lineNumber,
        call: aFrame.name
      });
      aFrame = aFrame.caller;
    }
    return trace;
  }

  /**
   * Take the output from parseStack() and convert it to nice readable
   * output
   *
   * @param {object[]} aTrace
   *        Array of trace objects as created by parseStack()
   * @return {string} Multi line report of the stack trace
   */
  function formatTrace(aTrace) {
    var reply = "";
    aTrace.forEach(function(frame) {
      reply += fmt(frame.file, 20, 20, { truncate: "start" }) + " " +
               fmt(frame.line, 5, 5) + " " +
               fmt(frame.call, 75, 75) + "\n";
    });
    return reply;
  }

  /**
   * Create a function which will output a concise level of output when used
   * as a logging function
   *
   * @param {string} aLevel
   *        A prefix to all output generated from this function detailing the
   *        level at which output occurred
   * @return {function}
   *        A logging function
   * @see createMultiLineDumper()
   */
  function createDumper(aLevel) {
    return function() {
      var args = Array.prototype.slice.call(arguments, 0);
      var data = args.map(function(arg) {
        return stringify(arg);
      });
      dump(aLevel + ": " + data.join(", ") + "\n");
    };
  }

  /**
   * Create a function which will output more detailed level of output when
   * used as a logging function
   *
   * @param {string} aLevel
   *        A prefix to all output generated from this function detailing the
   *        level at which output occurred
   * @return {function}
   *        A logging function
   * @see createDumper()
   */
  function createMultiLineDumper(aLevel) {
    return function() {
      dump(aLevel + "\n");
      var args = Array.prototype.slice.call(arguments, 0);
      args.forEach(function(arg) {
        dump(log(arg));
      });
    };
  }

  /**
   * Build out the console object
   */
  console.debug = createMultiLineDumper("debug");
  console.log = createDumper("log");
  console.info = createDumper("info");
  console.warn = createDumper("warn");
  console.error = createMultiLineDumper("error");
  console.trace = function Console_trace() {
    var trace = getStack(Components.stack.caller);
    dump(formatTrace(trace) + "\n");
  },
  console.clear = function Console_clear() {};

  console.dir = createMultiLineDumper("dir");
  console.dirxml = createMultiLineDumper("dirxml");
  console.group = createDumper("group");
  console.groupEnd = createDumper("groupEnd");

})();
<commit_msg>Bug 683508 (inspect): Create a setTimeout function in the context console.js is becoming a bad name, it's really about easing over the diffs between content and chrome<commit_after>/*
 * This creates a console object that somewhat replicates Firebug's console
 * object. It currently writes to dump(), but should write to the web
 * console's chrome error section (when it has one)
 */

/**
 * This is extra to the console object. It allows us to use the Node constants
 * without resorting to hardcoded numbers
 */
var Node = Components.interfaces.nsIDOMNode;

Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");

/**
 * Define setTimeout and clearTimeout to match the browser functions
 */
var setTimeout;
var clearTimeout;

(function() {
  /**
   * The next value to be returned by setTimeout
   */
  var nextID = 1;

  /**
   * The map of outstanding timeouts
   */
  var timers = {};

  /**
   * Object to be passed to Timer.initWithCallback()
   */
  function TimerCallback(callback) {
    this._callback = callback;
    var interfaces = [ Components.interfaces.nsITimerCallback ];
    this.QueryInterface = XPCOMUtils.generateQI(interfaces);
  }

  TimerCallback.prototype.notify = function(timer) {
    try {
      for (var timerID in timers) {
        if (timers[timerID] === timer) {
          delete timers[timerID];
          break;
        }
      }
      this._callback.apply(null, []);
    }
    catch (ex) {
      console.error(ex);
    }
  };

  /**
   * Executes a code snippet or a function after specified delay.
   * This is designed to have the same interface contract as the browser
   * function.
   * @param callback is the function you want to execute after the delay.
   * @param delay is the number of milliseconds that the function call should
   * be delayed by. Note that the actual delay may be longer, see Notes below.
   * @return the ID of the timeout, which can be used later with
   * window.clearTimeout.
   */
  setTimeout = function setTimeout(callback, delay) {
    var timer = Components.classes["@mozilla.org/timer;1"]
                          .createInstance(Components.interfaces.nsITimer);

    var timerID = nextID++;
    timers[timerID] = timer;

    timer.initWithCallback(new TimerCallback(callback), delay, timer.TYPE_ONE_SHOT);
    return timerID;
  };

  /**
   * Clears the delay set by window.setTimeout() and prevents the callback from
   * being executed (if it hasn't been executed already)
   * @param timerID the ID of the timeout you wish to clear, as returned by
   * window.setTimeout().
   */
  clearTimeout = function clearTimeout(timerID) {
    var timer = timers[timerID];
    if (timer) {
      timer.cancel();
      delete timers[timerID];
    }
  };
})();

/**
 * The console object to expose
 */
var console = {};

(function() {
  /**
   * String utility to ensure that strings are a specified length. Strings
   * that are too long are truncated to the max length and the last char is
   * set to "_". Strings that are too short are left padded with spaces.
   *
   * @param {string} aStr
   *        The string to format to the correct length
   * @param {number} aMaxLen
   *        The maximum allowed length of the returned string
   * @param {number} aMinLen (optional)
   *        The minimum allowed length of the returned string. If undefined,
   *        then aMaxLen will be used
   * @param {object} aOptions (optional)
   *        An object allowing format customization. The only customization
   *        allowed currently is 'truncate' which can take the value "start" to
   *        truncate strings from the start as opposed to the end.
   * @return {string}
   *        The original string formatted to fit the specified lengths
   */
  function fmt(aStr, aMaxLen, aMinLen, aOptions) {
    if (aMinLen == undefined) {
      aMinLen = aMaxLen;
    }
    if (aStr == null) {
      aStr = "";
    }
    if (aStr.length > aMaxLen) {
      if (aOptions && aOptions.truncate == "start") {
        return "_" + aStr.substring(aStr.length - aMaxLen + 1);
      }
      else {
        return aStr.substring(0, aMaxLen - 1) + "_";
      }
    }
    if (aStr.length < aMinLen) {
      return Array(aMinLen - aStr.length + 1).join(" ") + aStr;
    }
    return aStr;
  }

  /**
   * Utility to extract the constructor name of an object.
   * Object.toString gives: "[object ?????]"; we want the "?????".
   *
   * @param {object} aObj
   *        The object from which to extract the constructor name
   * @return {string}
   *        The constructor name
   */
  function getCtorName(aObj) {
    return Object.prototype.toString.call(aObj).slice(8, -1);
  }

  /**
   * A single line stringification of an object designed for use by humans
   *
   * @param {any} aThing
   *        The object to be stringified
   * @return {string}
   *        A single line representation of aThing, which will generally be at
   *        most 60 chars long
   */
  function stringify(aThing) {
    if (aThing === undefined) {
      return "undefined";
    }

    if (aThing === null) {
      return "null";
    }

    if (typeof aThing == "object") {
      var type = getCtorName(aThing);
      if (type == "XULElement") {
        return debugElement(aThing);
      }
      type = (type == "Object" ? "" : type + " ");
      var json;
      try {
        json = JSON.stringify(aThing);
      }
      catch (ex) {
        // Can't use a real ellipsis here, because cmd.exe isn't unicode-enabled
        json = "{" + Object.keys(aThing).join(":..,") + ":.., " + "}";
      }
      return type + fmt(json, 50, 0);
    }

    var str = aThing.toString().replace(/\s+/g, " ");
    return fmt(str, 60, 0);
  }

  /**
   * Create a simple debug representation of a given element.
   *
   * @param {nsIDOMElement} aElement
   *        The element to debug
   * @return {string}
   *        A simple single line representation of aElement
   */
  function debugElement(aElement) {
    return "<" + aElement.tagName +
        (aElement.id ? "#" + aElement.id : "") +
        (aElement.className ?
            "." + aElement.className.split(" ").join(" .") :
            "") +
        ">";
  }

  /**
   * A multi line stringification of an object, designed for use by humans
   *
   * @param {any} aThing
   *        The object to be stringified
   * @return {string}
   *        A multi line representation of aThing
   */
  function log(aThing) {
    if (aThing == null) {
      return "null\n";
    }

    if (aThing == undefined) {
      return "undefined\n";
    }

    if (typeof aThing == "object") {
      var reply = "";
      var type = getCtorName(aThing);
      if (type == "Error") {
        reply += "  " + aThing.message + "\n";
        reply += logProperty("stack", aThing.stack);
      }
      else if (type == "XULElement") {
        reply += "  " + debugElement(aThing) + " (XUL)\n";
      }
      else {
        var keys = Object.getOwnPropertyNames(aThing);
        if (keys.length > 0) {
          reply += type + "\n";
          keys.forEach(function(aProp) {
            reply += logProperty(aProp, aThing[aProp]);
          }, this);
        }
        else {
          reply += type + " (enumerated with for-in)\n";
          var prop;
          for (prop in aThing) {
            reply += logProperty(prop, aThing[prop]);
          }
        }
      }

      return reply;
    }

    return "  " + aThing.toString() + "\n";
  }

  /**
   * Helper for log() which converts a property/value pair into an output
   * string
   *
   * @param {string} aProp
   *        The name of the property to include in the output string
   * @param {object} aValue
   *        Value assigned to aProp to be converted to a single line string
   * @return {string}
   *        Multi line output string describing the property/value pair
   */
  function logProperty(aProp, aValue) {
    var reply = "";
    if (aProp == "stack" && typeof value == "string") {
      var trace = parseStack(aValue);
      reply += formatTrace(trace);
    }
    else {
      reply += "    - " + aProp + " = " + stringify(aValue) + "\n";
    }
    return reply;
  }

  /**
   * Parse a stack trace, returning an array of stack frame objects, where
   * each has file/line/call members
   *
   * @param {string} aStack
   *        The serialized stack trace
   * @return {object[]}
   *        Array of { file: "...", line: NNN, call: "..." } objects
   */
  function parseStack(aStack) {
    var trace = [];
    aStack.split("\n").forEach(function(line) {
      if (!line) {
        return;
      }
      var at = line.lastIndexOf("@");
      var posn = line.substring(at + 1);
      trace.push({
        file: posn.split(":")[0],
        line: posn.split(":")[1],
        call: line.substring(0, at)
      });
    }, this);
    return trace;
  }

  /**
   * parseStack() takes output from an exception from which it creates the an
   * array of stack frame objects, this has the same output but using data from
   * Components.stack
   *
   * @param {string} aFrame
   *        The stack frame from which to begin the walk
   * @return {object[]}
   *        Array of { file: "...", line: NNN, call: "..." } objects
   */
  function getStack(aFrame) {
    if (!aFrame) {
      aFrame = Components.stack.caller;
    }
    var trace = [];
    while (aFrame) {
      trace.push({
        file: aFrame.filename,
        line: aFrame.lineNumber,
        call: aFrame.name
      });
      aFrame = aFrame.caller;
    }
    return trace;
  }

  /**
   * Take the output from parseStack() and convert it to nice readable
   * output
   *
   * @param {object[]} aTrace
   *        Array of trace objects as created by parseStack()
   * @return {string} Multi line report of the stack trace
   */
  function formatTrace(aTrace) {
    var reply = "";
    aTrace.forEach(function(frame) {
      reply += fmt(frame.file, 20, 20, { truncate: "start" }) + " " +
               fmt(frame.line, 5, 5) + " " +
               fmt(frame.call, 75, 75) + "\n";
    });
    return reply;
  }

  /**
   * Create a function which will output a concise level of output when used
   * as a logging function
   *
   * @param {string} aLevel
   *        A prefix to all output generated from this function detailing the
   *        level at which output occurred
   * @return {function}
   *        A logging function
   * @see createMultiLineDumper()
   */
  function createDumper(aLevel) {
    return function() {
      var args = Array.prototype.slice.call(arguments, 0);
      var data = args.map(function(arg) {
        return stringify(arg);
      });
      dump(aLevel + ": " + data.join(", ") + "\n");
    };
  }

  /**
   * Create a function which will output more detailed level of output when
   * used as a logging function
   *
   * @param {string} aLevel
   *        A prefix to all output generated from this function detailing the
   *        level at which output occurred
   * @return {function}
   *        A logging function
   * @see createDumper()
   */
  function createMultiLineDumper(aLevel) {
    return function() {
      dump(aLevel + "\n");
      var args = Array.prototype.slice.call(arguments, 0);
      args.forEach(function(arg) {
        dump(log(arg));
      });
    };
  }

  /**
   * Build out the console object
   */
  console.debug = createMultiLineDumper("debug");
  console.log = createDumper("log");
  console.info = createDumper("info");
  console.warn = createDumper("warn");
  console.error = createMultiLineDumper("error");
  console.trace = function Console_trace() {
    var trace = getStack(Components.stack.caller);
    dump(formatTrace(trace) + "\n");
  },
  console.clear = function Console_clear() {};

  console.dir = createMultiLineDumper("dir");
  console.dirxml = createMultiLineDumper("dirxml");
  console.group = createDumper("group");
  console.groupEnd = createDumper("groupEnd");

})();
<|endoftext|>


<commit_before>Accents.module("TermsApp.Views", function(Views, Accents, Backbone, Marionette, $, _){
  // form for adding terms
  Views.AddTermFormView = Backbone.Marionette.ItemView.extend({
    template: '#add-term-form-template',
    currentAlertView: null,
    events: {
         'click button': 'addTerm',
         'change #add-word': 'updateTerm',
         'keyup #add-word': 'updateTerm',
         'keyup #book-ref': 'chekTerm'
    },
    ui: {
        term: '#add-word',
        ref: '#book-ref',
        rendered_word: '#rendered-word',
    },

    onRender: function(){
      if(Accents.TermsApp.refValue){
        this.ui.ref.val( Accents.TermsApp.refValue );
      }
    },

    chekTerm: function(e){
      if(e.keyCode == 13){
        this.addTerm();
      }
    },

    addTerm: function () {
       console.log('Adding new term: ', this.ui.term.val(), this.ui.ref.val());
       var self = this;
       if( this.currentAlertView ){
         this.currentAlertView.remove();
       }
       var validateTerm = new Accents.Entities.Term({
            term: this.ui.term.val(),
            ref: this.ui.ref.val(),
            user : Accents.user.get('user'),
       });
        var errors = validateTerm.validate();
        if( _.isEmpty(errors) ){
          var termValues = validateTerm.get("term").split(" ");
          Accents.TermsApp.refValue = this.ui.ref.val();
          _.each(termValues, function(termV){
              if(termV.trim() != "" ){
                var savedModel = new Accents.Entities.Term({
                    id: Accents.Utils.genUUID('xxxxxxxxxx'),
                    term: termV,
                    ref: self.ui.ref.val(),
                    user : Accents.user.get('user'),
                    type: 'term'
                });
                self.collection.add(savedModel);
                savedModel.save({}, {
                    error: function(model, response) {
                        console.log(response.responseText);
                    }
                });
              }
          });
          this.showSuccess();
          this.ui.term.val('');
          this.ui.rendered_word.empty();
          this.ui.term.focus();
        }else{
          this.showErrors(errors);
	}
    },

    updateTerm: function (e) {
      if(e.keyCode == 13){
        this.addTerm();
      }else{
        var pos = this.ui.term[0].selectionStart;
        var term = this.ui.term.val();
        var part = Accents.Utils.renderGlyph2UTF(term.slice(0, pos));
        this.ui.term.val(part + term.slice(pos));
        this.ui.term[0].selectionStart = part.length;
        this.ui.term[0].selectionEnd = part.length;
        // temporarily display HTML version below since we cannot display underscores in input
        this.ui.rendered_word.html(Accents.Utils.renderTypedTerm(this.ui.term.val()));

        if( this.ui.ref.val() == "" && Accents.TermsApp.refValue){
          this.ui.ref.val( Accents.TermsApp.refValue );
        }

        Accents.trigger("filter:terms", Accents.Utils.renderTypedTerm(this.ui.term.val()));
      }
    },

    showSuccess: function(){
      var _errors =[];
      _errors.push("The word(s) have been Added");
      this.currentAlertView = new Views.AlertView( {model: new Backbone.Model({errors: _errors, type: "success"}) } );
      this.$(".alert-container").html(this.currentAlertView.render().el);
    },

    showErrors: function(errors){
      var _errors =[];
      if(errors.term){
        _errors.push("Term: " + errors.term);
      }
      if(errors.ref){
        _errors.push("Ref: " + errors.ref);
      }
      this.currentAlertView = new Views.AlertView( {model: new Backbone.Model({errors: _errors, type: "danger"}) } );
      //this.$(".form-inline").prepend("
"+ _errors  +"
");
      this.$(".alert-container").html(this.currentAlertView.render().el);
      if( errors.term ){  this.ui.term.parent().addClass("has-error"); }
      if( errors.term ){  this.ui.ref.parent().addClass("has-error"); }
    }
  });

  // temporary add/remove links
  /*
  Views.TempLinksView = Backbone.Marionette.ItemView.extend({
    template: '#temp-links-template',
    events: {
         'click button#deleteall': 'deleteAll',
         'click button#generatefakes': 'generateFakes',
    },
    deleteAll: function() {
        while (model = this.collection.first()) {
            model.destroy();
        }
    },
    generateFakes: function () {
        Accents.Entities.fakeTerms(this.collection);
    },
  });
*/

  // table of terms at bottom
  Views.TermView = Backbone.Marionette.ItemView.extend({
    template: '#term-list-item-template',
    tagName: 'tr',

    events: {
      'click .remove': 'removeTerm'
    },

    removeTerm: function(){
      if( confirm('Are you sure?')){
        this.model.destroy();
      }
    }

  });

  Views.FilteredTermView = Backbone.Marionette.ItemView.extend({
    template: '#term-filtered-list-item-template',
    tagName: 'tr'
  });

  Views.TermsView = Backbone.Marionette.CompositeView.extend({
    template: '#terms-list-table-template',
    itemView: Views.TermView,
    itemViewContainer: 'tbody',
    collectionEvents: {
        "change reset add remove": "render"
    }
  });

  Views.FilteredTermsView = Backbone.Marionette.CompositeView.extend({
    template: '#terms-filtered-list-table-template',
    itemView: Views.FilteredTermView,
    itemViewContainer: 'tbody',
    collectionEvents: {
        "reset add remove": "render"
    },

    initialize: function(){
      var groupedObject = this.collection.countBy("term");
      var array = [];
      for(object in groupedObject ){
        array.push({term: object, count: groupedObject[object]});
      }
      this.collection = new Backbone.Collection(array);
      Accents.on("filter:terms", this.filterTerms);
    },

    onClose: function(){
      Accents.off("filter:terms", this.filterTerms);
    },

    filterTerms: function(term){
      var text = term || ""
      var patt = new RegExp(text, 'i');
      var patt2 = new RegExp(Accents.Utils.dotUndersRevert(text), 'i');
      $("#terms-filtered-table table tbody tr").each(function(){
        var text = $(this).find('td.term').text();
        if( patt2.test( Accents.Utils.dotUndersRevert(text)) || patt.test(text) ){
          $(this).css("display", "");
        }else{
          $(this).css( "display", "none" );
          return true;
        }
      });
      console.log("Lets filter terms: " + term );
    }

  });

  // table of terms at bottom
  Views.TotalTermsView = Backbone.Marionette.ItemView.extend({
    template: '#term-list-total-template',
    serializeData: function() {
        return {
            "total_count": this.collection.length
        };
    },
    collectionEvents: {
        "change reset add remove": "render",
    },
    tagName: 'h3'
  });

  // add terms main area
  Views.AddTermMainLayout = Marionette.Layout.extend({
    template: '#add-term-main-layout-template',
    regions: {
      add_term_form : "#add-term-form",
      add_remove_links  : "#add-remove-links",
      add_terms_list  : "#add-terms-list",
    }
  });

  // table layout with total at the top
  Views.TermsListLayout = Marionette.Layout.extend({
    template: '#terms-list-layout-template',
    regions: {
      add_term_list_total: "#terms-total",
      add_term_list_table: "#terms-table",
      add_term_filtered_table: "#terms-filtered-table"
    },

    initialize: function(){
      Accents.on("filter:terms", this.selectFilteredTab);
    },

    selectFilteredTab: function(term){
      $('#myTab a:last').tab('show');
    }

  });

  Views.AlertView =  Backbone.Marionette.ItemView.extend({
    template: "#alert-template",

    events:{
      "click .close": "close"
    },

    close: function(e){
      this.remove();
    }
  });

});
<commit_msg>removed underscore character when user is filtering<commit_after>Accents.module("TermsApp.Views", function(Views, Accents, Backbone, Marionette, $, _){
  // form for adding terms
  Views.AddTermFormView = Backbone.Marionette.ItemView.extend({
    template: '#add-term-form-template',
    currentAlertView: null,
    events: {
         'click button': 'addTerm',
         'change #add-word': 'updateTerm',
         'keyup #add-word': 'updateTerm',
         'keyup #book-ref': 'chekTerm'
    },
    ui: {
        term: '#add-word',
        ref: '#book-ref',
        rendered_word: '#rendered-word',
    },

    onRender: function(){
      if(Accents.TermsApp.refValue){
        this.ui.ref.val( Accents.TermsApp.refValue );
      }
    },

    chekTerm: function(e){
      if(e.keyCode == 13){
        this.addTerm();
      }
    },

    addTerm: function () {
       console.log('Adding new term: ', this.ui.term.val(), this.ui.ref.val());
       var self = this;
       if( this.currentAlertView ){
         this.currentAlertView.remove();
       }
       var validateTerm = new Accents.Entities.Term({
            term: this.ui.term.val(),
            ref: this.ui.ref.val(),
            user : Accents.user.get('user'),
       });
        var errors = validateTerm.validate();
        if( _.isEmpty(errors) ){
          var termValues = validateTerm.get("term").split(" ");
          Accents.TermsApp.refValue = this.ui.ref.val();
          _.each(termValues, function(termV){
              if(termV.trim() != "" ){
                var savedModel = new Accents.Entities.Term({
                    id: Accents.Utils.genUUID('xxxxxxxxxx'),
                    term: termV,
                    ref: self.ui.ref.val(),
                    user : Accents.user.get('user'),
                    type: 'term'
                });
                self.collection.add(savedModel);
                savedModel.save({}, {
                    error: function(model, response) {
                        console.log(response.responseText);
                    }
                });
              }
          });
          this.showSuccess();
          this.ui.term.val('');
          this.ui.rendered_word.empty();
          this.ui.term.focus();
        }else{
          this.showErrors(errors);
	}
    },

    updateTerm: function (e) {
      if(e.keyCode == 13){
        this.addTerm();
      }else{
        var pos = this.ui.term[0].selectionStart;
        var term = this.ui.term.val();
        var part = Accents.Utils.renderGlyph2UTF(term.slice(0, pos));
        this.ui.term.val(part + term.slice(pos));
        this.ui.term[0].selectionStart = part.length;
        this.ui.term[0].selectionEnd = part.length;
        // temporarily display HTML version below since we cannot display underscores in input
        this.ui.rendered_word.html(Accents.Utils.renderTypedTerm(this.ui.term.val()));

        if( this.ui.ref.val() == "" && Accents.TermsApp.refValue){
          this.ui.ref.val( Accents.TermsApp.refValue );
        }

        Accents.trigger("filter:terms", Accents.Utils.renderTypedTerm( this.ui.term.val().replace("_", "")  ));
      }
    },

    showSuccess: function(){
      var _errors =[];
      _errors.push("The word(s) have been Added");
      this.currentAlertView = new Views.AlertView( {model: new Backbone.Model({errors: _errors, type: "success"}) } );
      this.$(".alert-container").html(this.currentAlertView.render().el);
    },

    showErrors: function(errors){
      var _errors =[];
      if(errors.term){
        _errors.push("Term: " + errors.term);
      }
      if(errors.ref){
        _errors.push("Ref: " + errors.ref);
      }
      this.currentAlertView = new Views.AlertView( {model: new Backbone.Model({errors: _errors, type: "danger"}) } );
      //this.$(".form-inline").prepend("
"+ _errors  +"
");
      this.$(".alert-container").html(this.currentAlertView.render().el);
      if( errors.term ){  this.ui.term.parent().addClass("has-error"); }
      if( errors.term ){  this.ui.ref.parent().addClass("has-error"); }
    }
  });

  // temporary add/remove links
  /*
  Views.TempLinksView = Backbone.Marionette.ItemView.extend({
    template: '#temp-links-template',
    events: {
         'click button#deleteall': 'deleteAll',
         'click button#generatefakes': 'generateFakes',
    },
    deleteAll: function() {
        while (model = this.collection.first()) {
            model.destroy();
        }
    },
    generateFakes: function () {
        Accents.Entities.fakeTerms(this.collection);
    },
  });
*/

  // table of terms at bottom
  Views.TermView = Backbone.Marionette.ItemView.extend({
    template: '#term-list-item-template',
    tagName: 'tr',

    events: {
      'click .remove': 'removeTerm'
    },

    removeTerm: function(){
      if( confirm('Are you sure?')){
        this.model.destroy();
      }
    }

  });

  Views.FilteredTermView = Backbone.Marionette.ItemView.extend({
    template: '#term-filtered-list-item-template',
    tagName: 'tr'
  });

  Views.TermsView = Backbone.Marionette.CompositeView.extend({
    template: '#terms-list-table-template',
    itemView: Views.TermView,
    itemViewContainer: 'tbody',
    collectionEvents: {
        "change reset add remove": "render"
    }
  });

  Views.FilteredTermsView = Backbone.Marionette.CompositeView.extend({
    template: '#terms-filtered-list-table-template',
    itemView: Views.FilteredTermView,
    itemViewContainer: 'tbody',
    collectionEvents: {
        "reset add remove": "render"
    },

    initialize: function(){
      var groupedObject = this.collection.countBy("term");
      var array = [];
      for(object in groupedObject ){
        array.push({term: object, count: groupedObject[object]});
      }
      this.collection = new Backbone.Collection(array);
      Accents.on("filter:terms", this.filterTerms);
    },

    onClose: function(){
      Accents.off("filter:terms", this.filterTerms);
    },

    filterTerms: function(term){
      var text = term || ""
      var patt = new RegExp(text, 'i');
      var patt2 = new RegExp(Accents.Utils.dotUndersRevert(text), 'i');
      $("#terms-filtered-table table tbody tr").each(function(){
        var text = $(this).find('td.term').text();
        if( patt2.test( Accents.Utils.dotUndersRevert(text)) || patt.test(text) ){
          $(this).css("display", "");
        }else{
          $(this).css( "display", "none" );
          return true;
        }
      });
      console.log("Lets filter terms: " + term );
    }

  });

  // table of terms at bottom
  Views.TotalTermsView = Backbone.Marionette.ItemView.extend({
    template: '#term-list-total-template',
    serializeData: function() {
        return {
            "total_count": this.collection.length
        };
    },
    collectionEvents: {
        "change reset add remove": "render",
    },
    tagName: 'h3'
  });

  // add terms main area
  Views.AddTermMainLayout = Marionette.Layout.extend({
    template: '#add-term-main-layout-template',
    regions: {
      add_term_form : "#add-term-form",
      add_remove_links  : "#add-remove-links",
      add_terms_list  : "#add-terms-list",
    }
  });

  // table layout with total at the top
  Views.TermsListLayout = Marionette.Layout.extend({
    template: '#terms-list-layout-template',
    regions: {
      add_term_list_total: "#terms-total",
      add_term_list_table: "#terms-table",
      add_term_filtered_table: "#terms-filtered-table"
    },

    initialize: function(){
      Accents.on("filter:terms", this.selectFilteredTab);
    },

    selectFilteredTab: function(term){
      $('#myTab a:last').tab('show');
    }

  });

  Views.AlertView =  Backbone.Marionette.ItemView.extend({
    template: "#alert-template",

    events:{
      "click .close": "close"
    },

    close: function(e){
      this.remove();
    }
  });

});
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016, Globo.com (https://github.com/globocom)
 *
 * License: MIT
 */

import React, {Component} from "react";
import {Editor, RichUtils} from "draft-js";

import Icons from "./icons";
import Toolbar from "./toolbar";
import {getSelectionRange, getSelectedBlockElement} from "./utils";

export default class Megadraft extends Component {
  constructor(props) {
    super(props);

    this.actions = [
      {type: "inline", label: "B", style: "BOLD", icon: Icons.BoldIcon},
      {type: "inline", label: "I", style: "ITALIC", icon: Icons.ItalicIcon},
      {type: "separator", label: null, style: null, icon: Icons.SeparatorIcon},
      {type: "block", label: "UL", style: "unordered-list-item", icon: Icons.ULIcon},
      {type: "block", label: "OL", style: "ordered-list-item", icon: Icons.OLIcon},
      {type: "block", label: "H2", style: "header-two", icon: Icons.H2Icon},
      {type: "block", label: "QT", style: "blockquote", icon: Icons.BlockQuoteIcon}
    ];
  }

  onChange(editorState) {
    this.props.onChange(editorState);
  }

  handleKeyCommand(command) {
    const {editorState} = this.props;
    const newState = RichUtils.handleKeyCommand(editorState, command);
    if (newState) {
      this.props.onChange(newState);
      return true;
    }
    return false;
  }

  render() {
    const {editorState} = this.props;
    return (

          <Editor
            handleKeyCommand={::this.handleKeyCommand}
            editorState={editorState}
            onChange={::this.onChange} />
          <Toolbar
            editor={this.refs.editor}
            editorState={editorState}
            onChange={::this.onChange}
            actions={this.actions}/>

    );
  }
}
<commit_msg>Remove unused imports<commit_after>/*
 * Copyright (c) 2016, Globo.com (https://github.com/globocom)
 *
 * License: MIT
 */

import React, {Component} from "react";
import {Editor, RichUtils} from "draft-js";

import Icons from "./icons";
import Toolbar from "./toolbar";

export default class Megadraft extends Component {
  constructor(props) {
    super(props);

    this.actions = [
      {type: "inline", label: "B", style: "BOLD", icon: Icons.BoldIcon},
      {type: "inline", label: "I", style: "ITALIC", icon: Icons.ItalicIcon},
      {type: "separator", label: null, style: null, icon: Icons.SeparatorIcon},
      {type: "block", label: "UL", style: "unordered-list-item", icon: Icons.ULIcon},
      {type: "block", label: "OL", style: "ordered-list-item", icon: Icons.OLIcon},
      {type: "block", label: "H2", style: "header-two", icon: Icons.H2Icon},
      {type: "block", label: "QT", style: "blockquote", icon: Icons.BlockQuoteIcon}
    ];
  }

  onChange(editorState) {
    this.props.onChange(editorState);
  }

  handleKeyCommand(command) {
    const {editorState} = this.props;
    const newState = RichUtils.handleKeyCommand(editorState, command);
    if (newState) {
      this.props.onChange(newState);
      return true;
    }
    return false;
  }

  render() {
    const {editorState} = this.props;
    return (

          <Editor
            handleKeyCommand={::this.handleKeyCommand}
            editorState={editorState}
            onChange={::this.onChange} />
          <Toolbar
            editor={this.refs.editor}
            editorState={editorState}
            onChange={::this.onChange}
            actions={this.actions}/>

    );
  }
}
<|endoftext|>


<commit_before>// TODO:
// Add ability for user to apply arbitrary CSS filters (see http://html5-demos.appspot.com/static/css/filters/index.html)

var idlegif = {
    _options: {
        gifSearch: 'cute+cats',
        giphyApiUrl: 'http://api.giphy.com/v1/gifs/search',
        apiKey: 'dc6zaTOxFJmzC',

        color: 'black',
        transition: '0.5s',
    },

    _gifUrls: [],

    init: function() {
        this.createIdleGif();
        this.doGiphyApiRequest();
    },

    createIdleGif: function() {
        container = document.createElement('div');
        container.setAttribute('class', 'idlegif-container');
        container.style.cssText = 'position: fixed; left: 0px; top: 0px; width: 100%; height: 100%; opacity: 0; pointer-events: none; z-index: 2147483647';
        container.style.setProperty('-webkit-Transition' , 'opacity ' + this._options.transition);
        container.style.transition = 'opacity ' + this._options.transition;
        container.style.backgroundColor = this._options.color;

        image = document.createElement('img');
        image.setAttribute('class', 'idlegif-image');
        image.style.cssText = 'position: absolute; left: 0px; top: 0px; width: 100%; height: 100%;';

        footer = document.createElement('span');
        footer.setAttribute('class', 'idlegif-footer');
        footer.style.cssText = 'position: absolute; left: 0px; bottom: 0px; padding: 0.2em; opacity: 0.5; background-color: black; color: white;';
        footer.innerHTML = 'idlegif.js | made with ♥ & ☕ | powered by Giphy';

        document.body.appendChild(container);
        container.appendChild(image);
        container.appendChild(footer);

        this.container = container;
        this.image = image;
    },

    doGiphyApiRequest: function() {
        var xmlhttp = new XMLHttpRequest();
        ajaxUrl = this._options.giphyApiUrl + '?' + 'q=' + this._options.gifSearch + '&' + 'api_key=' + this._options.apiKey;

        // Called from xmlhttp
        xmlhttp.onreadystatechange = function() {
            if (xmlhttp.readyState == 4 && xmlhttp.status == 200)
                idlegif.digestGiphyApiResponse(xmlhttp.responseText);
        }

        xmlhttp.open('GET', ajaxUrl, true);
        xmlhttp.send();
    },

    // Called from idlegif
    digestGiphyApiResponse: function(responseText) {
        responseObj = JSON.parse(responseText);

        if (gifObjs = responseObj.data) this._gifUrls = [];

        for (var i = gifObjs.length - 1; i >= 0; i--) {
            if (gifId = gifObjs[i].id) {
                this._gifUrls.push('https://media.giphy.com/media/' + gifId + '/giphy.gif');
            }
        };
    },

    showIdleGif: function() {
        if (!(gifUrl = this._gifUrls[Math.floor(this._gifUrls.length * Math.random())])) {
            console.log('No GIF urls were present: ' + this._gifUrls);
            return;
        }

        this.image.setAttribute('src', gifUrl);
        // note that anonymous function is called from image object
        this.bindEvent(this.image, 'load', function() {
            idlegif.container.style.opacity = 1;
            idlegif.container.style.pointerEvents = 'auto';
        });
    },

    hideIdleGif: function() {
        this.container.style.opacity = 0;
        this.container.style.pointerEvents = 'none';
    },

    // For compatibility issues with adding event handlers
    bindEvent: function(elem, e, func) {
        if (elem.addEventListener)
            elem.addEventListener(e, func, false);
        else
            elem.attachEvent('on' + e, func);
    },
}<commit_msg>changed default giphy search, click to exit screeny<commit_after>// TODO:
// Add ability for user to apply arbitrary CSS filters (see http://html5-demos.appspot.com/static/css/filters/index.html)

var idlegif = {
    _options: {
        gifSearch: 'glitch',
        giphyApiUrl: 'http://api.giphy.com/v1/gifs/search',
        apiKey: 'dc6zaTOxFJmzC',

        color: 'black',
        transition: '0.5s',
    },

    _gifUrls: [],

    init: function() {
        this.createIdleGif();
        this.doGiphyApiRequest();
    },

    createIdleGif: function() {
        container = document.createElement('div');
        container.setAttribute('class', 'idlegif-container');
        container.style.cssText = 'position: fixed; left: 0px; top: 0px; width: 100%; height: 100%; opacity: 0; pointer-events: none; z-index: 2147483647';
        container.style.setProperty('-webkit-Transition' , 'opacity ' + this._options.transition);
        container.style.transition = 'opacity ' + this._options.transition;
        container.style.backgroundColor = this._options.color;

        image = document.createElement('img');
        image.setAttribute('class', 'idlegif-image');
        image.style.cssText = 'position: absolute; left: 0px; top: 0px; width: 100%; height: 100%;';

        footer = document.createElement('span');
        footer.setAttribute('class', 'idlegif-footer');
        footer.style.cssText = 'position: absolute; left: 0px; bottom: 0px; padding: 0.2em; opacity: 0.5; background-color: black; color: white;';
        footer.innerHTML = 'idlegif.js | made with ♥ & ☕ | powered by Giphy';

        document.body.appendChild(container);
        container.appendChild(image);
        container.appendChild(footer);

        this.container = container;
        this.image = image;

        this.bindEvent(image, 'click', this.hideIdleGif);
    },

    doGiphyApiRequest: function() {
        var xmlhttp = new XMLHttpRequest();
        ajaxUrl = this._options.giphyApiUrl + '?' + 'q=' + this._options.gifSearch + '&' + 'api_key=' + this._options.apiKey;

        // Called from xmlhttp
        xmlhttp.onreadystatechange = function() {
            if (xmlhttp.readyState == 4 && xmlhttp.status == 200)
                idlegif.digestGiphyApiResponse(xmlhttp.responseText);
        }

        xmlhttp.open('GET', ajaxUrl, true);
        xmlhttp.send();
    },

    // Called from idlegif
    digestGiphyApiResponse: function(responseText) {
        responseObj = JSON.parse(responseText);

        if (gifObjs = responseObj.data) this._gifUrls = [];

        for (var i = gifObjs.length - 1; i >= 0; i--) {
            if (gifId = gifObjs[i].id) {
                this._gifUrls.push('https://media.giphy.com/media/' + gifId + '/giphy.gif');
            }
        };
    },

    showIdleGif: function() {
        if (!(gifUrl = this._gifUrls[Math.floor(this._gifUrls.length * Math.random())])) {
            console.log('No GIF urls were present: ' + this._gifUrls);
            return;
        }

        this.image.setAttribute('src', gifUrl);
        // note that anonymous function is called from image object
        this.bindEvent(this.image, 'load', function() {
            idlegif.container.style.opacity = 1;
            idlegif.container.style.pointerEvents = 'auto';
        });
    },

    hideIdleGif: function() {
        idlegif.container.style.opacity = 0;
        idlegif.container.style.pointerEvents = 'none';
    },

    // For compatibility issues with adding event handlers
    bindEvent: function(elem, e, func) {
        if (elem.addEventListener)
            elem.addEventListener(e, func, false);
        else
            elem.attachEvent('on' + e, func);
    },
}<|endoftext|>


<commit_before>/**
* The Icons used in this Toolbar are CC-BY Glyphicons - http://glyphicons.com/
*/

import intersect from '@turf/intersect';
import difference from '@turf/difference';
import PMButton from './L.Controls';

L.Control.PMButton = PMButton;

const Toolbar = L.Class.extend({
    options: {
        drawMarker: true,
        drawPolygon: true,
        drawPolyline: true,
        drawCircle: true,
        editPolygon: true,
        cutPolygon: true,
        dragPolygon: false,
        deleteLayer: true,
        position: 'topleft',
    },
    initialize(map) {
        this.map = map;

        this.buttons = {};
        this.isVisible = false;
        this.container = L.DomUtil.create('div', 'leaflet-pm-toolbar leaflet-bar leaflet-control');
        this._defineButtons();
    },
    getButtons() {
        return this.buttons;
    },

    addControls(options = this.options) {
        // adds all buttons to the map specified inside options

        // first set the options
        L.Util.setOptions(this, options);

        // now show the specified buttons
        this._showHideButtons();
        this.isVisible = true;
    },
    removeControls() {
        // grab all buttons to loop through
        const buttons = this.getButtons();

        // remove all buttons
        for (const btn in buttons) {
            buttons[btn].remove();
        }

        this.isVisible = false;
    },
    toggleControls() {
        if (this.isVisible) {
            this.removeControls();
        } else {
            this.addControls();
        }
    },
    _addButton(name, button) {
        this.buttons[name] = button;
        this.options[name] = this.options[name] || false;

        return this.buttons[name];
    },
    triggerClickOnToggledButtons(exceptThisButton) {
        // this function is used when - e.g. drawing mode is enabled and a possible
        // other active mode (like removal tool) is already active.
        // we can't have two active modes because of possible event conflicts
        // so, we trigger a click on all currently active (toggled) buttons

        for (const name in this.buttons) {
            if(this.buttons[name] !== exceptThisButton && this.buttons[name].toggled()) {
                this.buttons[name]._triggerClick();
            }
        }
    },
    toggleButton(name, status) {
        // does not fire the events/functionality of the button
        // this just changes the state and is used if a functionality (like Draw)
        // is enabled manually via script

        // as some mode got enabled, we still have to trigger the click on the other buttons
        // to disable their mode
        this.triggerClickOnToggledButtons(this.buttons[name]);

        // now toggle the state of the button
        return this.buttons[name].toggle(status);
    },
    _defineButtons() {
        // some buttons are still in their respective classes, like L.PM.Draw.Poly
        const deleteButton = {
            className: ' leaflet-pm-icon-delete',
            onClick: () => {

            },
            afterClick: () => {
                this.map.pm.toggleGlobalRemovalMode();
            },
            doToggle: true,
            toggleStatus: false,
            disableOtherButtons: true,
            position: this.options.position,
        };

        const drawPolyButton = {
            className: 'leaflet-pm-icon-polygon',
            onClick: () => {

            },
            afterClick: () => {
                // toggle drawing mode
                this.map.pm.Draw.Poly.toggle();
            },
            doToggle: true,
            toggleStatus: false,
            disableOtherButtons: true,
            position: this.options.position,
        };

        const cutButton = {
            className: 'leaflet-pm-icon-cut',
            onClick: () => {
            },
            afterClick: () => {
                // TODO:
                // take care of the "double activating" and button activation problem
                // handle cancelation of cutting
                // move the code into a class or helper or whatever
                // check if we can alter the current layer instead of replacing it to keep references

                // disable all edit modes
                this.map.pm.disableGlobalEditMode();

                // enable polygon drawing mode without snap
                this.map.pm.Draw.Poly.enable({ snappable: false });

                this.map.off('pm:create');
                this.map.on('pm:create', (e) => {
                    const layer = e.layer;
                    const all = this.map._layers;

                    const layers = Object.keys(all)

                    // convert object to array
                    .map(l => all[l])

                    // only layers handled by leaflet.pm
                    .filter(l => l.pm)

                    // only polygons
                    .filter(l => l instanceof L.Polygon)

                    // exclude the drawn one
                    .filter(l => l !== layer)

                    // only layers with intersections
                    .filter(l => !!intersect(layer.toGeoJSON(), l.toGeoJSON()));

                    layers.forEach((l) => {
                        const diff = difference(l.toGeoJSON(), layer.toGeoJSON());
                        L.geoJSON(diff).addTo(this.map);

                        l.remove();
                        layer.remove();
                    });
                });
            },
            doToggle: true,
            toggleStatus: false,
            disableOtherButtons: true,
            position: this.options.position,
        };

        const drawMarkerButton = {
            className: 'leaflet-pm-icon-marker',
            onClick: () => {

            },
            afterClick: () => {
                // toggle drawing mode
                this.map.pm.Draw.Marker.toggle();
            },
            doToggle: true,
            toggleStatus: false,
            disableOtherButtons: true,
            position: this.options.position,
        };

        const drawLineButton = {
            className: 'leaflet-pm-icon-polyline',
            onClick: () => {

            },
            afterClick: () => {
                // toggle drawing mode
                this.map.pm.Draw.Line.toggle();
            },
            doToggle: true,
            toggleStatus: false,
            disableOtherButtons: true,
            position: this.options.position,
        };

        const drawCircleButton = {
            className: 'leaflet-pm-icon-circle',
            onClick: () => {

            },
            afterClick: () => {
                // toggle drawing mode
                this.map.pm.Draw.Circle.toggle();
            },
            doToggle: true,
            toggleStatus: false,
            disableOtherButtons: true,
            position: this.options.position,
        };

        const editButton = {
            className: 'leaflet-pm-icon-edit',
            onClick: () => {
            },
            afterClick: () => {
                this.map.pm.toggleGlobalEditMode({
                    snappable: true,
                    draggable: true,
                });
            },
            doToggle: true,
            toggleStatus: false,
            disableOtherButtons: true,
            position: this.options.position,
        };

        const dragButton = {
            className: 'leaflet-pm-icon-drag',
            onClick: () => {
            },
            afterClick: () => {

            },
            doToggle: true,
            toggleStatus: false,
            disableOtherButtons: true,
            position: this.options.position,
        };

        this._addButton('drawMarker', new L.Control.PMButton(drawMarkerButton));
        this._addButton('drawPolygon', new L.Control.PMButton(drawPolyButton));
        this._addButton('cutPolygon', new L.Control.PMButton(cutButton));
        this._addButton('drawPolyline', new L.Control.PMButton(drawLineButton));
        this._addButton('drawCircle', new L.Control.PMButton(drawCircleButton));
        // TODO: rename editPolygon to editMode
        this._addButton('editPolygon', new L.Control.PMButton(editButton));
        this._addButton('dragPolygon', new L.Control.PMButton(dragButton));
        // TODO: rename deleteLayer to removalMode
        this._addButton('deleteLayer', new L.Control.PMButton(deleteButton));
    },

    _showHideButtons() {
        // remove all buttons, that's because the Toolbar can be added again with
        // different options so it's basically a reset and add again
        this.removeControls();

        const buttons = this.getButtons();
        for (const btn in buttons) {
            if(this.options[btn]) {
                // if options say the button should be visible, add it to the map
                buttons[btn].setPosition(this.options.position);
                buttons[btn].addTo(this.map);
            }
        }
    },
});

export default Toolbar;
<commit_msg>properly removing cutting events<commit_after>/**
* The Icons used in this Toolbar are CC-BY Glyphicons - http://glyphicons.com/
*/

import intersect from '@turf/intersect';
import difference from '@turf/difference';
import PMButton from './L.Controls';

L.Control.PMButton = PMButton;

const Toolbar = L.Class.extend({
    options: {
        drawMarker: true,
        drawPolygon: true,
        drawPolyline: true,
        drawCircle: true,
        editPolygon: true,
        cutPolygon: true,
        dragPolygon: false,
        deleteLayer: true,
        position: 'topleft',
    },
    initialize(map) {
        this.map = map;

        this.buttons = {};
        this.isVisible = false;
        this.container = L.DomUtil.create('div', 'leaflet-pm-toolbar leaflet-bar leaflet-control');
        this._defineButtons();
    },
    getButtons() {
        return this.buttons;
    },

    addControls(options = this.options) {
        // adds all buttons to the map specified inside options

        // first set the options
        L.Util.setOptions(this, options);

        // now show the specified buttons
        this._showHideButtons();
        this.isVisible = true;
    },
    removeControls() {
        // grab all buttons to loop through
        const buttons = this.getButtons();

        // remove all buttons
        for (const btn in buttons) {
            buttons[btn].remove();
        }

        this.isVisible = false;
    },
    toggleControls() {
        if (this.isVisible) {
            this.removeControls();
        } else {
            this.addControls();
        }
    },
    _addButton(name, button) {
        this.buttons[name] = button;
        this.options[name] = this.options[name] || false;

        return this.buttons[name];
    },
    triggerClickOnToggledButtons(exceptThisButton) {
        // this function is used when - e.g. drawing mode is enabled and a possible
        // other active mode (like removal tool) is already active.
        // we can't have two active modes because of possible event conflicts
        // so, we trigger a click on all currently active (toggled) buttons

        for (const name in this.buttons) {
            if(this.buttons[name] !== exceptThisButton && this.buttons[name].toggled()) {
                this.buttons[name]._triggerClick();
            }
        }
    },
    toggleButton(name, status) {
        // does not fire the events/functionality of the button
        // this just changes the state and is used if a functionality (like Draw)
        // is enabled manually via script

        // as some mode got enabled, we still have to trigger the click on the other buttons
        // to disable their mode
        this.triggerClickOnToggledButtons(this.buttons[name]);

        // now toggle the state of the button
        return this.buttons[name].toggle(status);
    },
    _defineButtons() {
        // some buttons are still in their respective classes, like L.PM.Draw.Poly
        const deleteButton = {
            className: ' leaflet-pm-icon-delete',
            onClick: () => {

            },
            afterClick: () => {
                this.map.pm.toggleGlobalRemovalMode();
            },
            doToggle: true,
            toggleStatus: false,
            disableOtherButtons: true,
            position: this.options.position,
        };

        const drawPolyButton = {
            className: 'leaflet-pm-icon-polygon',
            onClick: () => {

            },
            afterClick: () => {
                // toggle drawing mode
                this.map.pm.Draw.Poly.toggle();
            },
            doToggle: true,
            toggleStatus: false,
            disableOtherButtons: true,
            position: this.options.position,
        };

        const cutButton = {
            className: 'leaflet-pm-icon-cut',
            onClick: () => {
            },
            afterClick: () => {
                // TODO:
                // take care of the "double activating" and button activation problem
                // handle cancelation of cutting
                // move the code into a class or helper or whatever
                // check if we can alter the current layer instead of replacing it to keep references

                // disable all edit modes
                this.map.pm.disableGlobalEditMode();

                // enable polygon drawing mode without snap
                this.map.pm.Draw.Poly.enable({ snappable: false });

                const cut = (e) => {
                    const layer = e.layer;
                    const all = this.map._layers;

                    const layers = Object.keys(all)

                    // convert object to array
                    .map(l => all[l])

                    // only layers handled by leaflet.pm
                    .filter(l => l.pm)

                    // only polygons
                    .filter(l => l instanceof L.Polygon)

                    // exclude the drawn one
                    .filter(l => l !== layer)

                    // only layers with intersections
                    .filter(l => !!intersect(layer.toGeoJSON(), l.toGeoJSON()));

                    layers.forEach((l) => {
                        // find layer difference
                        const diff = difference(l.toGeoJSON(), layer.toGeoJSON());

                        // add new layer to map
                        L.geoJSON(diff).addTo(this.map);

                        // remove old layer and cutting layer
                        l.remove();
                        layer.remove();
                    });

                    this.map.off('pm:create', cut);
                };

                this.map.off('pm:create');
                this.map.on('pm:create', cut);
            },
            doToggle: true,
            toggleStatus: false,
            disableOtherButtons: true,
            position: this.options.position,
        };

        const drawMarkerButton = {
            className: 'leaflet-pm-icon-marker',
            onClick: () => {

            },
            afterClick: () => {
                // toggle drawing mode
                this.map.pm.Draw.Marker.toggle();
            },
            doToggle: true,
            toggleStatus: false,
            disableOtherButtons: true,
            position: this.options.position,
        };

        const drawLineButton = {
            className: 'leaflet-pm-icon-polyline',
            onClick: () => {

            },
            afterClick: () => {
                // toggle drawing mode
                this.map.pm.Draw.Line.toggle();
            },
            doToggle: true,
            toggleStatus: false,
            disableOtherButtons: true,
            position: this.options.position,
        };

        const drawCircleButton = {
            className: 'leaflet-pm-icon-circle',
            onClick: () => {

            },
            afterClick: () => {
                // toggle drawing mode
                this.map.pm.Draw.Circle.toggle();
            },
            doToggle: true,
            toggleStatus: false,
            disableOtherButtons: true,
            position: this.options.position,
        };

        const editButton = {
            className: 'leaflet-pm-icon-edit',
            onClick: () => {
            },
            afterClick: () => {
                this.map.pm.toggleGlobalEditMode({
                    snappable: true,
                    draggable: true,
                });
            },
            doToggle: true,
            toggleStatus: false,
            disableOtherButtons: true,
            position: this.options.position,
        };

        const dragButton = {
            className: 'leaflet-pm-icon-drag',
            onClick: () => {
            },
            afterClick: () => {

            },
            doToggle: true,
            toggleStatus: false,
            disableOtherButtons: true,
            position: this.options.position,
        };

        this._addButton('drawMarker', new L.Control.PMButton(drawMarkerButton));
        this._addButton('drawPolygon', new L.Control.PMButton(drawPolyButton));
        this._addButton('cutPolygon', new L.Control.PMButton(cutButton));
        this._addButton('drawPolyline', new L.Control.PMButton(drawLineButton));
        this._addButton('drawCircle', new L.Control.PMButton(drawCircleButton));
        // TODO: rename editPolygon to editMode
        this._addButton('editPolygon', new L.Control.PMButton(editButton));
        this._addButton('dragPolygon', new L.Control.PMButton(dragButton));
        // TODO: rename deleteLayer to removalMode
        this._addButton('deleteLayer', new L.Control.PMButton(deleteButton));
    },

    _showHideButtons() {
        // remove all buttons, that's because the Toolbar can be added again with
        // different options so it's basically a reset and add again
        this.removeControls();

        const buttons = this.getButtons();
        for (const btn in buttons) {
            if(this.options[btn]) {
                // if options say the button should be visible, add it to the map
                buttons[btn].setPosition(this.options.position);
                buttons[btn].addTo(this.map);
            }
        }
    },
});

export default Toolbar;
<|endoftext|>