<commit_before>// SAMPLE
this.manifest = {
    "name": "BetterTweetDeck",
    "icon": "icon.png",
    "settings": [
        {
            "tab": "General",
            "group": "Info",
            "name": "informations",
            "type": "description",
            "text": "

Don't forget to reload any TweetDeck tab after applying your settings
 This extension only works with http://tweetdeck.twitter.com not with the \"TweetDeck\" Chrome application !
"
        },
        {
            "tab": "General",
            "group": "Time formatting",
            "name": "timestamp",
            "type": "popupButton",
            "label": "Time should be:",
            "options": {
                "values": [
                    {
                        "value": "relative",
                        "text": "Relative (1m, 2h, 3d...)"
                    },
                    {
                        "value": "absolute",
                        "text": "Absolute (dd/mm/yy hh:mm)"
                    },
                    {
                        "value": "absolute_us",
                        "text": "Absolute 'US Style' (mm/dd/yy hh:mm)"
                    }
                ],
            },
        },
        {
            "tab":"General",
            "group":"Time formatting",
            "name":"full_after_24h",
            "type":"checkbox",
            "label":"Display full-time (dd/mm/yy hh:mm) only after 24h"
        },
        {
            "tab": "General",
            "group": "Users",
            "name": "name_display",
            "type": "popupButton",
            "label": "Display name/username as:",
            "options": {
                "values": [
                    {
                        "value": "both",
                        "text": "Full Name @username"
                    },
                    {
                        "value": "inverted",
                        "text": "@Username Full Name"
                    },
                    {
                        "value": "username",
                        "text": "Username only"
                    },
                    {
                        "value": "fullname",
                        "text": "Fullname only"
                    }
                ],
            },
        },
        {
            "tab": "General",
            "group": "Users",
            "name": "typeahead_display_username_only",
            "type": "checkbox",
            "label": "The mention helper displays only the usernames"
        },
        {
            "tab": "General",
            "group": "Users",
            "name": "circled_avatars",
            "type": "checkbox",
            "label": "Display rounded avatars (it's fancy!)"
        },
        {
            "tab": "General",
            "group": "Appearance",
            "name": "reduced_padding",
            "type": "checkbox",
            "label": "Columns take less space"
        },
        {
            "tab": "General",
            "group": "Appearance",
            "name": "no_columns_icons",
            "type": "checkbox",
            "label": "No icons in column headers",
        },
        {
            "tab": "General",
            "group": "Appearance",
            "name": "grayscale_notification_icons",
            "type": "checkbox",
            "label": "Icons in Notification column should be in grayscales"
        },
        {
            "tab": "General",
            "group": "Content",
            "name": "url_redirection",
            "type": "checkbox",
            "label": "Remove t.co redirection"
        },
        {
            "tab": "General",
            "group": "Appearance",
            "name": "yt_rm_button",
            "type": "checkbox",
            "label": "Hide play button on YouTube previews"
        },
        {
            "tab": "General",
            "group": "Content",
            "name": "only_one_thumbnails",
            "type": "checkbox",
            "label": "Display only one thumbnail per tweet"
        },
        {
            "tab": "General",
            "group": "Content",
            "name": "thumbnails",
            "type": "description",
            "text": "Display thumbnails from"
        },
        {
            "tab": "General",
            "group": "Content",
            "name": "img_preview_500px",
            "type": "checkbox",
            "label": "500px"
        },
        {
            "tab": "General",
            "group": "Content",
            "name": "img_preview_cloud",
            "type": "checkbox",
            "label": "CloudApp"
        },
        {
            "tab": "General",
            "group": "Content",
            "name": "img_preview_droplr",
            "type": "checkbox",
            "label": "Droplr"
        },
        {
            "tab": "General",
            "group": "Content",
            "name": "img_preview_dailymotion",
            "type": "checkbox",
            "label": "Dailymotion"
        },
        {
            "tab": "General",
            "group": "Content",
            "name": "img_preview_flickr",
            "type": "checkbox",
            "label": "Flickr"
        },
        {
            "tab": "General",
            "group": "Content",
            "name": "img_preview_imgur",
            "type": "checkbox",
            "label": "Imgur"
        },
        {
            "tab": "General",
            "group": "Content",
            "name": "img_preview_instagram",
            "type": "checkbox",
            "label": "Instagram"
        },
        {
            "tab": "General",
            "group": "Content",
            "name": "img_preview_tumblr",
            "type": "checkbox",
            "label": "Tumblr"
        },
        {
            "tab": "General",
            "group": "Content",
            "name": "img_preview_vimeo",
            "type": "checkbox",
            "label": "Vimeo"
        }
    ]
};
<commit_msg>[Improvement] Changed the "title" of the Settings page to go with the new design<commit_after>// SAMPLE
var settingsTitle = "BetterTweetDeck Settings";
this.manifest = {
    "name": "BetterTweetDeck",
    "icon": "icon.png",
    "settings": [
        {
            "tab": settingsTitle,
            "group": "Info",
            "name": "informations",
            "type": "description",
            "text": "

Don't forget to reload any TweetDeck tab after applying your settings
 This extension only works with http://tweetdeck.twitter.com not with the \"TweetDeck\" Chrome application !
"
        },
        {
            "tab": settingsTitle,
            "group": "Time formatting",
            "name": "timestamp",
            "type": "popupButton",
            "label": "Time should be:",
            "options": {
                "values": [
                    {
                        "value": "relative",
                        "text": "Relative (1m, 2h, 3d...)"
                    },
                    {
                        "value": "absolute",
                        "text": "Absolute (dd/mm/yy hh:mm)"
                    },
                    {
                        "value": "absolute_us",
                        "text": "Absolute 'US Style' (mm/dd/yy hh:mm)"
                    }
                ],
            },
        },
        {
            "tab":settingsTitle,
            "group":"Time formatting",
            "name":"full_after_24h",
            "type":"checkbox",
            "label":"Display full-time (dd/mm/yy hh:mm) only after 24h"
        },
        {
            "tab": settingsTitle,
            "group": "Users",
            "name": "name_display",
            "type": "popupButton",
            "label": "Display name/username as:",
            "options": {
                "values": [
                    {
                        "value": "both",
                        "text": "Full Name @username"
                    },
                    {
                        "value": "inverted",
                        "text": "@Username Full Name"
                    },
                    {
                        "value": "username",
                        "text": "Username only"
                    },
                    {
                        "value": "fullname",
                        "text": "Fullname only"
                    }
                ],
            },
        },
        {
            "tab": settingsTitle,
            "group": "Users",
            "name": "typeahead_display_username_only",
            "type": "checkbox",
            "label": "The mention helper displays only the usernames"
        },
        {
            "tab": settingsTitle,
            "group": "Users",
            "name": "circled_avatars",
            "type": "checkbox",
            "label": "Display rounded avatars (it's fancy!)"
        },
        {
            "tab": settingsTitle,
            "group": "Appearance",
            "name": "reduced_padding",
            "type": "checkbox",
            "label": "Columns take less space"
        },
        {
            "tab": settingsTitle,
            "group": "Appearance",
            "name": "no_columns_icons",
            "type": "checkbox",
            "label": "No icons in column headers",
        },
        {
            "tab": settingsTitle,
            "group": "Appearance",
            "name": "grayscale_notification_icons",
            "type": "checkbox",
            "label": "Icons in Notification column should be in grayscales"
        },
        {
            "tab": settingsTitle,
            "group": "Content",
            "name": "url_redirection",
            "type": "checkbox",
            "label": "Remove t.co redirection"
        },
        {
            "tab": settingsTitle,
            "group": "Appearance",
            "name": "yt_rm_button",
            "type": "checkbox",
            "label": "Hide play button on YouTube previews"
        },
        {
            "tab": settingsTitle,
            "group": "Content",
            "name": "only_one_thumbnails",
            "type": "checkbox",
            "label": "Display only one thumbnail per tweet"
        },
        {
            "tab": settingsTitle,
            "group": "Content",
            "name": "thumbnails",
            "type": "description",
            "text": "Display thumbnails from"
        },
        {
            "tab": settingsTitle,
            "group": "Content",
            "name": "img_preview_500px",
            "type": "checkbox",
            "label": "500px"
        },
        {
            "tab": settingsTitle,
            "group": "Content",
            "name": "img_preview_cloud",
            "type": "checkbox",
            "label": "CloudApp"
        },
        {
            "tab": settingsTitle,
            "group": "Content",
            "name": "img_preview_droplr",
            "type": "checkbox",
            "label": "Droplr"
        },
        {
            "tab": settingsTitle,
            "group": "Content",
            "name": "img_preview_dailymotion",
            "type": "checkbox",
            "label": "Dailymotion"
        },
        {
            "tab": settingsTitle,
            "group": "Content",
            "name": "img_preview_flickr",
            "type": "checkbox",
            "label": "Flickr"
        },
        {
            "tab": settingsTitle,
            "group": "Content",
            "name": "img_preview_imgur",
            "type": "checkbox",
            "label": "Imgur"
        },
        {
            "tab": settingsTitle,
            "group": "Content",
            "name": "img_preview_instagram",
            "type": "checkbox",
            "label": "Instagram"
        },
        {
            "tab": settingsTitle,
            "group": "Content",
            "name": "img_preview_tumblr",
            "type": "checkbox",
            "label": "Tumblr"
        },
        {
            "tab": settingsTitle,
            "group": "Content",
            "name": "img_preview_vimeo",
            "type": "checkbox",
            "label": "Vimeo"
        }
    ]
};
<|endoftext|>


<commit_before>import React from "react";

import Container from "./Container.js";
import Button from "./../Shared/Button.js";

import setCurrentScreenAction from "../../actions/ScreenActions.js";
import { GAME_SCREEN } from "../../actions/ScreenActions.js";

import {setGameModeAction} from "../../actions/GameActions.js";
import {VS_HUMAN, EASY, MEDIUM, HARD} from "../../reducers/Game.js";

const screenTitle = "Tic Tac Toe React";

const MenuScreen = (props) => {
  let headerStyle = {
    textAlign: "center",
    color: "white"
  };

  return (
    <Container>

        {screenTitle}

      <Button onClick={() => {
              props.dispatch(setCurrentScreenAction(GAME_SCREEN))
              props.dispatch(setGameModeAction(VS_HUMAN));
            }
          }
          text="Play with Human"
          useWrapper
      />

        {"Play with computer"}

      <Button onClick={() => {
              props.dispatch(setCurrentScreenAction(GAME_SCREEN))
              props.dispatch(setGameModeAction(EASY));
            }
          }
          text="EASY"
          useWrapper
      />
      <Button onClick={() => {
              props.dispatch(setCurrentScreenAction(GAME_SCREEN))
              props.dispatch(setGameModeAction(MEDIUM));
            }
          }
          text="MEDIUM"
          useWrapper
      />
      <Button onClick={() => {
              props.dispatch(setCurrentScreenAction(GAME_SCREEN))
              props.dispatch(setGameModeAction(HARD));
            }
          }
          text="HARD"
          useWrapper
      />
    </Container>
  );
};

MenuScreen.propTypes = {
  dispatch: React.PropTypes.func.isRequired
}

export default MenuScreen;
<commit_msg>Convert stateless component to react composite component using ES6 class<commit_after>import React from "react";

import Container from "./Container.js";
import Button from "./../Shared/Button.js";

import setCurrentScreenAction from "../../actions/ScreenActions.js";
import { GAME_SCREEN } from "../../actions/ScreenActions.js";

import {setGameModeAction} from "../../actions/GameActions.js";
import {VS_HUMAN, EASY, MEDIUM, HARD} from "../../reducers/Game.js";

const screenTitle = "Tic Tac Toe React";

class MenuScreen extends React.Component {
  render() {
    return (
      <Container>

          {screenTitle}

        <Button onClick={() => {
                this.props.dispatch(setCurrentScreenAction(GAME_SCREEN))
                this.props.dispatch(setGameModeAction(VS_HUMAN));
              }
            }
            text="Play with Human"
            useWrapper
        />

          {"Play with computer"}

        <Button onClick={() => {
                this.props.dispatch(setCurrentScreenAction(GAME_SCREEN))
                this.props.dispatch(setGameModeAction(EASY));
              }
            }
            text="EASY"
            useWrapper
        />
        <Button onClick={() => {
                this.props.dispatch(setCurrentScreenAction(GAME_SCREEN))
                this.props.dispatch(setGameModeAction(MEDIUM));
              }
            }
            text="MEDIUM"
            useWrapper
        />
        <Button onClick={() => {
                this.props.dispatch(setCurrentScreenAction(GAME_SCREEN))
                this.props.dispatch(setGameModeAction(HARD));
              }
            }
            text="HARD"
            useWrapper
        />
      </Container>
    );
  }
}

let headerStyle = {
  textAlign: "center",
  color: "white"
};

MenuScreen.propTypes = {
  dispatch: React.PropTypes.func.isRequired
}

export default MenuScreen;
<|endoftext|>


<commit_before>$(function () {
    if ($('body').hasClass('compendium_landing_page')) {
        $('.js-print-chapters').click(function (e) {
            e.preventDefault();
            // addLoadingOverlay();

            var $chapters =  $('.chapter'),
            chapterLength = $chapters.length;

            $chapters.each(function (index) {
                // Synchronously adds div with id to get around Ajax working asynchronously
                $('main').append("

");

                var url = $(this).attr('href');

                // Set what content from each page we want to retrieve for printing
                var childIntro = ('.page-intro');
                var childContent = ('.page-content');

                // Get chapter content
                $.get(url, function (response) {
                    // Remove noscript tags around images, they break the charts when requested
                    var html = response.replace(/<\/noscript>/g, '').replace(//g, '');

                    // Add in print page breaks before each chapter and add to compendium landing page
                    var $response = $(html);
                    $response.find(childIntro).addClass('print--break-before').appendTo('#compendium-print' + index);
                    $response.find(childContent).appendTo('#compendium-print' + index);

                    chaptersComplete(index)
                });
            });

            // Tally number of chapters complete and print window when done
            function chaptersComplete(index) {
                if (index+1 == chapterLength) {
                    // Only open print window once all images are loaded
                    $('img').on('load', function() {
                        window.print();
                        location.reload();
                    });
                }
            }
        });
    }
});<commit_msg>Re-enable loading overlay<commit_after>$(function () {
    if ($('body').hasClass('compendium_landing_page')) {
        $('.js-print-chapters').click(function (e) {
            e.preventDefault();
            addLoadingOverlay();

            var $chapters =  $('.chapter'),
            chapterLength = $chapters.length;

            $chapters.each(function (index) {
                // Synchronously adds div with id to get around Ajax working asynchronously
                $('main').append("

");

                var url = $(this).attr('href');

                // Set what content from each page we want to retrieve for printing
                var childIntro = ('.page-intro');
                var childContent = ('.page-content');

                // Get chapter content
                $.get(url, function (response) {
                    // Remove noscript tags around images, they break the charts when requested
                    var html = response.replace(/<\/noscript>/g, '').replace(//g, '');

                    // Add in print page breaks before each chapter and add to compendium landing page
                    var $response = $(html);
                    $response.find(childIntro).addClass('print--break-before').appendTo('#compendium-print' + index);
                    $response.find(childContent).appendTo('#compendium-print' + index);

                    chaptersComplete(index)
                });
            });

            // Tally number of chapters complete and print window when done
            function chaptersComplete(index) {
                if (index+1 == chapterLength) {
                    // Only open print window once all images are loaded
                    $('img').on('load', function() {
                        window.print();
                        location.reload();
                    });
                }
            }
        });
    }
});<|endoftext|>


<commit_before>"use strict";

var path = require("path");

module.exports = {
    // Path to css, js and img folders
    root: path.resolve("./"),
    // Path to build folder
    buildPath: function() { return path.join(this.root, "builds"); },
    // Beep on error
    beep: true,
    // Folders to exclude for watch and jshint (optionla)
    jsFoldersToExclude: [ "node_modules" ],
    // Folders to copy to the build folder (optional)
    jsFoldersToCopy: [],
    // Proxy used with browser sync, examples local.dev, localhost:8888 (optional)
    proxy: ""
};
<commit_msg>Changed variable names<commit_after>"use strict";

var path = require("path");

module.exports = {
    // Path to css, js and img folders
    root: path.resolve("./"),
    // Path to build folder
    buildPath: function() { return path.join(this.root, "builds"); },
    // Beep on error
    beep: true,
    // Folders to exclude for watch and jshint (optional)
    excludedFolders: [ "node_modules" ],
    // Folders to copy to the build folder (optional). You probably want "fonts"
    foldersToCopy: [],
    // Proxy used with browser sync, examples local.dev, localhost:8888 (optional)
    proxy: ""
};
<|endoftext|>


<commit_before>import React from 'react';
import { ThemeProvider } from 'styled-components';
import { storiesOf } from '@storybook/react';
import { text, select, boolean } from '@storybook/addon-knobs';
import { action } from '@storybook/addon-actions';
import OptionsHelper from '../../utils/helpers/options-helper';
import { notes, Info, InfoClassic } from './documentation';
import Button, { OriginalButton } from '.';
import classic from '../../style/themes/classic';
import getDocGenInfo from '../../utils/helpers/docgen-info';

OriginalButton.__docgenInfo = getDocGenInfo(
  require('./docgenInfo.json'),
  /button\.component(?!spec)/
);

const getIconKnobs = () => {
  const defaultPosition = Button.defaultProps.iconPosition;
  const hasIcon = boolean('has icon', false);

  return {
    iconType: hasIcon ? select('iconType', [...OptionsHelper.icons, ''], '') : undefined,
    iconPosition: hasIcon ? select('iconPosition', [...OptionsHelper.buttonIconPositions], defaultPosition) : undefined
  };
};

const getKnobs = (isClassic) => {
  const size = select('size', OptionsHelper.sizesRestricted, Button.defaultProps.size);
  let classicProps = {}, buttonType;

  if (isClassic) {
    classicProps = {
      theme: select('theme', OptionsHelper.buttonColors, Button.defaultProps.theme),
      as: select('as', OptionsHelper.themesBinary, Button.defaultProps.as),
      href: text('href'),
      to: text('to')
    };
  } else {
    buttonType = select('buttonType', OptionsHelper.buttonTypes, Button.defaultProps.as);
  }

  return {
    buttonType,
    children: text('children', 'Example Button'),
    disabled: boolean('disabled', Button.defaultProps.disabled),
    onClick: ev => action('click')(ev),
    size,
    subtext: (size === OptionsHelper.sizesRestricted[2]) ? text('subtext', Button.defaultProps.subtext) : undefined,
    ...classicProps,
    ...getIconKnobs()
  };
};

storiesOf('Button', module)
  .add('default', () => {
    const props = getKnobs();
    const { children } = props;
    return (
      <OriginalButton
        { ...props }
      >
        { children }
      </OriginalButton>
    );
  }, {
    info: { text: Info },
    notes: { markdown: notes },
    knobs: {
      escapeHTML: false
    }
  })
  .add('classic', () => {
    const props = getKnobs(true);
    const { children } = props;
    return (
      <ThemeProvider theme={ classic }>
        <OriginalButton
          { ...props }
        >
          { children }
        </OriginalButton>
      </ThemeProvider>
    );
  }, {
    info: { text: InfoClassic },
    notes: { markdown: notes },
    knobs: {
      escapeHTML: false
    }
  })
  .add('as a sibling', () => {
    const props = getKnobs();
    const { children } = props;
    return (

        <OriginalButton
          { ...props }
        >
          { children }
        </OriginalButton>

        <OriginalButton
          { ...props }
        >
          { children }
        </OriginalButton>

    );
  });
<commit_msg>(FE-1527) Update button.stories.js<commit_after>import React from 'react';
import { storiesOf } from '@storybook/react';
import { text, select, boolean } from '@storybook/addon-knobs';
import { action } from '@storybook/addon-actions';
import { dlsThemeSelector, classicThemeSelector } from '../../../.storybook/theme-selectors';
import OptionsHelper from '../../utils/helpers/options-helper';
import { notes, Info, InfoClassic } from './documentation';
import Button, { OriginalButton } from '.';
import getDocGenInfo from '../../utils/helpers/docgen-info';

OriginalButton.__docgenInfo = getDocGenInfo(
  require('./docgenInfo.json'),
  /button\.component(?!spec)/
);

const getIconKnobs = () => {
  const defaultPosition = Button.defaultProps.iconPosition;
  const hasIcon = boolean('has icon', false);

  return {
    iconType: hasIcon ? select('iconType', [...OptionsHelper.icons, ''], '') : undefined,
    iconPosition: hasIcon ? select('iconPosition', [...OptionsHelper.buttonIconPositions], defaultPosition) : undefined
  };
};

const getKnobs = (isClassic) => {
  const size = select('size', OptionsHelper.sizesRestricted, Button.defaultProps.size);
  let classicProps = {}, buttonType;

  if (isClassic) {
    classicProps = {
      theme: select('theme', OptionsHelper.buttonColors, Button.defaultProps.theme),
      as: select('as', OptionsHelper.themesBinary, Button.defaultProps.as),
      href: text('href'),
      to: text('to')
    };
  } else {
    buttonType = select('buttonType', OptionsHelper.buttonTypes, Button.defaultProps.as);
  }

  return {
    buttonType,
    children: text('children', 'Example Button'),
    disabled: boolean('disabled', Button.defaultProps.disabled),
    onClick: ev => action('click')(ev),
    size,
    subtext: (size === OptionsHelper.sizesRestricted[2]) ? text('subtext', Button.defaultProps.subtext) : undefined,
    ...classicProps,
    ...getIconKnobs()
  };
};

storiesOf('Button', module)
  .add('default', () => {
    const props = getKnobs();
    const { children } = props;
    return (
      <OriginalButton
        { ...props }
      >
        { children }
      </OriginalButton>
    );
  }, {
    info: { text: Info },
    notes: { markdown: notes },
    themeSelector: dlsThemeSelector,
    knobs: {
      escapeHTML: false
    }
  })
  .add('classic', () => {
    const props = getKnobs(true);
    const { children } = props;
    return (
      <OriginalButton
        { ...props }
      >
        { children }
      </OriginalButton>
    );
  }, {
    info: { text: InfoClassic },
    notes: { markdown: notes },
    themeSelector: classicThemeSelector,
    knobs: {
      escapeHTML: false
    }
  })
  .add('as a sibling', () => {
    const props = getKnobs();
    const { children } = props;
    return (

        <OriginalButton
          { ...props }
        >
          { children }
        </OriginalButton>

        <OriginalButton
          { ...props }
        >
          { children }
        </OriginalButton>

    );
  }, {
    themeSelector: dlsThemeSelector
  });
<|endoftext|>


<commit_before>var chug = require('gulp-chug');
var server = require('gulp-express');
var selenium = require('selenium-standalone');
var runSequence = require('run-sequence');

module.exports = function(gulp) {
  gulp.task('selenium', function(done) {
    selenium.install({
      logger: function() {}
    }, function(err) {
      if (err) {
        return done(err);
      }

      selenium.start(function(err, child) {
        if (err) {
          return done(err);
        }

        if (process.env.TRAVIS) {
          child.stderr.on('data', function(data) {
            console.log(data.toString());
          });
        }

        //saving the child to kill it later (oops)
        selenium.child = child;
        done();
      });
    });
  });

  gulp.task('dist:docs', function() {
    return gulp.src('./docs/gulpfile.js', {
      read: false
    }).pipe(chug({
      tasks: ['dist']
    }));
  });

  gulp.task('start:docs', function() {
    return server.run(['./examples/server/server.js']);
  });

  function killProcess() {
    selenium.child.kill();
    server.stop();
  }

  function runIntegration(platform, browserName, version) {
    process.env.E2E_PLATFORM = platform;
    process.env.E2E_BROWSER_NAME = browserName;
    process.env.E2E_BROWSER_VERSION = version;

    var mocha = require('gulp-mocha');
    return gulp.src('./e2e/**/*.js', {
      read: false
    }).pipe(mocha()).on('end', function() {
      killProcess();
    }).on('error', function() {
      killProcess();
      process.exit(1);
    });
  }

  /**
  ** Windows e2e matrix
  **/
  gulp.task('integration:windows:ie', ['start:docs', 'selenium'], function() {
    return runIntegration('Windows 7', 'internet explorer', '11.0');
  });

  gulp.task('integration:windows:chrome', ['start:docs', 'selenium'], function() {
    return runIntegration('Windows 7', 'chrome', '37.0');
  });

  gulp.task('integration:windows:firefox', ['start:docs', 'selenium'], function() {
    return runIntegration('Windows 7', 'firefox', '32.0');
  });

  gulp.task('integration:windows', function(done) {
    return runSequence('integration:windows:ie', 'integration:windows:chrome', 'integration:windows:firefox', done);
  });

  /**
  ** Linux e2e matrix
  **/
  gulp.task('integration:linux:firefox', ['start:docs', 'selenium'], function() {
    return runIntegration('Linux', 'firefox', '32.0');
  });

  gulp.task('integration:linux:opera', ['start:docs', 'selenium'], function() {
    return runIntegration('Linux', 'opera', '12.15');
  });

  gulp.task('integration:linux:chrome', ['start:docs', 'selenium'], function() {
    return runIntegration('Linux', 'chrome', '37.0');
  });

  gulp.task('integration:linux', function(done) {
    return runSequence('integration:linux:firefox', 'integration:linux:opera', 'integration:linux:chrome', done);
  });

  /**
  ** OSX e2e matrix
  **/
  gulp.task('integration:osx:firefox', ['start:docs', 'selenium'], function() {
    return runIntegration('OS X 10.10', 'firefox', '32.0');
  });

  gulp.task('integration:osx:safari', ['start:docs', 'selenium'], function() {
    return runIntegration('OS X 10.10', 'safari', '8.0');
  });

  gulp.task('integration:osx:chrome', ['start:docs', 'selenium'], function() {
    return runIntegration('OS X 10.10', 'chrome', '37.0');
  });

  gulp.task('integration:osx', function(done) {
    return runSequence('integration:osx:firefox', 'integration:osx:safari', 'integration:osx:chrome', done);
  });

  gulp.task('integration:localhost', ['start:docs', 'selenium'], function() {
    return runIntegration();
  });

};
<commit_msg>Add the dist docs again.<commit_after>var chug = require('gulp-chug');
var server = require('gulp-express');
var selenium = require('selenium-standalone');
var runSequence = require('run-sequence');

module.exports = function(gulp) {
  gulp.task('selenium', function(done) {
    selenium.install({
      logger: function() {}
    }, function(err) {
      if (err) {
        return done(err);
      }

      selenium.start(function(err, child) {
        if (err) {
          return done(err);
        }

        if (process.env.TRAVIS) {
          child.stderr.on('data', function(data) {
            console.log(data.toString());
          });
        }

        //saving the child to kill it later (oops)
        selenium.child = child;
        done();
      });
    });
  });

  gulp.task('dist:docs', function() {
    return gulp.src('./docs/gulpfile.js', {
      read: false
    }).pipe(chug({
      tasks: ['dist']
    }));
  });

  gulp.task('start:docs', ['dist:docs'], function() {
    return server.run(['./examples/server/server.js']);
  });

  function killProcess() {
    selenium.child.kill();
    server.stop();
  }

  function runIntegration(platform, browserName, version) {
    process.env.E2E_PLATFORM = platform;
    process.env.E2E_BROWSER_NAME = browserName;
    process.env.E2E_BROWSER_VERSION = version;

    var mocha = require('gulp-mocha');
    return gulp.src('./e2e/**/*.js', {
      read: false
    }).pipe(mocha()).on('end', function() {
      killProcess();
    }).on('error', function() {
      killProcess();
      process.exit(1);
    });
  }

  /**
  ** Windows e2e matrix
  **/
  gulp.task('integration:windows:ie', ['start:docs', 'selenium'], function() {
    return runIntegration('Windows 7', 'internet explorer', '11.0');
  });

  gulp.task('integration:windows:chrome', ['start:docs', 'selenium'], function() {
    return runIntegration('Windows 7', 'chrome', '37.0');
  });

  gulp.task('integration:windows:firefox', ['start:docs', 'selenium'], function() {
    return runIntegration('Windows 7', 'firefox', '32.0');
  });

  gulp.task('integration:windows', function(done) {
    return runSequence('integration:windows:ie', 'integration:windows:chrome', 'integration:windows:firefox', done);
  });

  /**
  ** Linux e2e matrix
  **/
  gulp.task('integration:linux:firefox', ['start:docs', 'selenium'], function() {
    return runIntegration('Linux', 'firefox', '32.0');
  });

  gulp.task('integration:linux:opera', ['start:docs', 'selenium'], function() {
    return runIntegration('Linux', 'opera', '12.15');
  });

  gulp.task('integration:linux:chrome', ['start:docs', 'selenium'], function() {
    return runIntegration('Linux', 'chrome', '37.0');
  });

  gulp.task('integration:linux', function(done) {
    return runSequence('integration:linux:firefox', 'integration:linux:opera', 'integration:linux:chrome', done);
  });

  /**
  ** OSX e2e matrix
  **/
  gulp.task('integration:osx:firefox', ['start:docs', 'selenium'], function() {
    return runIntegration('OS X 10.10', 'firefox', '32.0');
  });

  gulp.task('integration:osx:safari', ['start:docs', 'selenium'], function() {
    return runIntegration('OS X 10.10', 'safari', '8.0');
  });

  gulp.task('integration:osx:chrome', ['start:docs', 'selenium'], function() {
    return runIntegration('OS X 10.10', 'chrome', '37.0');
  });

  gulp.task('integration:osx', function(done) {
    return runSequence('integration:osx:firefox', 'integration:osx:safari', 'integration:osx:chrome', done);
  });

  gulp.task('integration:localhost', ['start:docs', 'selenium'], function() {
    return runIntegration();
  });

};
<|endoftext|>


<commit_before>// dependencies
//
import React from 'react';
import uniqueId from 'lodash/uniqueId';
import classnames from 'classnames';

/**
 * The RadioButtonGroup component
 */
class RadioButtonGroup extends React.Component {
    /**
     * Construct the component instance
     * @param  {Object} props The component props
     */
    constructor(props) {
        super(props);

        // generate a unique ID for this element (used to tie the label to the
        // input elements)
        //
        this.id = uniqueId('form-radiobuttongroup-');

        // build a list of permitted values from the options
        //
        this.permittedValues = this.props.options.map((opt) => `${opt.value}`);

        // initialize the component state
        //
        this.state = {
            value: this.isPermittedValue(this.props.value)
                ? `${this.props.value}`
                : `${this.props.options[0].value}`,
        };

        // bind `this` to the onChange event handler
        //
        this.onChange = this.onChange.bind(this);
    }

    /**
     * Handle a change to the input elements
     * @param  {Object} event The event object
     */
    onChange(event) {
        // get the current value & make sure it's a string
        //
        const value = `${event.target.value}`;

        // has the value changed? if so, then update the state & call the
        // onChange handler
        //
        if (value !== this.state.value) {
            // update the component state
            //
            this.setState({ value });

            // do we have an onChange handler? if so, call it
            //
            if (this.props.onChange) {
                this.props.onChange(value);
            }
        }
    }

    /**
     * Check a value to see if it's one of the permitted values
     * @param  {String}  value The value to check
     * @return {Boolean}       True if it's a permitted value; false otherwise
     */
    isPermittedValue(value) {
        return this.permittedValues.findIndex((val) => val === `${value}`) !== -1;
    }

    /**
     * Render the component
     * @return {React.Element} The React element describing the component
     */
    render() {
        // get the important values from the component properties
        //
        const { label, options } = this.props;

        const labelElement = label
            ? (<label
                    htmlFor={this.id}
                    className="radiobuttongroup"
                    className={classnames('radiobuttongroup', {
                        [`col-xs-${this.context.labelColumns}`]: this.context.labelColumns,
                    })}
                >{label})
            : null

        // render the component & return it
        //
        return (

                {labelElement}

                {options.map((opt) => (

                            <input
                                type="radio"
                                name={this.id}
                                value={opt.value}
                                checked={this.state.value === opt.value}
                                onChange={this.onChange}
                            />
                            {opt.name}

                ))}

        );
    }
}

// define the property types for the component
//
RadioButtonGroup.propTypes = {
    label:    React.PropTypes.string,
    options:  React.PropTypes.array,
    value:    React.PropTypes.oneOfType([
        React.PropTypes.string,
        React.PropTypes.number,
    ]),
    onChange: React.PropTypes.func,
};

// export the component
//
export default RadioButtonGroup;
<commit_msg>added context types for radiobutton group<commit_after>// dependencies
//
import React from 'react';
import uniqueId from 'lodash/uniqueId';
import classnames from 'classnames';

/**
 * The RadioButtonGroup component
 */
class RadioButtonGroup extends React.Component {
    /**
     * Construct the component instance
     * @param  {Object} props The component props
     */
    constructor(props) {
        super(props);

        // generate a unique ID for this element (used to tie the label to the
        // input elements)
        //
        this.id = uniqueId('form-radiobuttongroup-');

        // build a list of permitted values from the options
        //
        this.permittedValues = this.props.options.map((opt) => `${opt.value}`);

        // initialize the component state
        //
        this.state = {
            value: this.isPermittedValue(this.props.value)
                ? `${this.props.value}`
                : `${this.props.options[0].value}`,
        };

        // bind `this` to the onChange event handler
        //
        this.onChange = this.onChange.bind(this);
    }

    /**
     * Handle a change to the input elements
     * @param  {Object} event The event object
     */
    onChange(event) {
        // get the current value & make sure it's a string
        //
        const value = `${event.target.value}`;

        // has the value changed? if so, then update the state & call the
        // onChange handler
        //
        if (value !== this.state.value) {
            // update the component state
            //
            this.setState({ value });

            // do we have an onChange handler? if so, call it
            //
            if (this.props.onChange) {
                this.props.onChange(value);
            }
        }
    }

    /**
     * Check a value to see if it's one of the permitted values
     * @param  {String}  value The value to check
     * @return {Boolean}       True if it's a permitted value; false otherwise
     */
    isPermittedValue(value) {
        return this.permittedValues.findIndex((val) => val === `${value}`) !== -1;
    }

    /**
     * Render the component
     * @return {React.Element} The React element describing the component
     */
    render() {
        // get the important values from the component properties
        //
        const { label, options } = this.props;

        const labelElement = label
            ? (<label
                    htmlFor={this.id}
                    className="radiobuttongroup"
                    className={classnames('radiobuttongroup', {
                        [`col-xs-${this.context.labelColumns}`]: this.context.labelColumns,
                    })}
                >{label})
            : null

        // render the component & return it
        //
        return (

                {labelElement}

                {options.map((opt) => (

                            <input
                                type="radio"
                                name={this.id}
                                value={opt.value}
                                checked={this.state.value === opt.value}
                                onChange={this.onChange}
                            />
                            {opt.name}

                ))}

        );
    }
}

// define the property types for the component
//
RadioButtonGroup.propTypes = {
    label:    React.PropTypes.string,
    options:  React.PropTypes.array,
    value:    React.PropTypes.oneOfType([
        React.PropTypes.string,
        React.PropTypes.number,
    ]),
    onChange: React.PropTypes.func,
};

// set the context types for values received from higher up the food chain
//
RadioButtonGroup.contextTypes = {
    labelColumns:           React.PropTypes.number,
};

// export the component
//
export default RadioButtonGroup;
<|endoftext|>


<commit_before>/* eslint-disable no-use-before-define */
import defer from 'lodash.defer';

import suppress from '../suppress/suppress';
import drawToolConfig from './draw-tool-config';

const DrawTool = () => {
  // holds all information about the state of the shape being created or edited
  const DEFAULTS = {
    isConsistent: true,
    type: null,
    layer: null,
    markers: [],
    markersPrev: [],
    markersMaxCount: drawToolConfig.MAX_MARKERS,
    area: 0,
    areaTxt: '',
    distance: 0,
    distanceTxt: ''
  };

  let currentShape = { ...DEFAULTS };

  // holds all publicly available information about the last consistent state of the current shape
  const shapeInfo = {};
  updateShapeInfo(currentShape); // initialise to initial current shape

  // holds all information of the leaflet.draw drawing and editing structures
  const drawTool = {
    drawingMode: drawToolConfig.DRAWING_MODE.NONE,
    drawnItems: null,
    drawShapeHandler: null,
    editShapeHandler: null,
    lastEvent: null,
    timeout: null
  };

  // these callback methods will be called on a finished polygon and on a change of drawing mode
  let _onFinishPolygon,
    _onDrawingMode,
    _onUpdateShape;

  return {
    initialize,
    isEnabled,
    enable,
    disable,
    cancel,
    setPolygon,
    shape: shapeInfo
  };

  // initialise factory; initialise draw tool, register callback methods and register events
  function initialize(map, onFinish, onDrawingMode, onUpdateShape) {
    currentShape = { ...DEFAULTS };

    initDrawTool(map);
    _onFinishPolygon = onFinish; // callback method to call on finish draw/edit polygon
    _onDrawingMode = onDrawingMode; // callback method to call on change of drawing mode
    _onUpdateShape = onUpdateShape; // callback method to call on change of shape

    registerDrawEvents();
    registerMapEvents();
  }

  // triggered when a polygon has finished drawing or editing
  function onFinishPolygon() {
    if (typeof _onFinishPolygon === 'function') {
      // call any registered callback function, applyAsync because triggered by a leaflet event
      _onFinishPolygon(shapeInfo);
    }
  }

  // triggered when a polygon has changed to a new valid state
  function onChangePolygon() {
    // add class to drawn polygon
    if (currentShape.layer && currentShape.layer._path) {
      L.DomUtil.addClass(currentShape.layer._path, 'c-map__leaflet-drawn-polygon');
    }

    // update the publicly available shape info, applyAsync because triggered by a leaflet event
    updateShapeInfo();
    // triggered when the drawing mode has changed
    if (typeof _onDrawingMode === 'function') {
      // call any registered callback function, applyAsync because triggered by a leaflet event
      _onDrawingMode(drawTool.drawingMode);
    }
  }

  // Construct a polygon from a array of coordinates
  function setPolygon(latLngs) {
    deletePolygon(); // delete any existing polygon
    if (latLngs.length > 0) {
      createPolygon(new L.Polygon(latLngs));
    }
    updateShape();
  }

  // Delete an existing polygon
  function deletePolygon() {
    if (currentShape.layer) {
      currentShape.layer.off('click', toggleEditModeOnShapeClick);
      drawTool.drawnItems.removeLayer(currentShape.layer);
      drawTool.map.fire(L.Draw.Event.DELETED, {
        layers: currentShape.layer
      });
      currentShape.layer = null; // No current layer after delete polygon
    }
  }

  // Create a new polygon by registering the layer, show the layer and register a click
  // handler to start/end edit
  function createPolygon(layer) {
    currentShape.layer = layer;
    drawTool.drawnItems.addLayer(layer);
    layer.on('click', toggleEditModeOnShapeClick);
  }

  // Called when a polygon is finished (end draw or end edit)
  function finishPolygon() {
    // Silently change the drawing mode
    setDrawingMode(drawToolConfig.DRAWING_MODE.NONE);
    onFinishPolygon();
  }

  // updates the drawing mode and trigger any callback method
  function setDrawingMode(drawingMode) {
    if (drawTool.drawingMode !== drawingMode) {
      drawTool.drawingMode = drawingMode;
      _onDrawingMode(drawingMode);
    }
  }

  // Initialisation of the draw tool, initialise drawing and register required objects
  // in the drawTool object
  function initDrawTool(map) {
    L.drawLocal.format = drawToolConfig.format;

    drawTool.map = map;
    drawTool.drawnItems = new L.FeatureGroup();
    drawTool.drawShapeHandler = new L.Draw.Polygon(drawTool.map, drawToolConfig.draw.polygon);

    const editConfig = {...drawToolConfig.edit};
    editConfig.featureGroup = drawTool.drawnItems;
    const editToolbar = new L.EditToolbar(editConfig);

    drawTool.editShapeHandler = editToolbar.getModeHandlers(drawTool.map)[0].handler;

    drawTool.map.addLayer(drawTool.drawnItems);
  }

  // enforce the maximum markers limit and the non-intersection of line segments limit
  function enforceLimits() {
    if (!currentShape.isConsistent) {
      const markersPrev = {...currentShape.markersPrev}; // restore previous state

      deletePolygon(); // delete current polygon

      defer(() => {
        setPolygon(markersPrev); // restore previous polygon
        updateShape();
      });
    } else {
      // check for auto close of shape in drawing mode
      autoClose();
    }
  }

  // Auto close polygon when in drawing mode and max markers has been reached
  function autoClose() {
    if (drawTool.drawingMode === drawToolConfig.DRAWING_MODE.DRAW &&
      currentShape.markers.length === currentShape.markersMaxCount) {
        defer(() => {
          disable();
        });
    }
  }

  // handle any leaflet.draw event
  function handleDrawEvent(eventName, e) {
    const handlers = {
      // Triggered when the user has chosen to draw a particular vector or marker
      DRAWSTART: () => setDrawingMode(drawToolConfig.DRAWING_MODE.DRAW),

      // Triggered when a vertex is created on a polyline or polygon
      DRAWVERTEX: bindLastDrawnMarker,

      // Triggered when a new vector or marker has been created
      CREATED: () => {
        createPolygon(e.layer);
        finishPolygon();
      },

      // Triggered when the user starts edit mode by clicking the edit tool button
      EDITSTART: () => setDrawingMode(drawToolConfig.DRAWING_MODE.EDIT),

      // Triggered when the user has finshed editing (edit mode) and saves edits
      EDITSTOP: finishPolygon,

      // Triggered when layers have been removed (and saved) from the FeatureGroup
      DELETED: () => currentShape.layer = null
    };

    const handler = handlers[eventName];
    if (handler) {
      handler(e);
    }

    drawTool.lastEvent = eventName;
  }

  // Every leaflet.draw event is catched, thereby taking care that the shape is always up-to-date,
  // that all limits are respected and that the last consistent state gets exposed by the
  // drawing tool
  function registerDrawEvents() {
    Object.keys(L.Draw.Event).forEach(eventName => {
      drawTool.map.on(L.Draw.Event[eventName], function(e) {
        if (eventName === 'DELETED') { // IE HACK
          suppress.start(300);
        }

        handleDrawEvent(eventName, e);

        updateShape(); // Update current shape and tooltip

        defer(() => {
          // Force Leaflet to enable TextSelection (tg-2728)
          L.DomUtil.enableTextSelection();

          // Execute this code after leaflet.draw has finished the event
          enforceLimits(); // max vertices, auto close when max reached
          if (currentShape.isConsistent) {
            onChangePolygon(); // trigger change on new consistent state of the polygon
          }
        });
      });
    });
  }

  // register any non-leaflet.draw events
  function registerMapEvents() {
    // Click outside shape => delete shape
    drawTool.map.on('click', function() {
      if (suppress.isBusy()) {
        return;
      }

      // In edit mode => disable()
      if (drawTool.drawingMode === drawToolConfig.DRAWING_MODE.EDIT) {
        disable();
      } else if (drawTool.drawingMode !== drawToolConfig.DRAWING_MODE.DRAW && currentShape.layer) {
        // If not in Draw or EDIT mode and a polygon exists
        // then the current polygon gets deleted
        // Note: In draw mode the click on map adds a new marker
        deletePolygon();
        updateShape();
        onFinishPolygon();
        disable();
      }
    });
  }

  // Click on the shape toggles EDIT mode
  function toggleEditModeOnShapeClick(e) {
    if (suppress.isBusy()) {
      return;
    }
    L.DomEvent.stop(e);
    toggle();
  }

  // toggle between draw/edit (enable) and show mode (null)
  function toggle() {
    return isEnabled() ? disable() : enable();
  }

  function isEnabled() {
    // isEnabled => shape is being created or being edited
    return drawTool.drawingMode !== drawToolConfig.DRAWING_MODE.NONE;
  }

  // start draw or edit mode for current layer or start create mode for new shape
  // the outside only knows enabled or disabled, internally the mode is further defined
  // in DRAW or EDIT
  function enable() {
    if (!isEnabled()) {
      if (currentShape.layer) { // Shape exists, start edit
        drawTool.editShapeHandler.enable();
      } else { // Shape does not yet exist, start draw
        drawTool.drawShapeHandler.enable();
      }
    }
  }

  // end of draw or edit mode => in create mode complete shape, in edit mode save shape
  function disable() {
    if (isEnabled()) {
      if (drawTool.drawingMode === drawToolConfig.DRAWING_MODE.DRAW) {
        if (currentShape.markers.length > 1) {
          // Close the polyline between the first and last points
          drawTool.drawShapeHandler.completeShape();
        } else {
          drawTool.drawShapeHandler.disable();
        }
      } else {
        drawTool.editShapeHandler.save(); // Save the layer geometries
        drawTool.editShapeHandler.disable();
      }
      setDrawingMode(drawToolConfig.DRAWING_MODE.NONE);
    }
  }

  // Cancel drawing => disable the draw tool and do not save anything
  // that has been drawn
  function cancel() {
    if (isEnabled()) {
      if (drawTool.drawingMode === drawToolConfig.DRAWING_MODE.DRAW) {
        drawTool.drawShapeHandler.disable();
      } else {
        drawTool.editShapeHandler.disable();
      }
      // Silently change the drawing mode
      setDrawingMode(drawToolConfig.DRAWING_MODE.NONE);
    }
  }

  // Shape method for shape.info
  // while drawing the polygon is not closed => distance is distance of the lines
  // When editing the polygon is closed => distance is surrounding
  // When only tow points => distance is line lenght
  function getDistance(latLngs, isClosed) {
    return latLngs.reduce((total, latlng, i) => {
      if (i > 0) {
        const dist = latlng.distanceTo(latLngs[i - 1]);
        total += dist;
      }
      return total;
    }, isClosed && latLngs.length > 2 ? latLngs[0].distanceTo(latLngs[latLngs.length - 1]) : 0);
  }

  // Update the internal information about the current shape
  function updateShape() {
    const DISTANCE_IN_KILOMETERS = 1000; // Show in km starting from this #meters, else show in m

    let latLngs = [],
      area = 0,
      distance = 0,
      intersects = false;

    if (currentShape.layer) {
      latLngs = currentShape.layer.getLatLngs()[0];
      distance = getDistance(latLngs, true);
      area = L.GeometryUtil.geodesicArea(latLngs);
      intersects = currentShape.layer.intersects();
    } else if (drawTool.drawShapeHandler._markers && drawTool.drawShapeHandler._markers.length > 0) {
      latLngs = drawTool.drawShapeHandler._markers.map(m => m._latlng);
      area = drawTool.drawShapeHandler._area;
      distance = getDistance(latLngs, false);
    }

    currentShape.markersPrev = {...currentShape.markers};
    currentShape.markers = latLngs.map(({
      lat,
      lng
    }) => [lat, lng]);
    currentShape.area = area;
    currentShape.areaTxt = L.GeometryUtil.readableArea(
      area,
      drawToolConfig.draw.polygon.metric,
      drawToolConfig.draw.polygon.precision
    );
    currentShape.distance = distance;
    if (distance >= DISTANCE_IN_KILOMETERS) {
      currentShape.distanceTxt = L.GeometryUtil.formattedNumber(distance / DISTANCE_IN_KILOMETERS, 2) + ' km';
    } else {
      currentShape.distanceTxt = L.GeometryUtil.formattedNumber(distance, 1) + ' m';
    }
    currentShape.intersects = intersects;

    currentShape.isConsistent = !(
      currentShape.markers.length > currentShape.markersMaxCount || currentShape.intersects
    );

    if (currentShape.isConsistent) {
      L.drawLocal.edit.handlers.edit.tooltip.text = currentShape.areaTxt;
      L.drawLocal.edit.handlers.edit.tooltip.subtext = currentShape.distanceTxt;
      updateShapeInfo(); // update public shape info of new consistent state of the polygon
    }

    if (currentShape.isConsistent && typeof _onUpdateShape === 'function') {
      // call any registered callback function, applyAsync because triggered by a leaflet event
      _onUpdateShape(currentShape);
    }
  }

  // Updates the publicly available info for the current shape
  // Only to be called when shape is in a consistent state
  function updateShapeInfo() {
    // Copy a set of properties of the current shape into the shapeInfo object
    ['type', 'markers', 'markersMaxCount', 'area', 'areaTxt', 'distance', 'distanceTxt']
    .forEach(key => {
      shapeInfo[key] = currentShape[key];
    });
  }

  // delete a marker in DRAW mode
  function deleteMarker(marker) {
    const drawShapeHandler = drawTool.drawShapeHandler;
    const markers = drawShapeHandler._markers; // is always an array
    const index = markers.findIndex(m => m._leaflet_id === marker._leaflet_id);
    let nDelete = markers.length - index; // Delete all from last to marker, inclusive
    while (nDelete-- > 0) {
      // Remove the last vertex from the polyline, removes polyline from map if only one point exists
      drawShapeHandler.deleteLastVertex();
    }
  }

  // returns the last marker that was added to the polygon (only called in draw mode)
  function getLastDrawnMarker() {
    const drawShapeHandler = drawTool.drawShapeHandler;
    return drawShapeHandler._markers[drawShapeHandler._markers.length - 1];
  }

  // bind last marker in DRAW mode to deleteMarker
  // bind first marker in DRAW mode to close polygon (by calling disable())
  function bindLastDrawnMarker() {
    const lastMarker = getLastDrawnMarker();
    const isFirstMarker = drawTool.drawShapeHandler._markers.length === 1;

    suppress.start(300);
    ['mousedown', 'click'].forEach(key => lastMarker.on(key, (e) => {
      if (suppress.isBusy()) {
        return;
      }

      if (drawTool.drawShapeHandler.enabled() && isFirstMarker) {
        const isLineOrPolygon = currentShape.markers.length > 1;
        disable(); // Includes auto close for any line or polygon
        if (!isLineOrPolygon) {
          // Reopen draw mode to place first marker somewhere else
          enable();
        }
      } else {
        deleteMarker(lastMarker);
      }
    }));
  }
};

export default DrawTool();
/* eslint-enable no-use-before-define */
<commit_msg>eslint DP-4947<commit_after>/* eslint-disable no-use-before-define,no-underscore-dangle */
/* global L */

import defer from 'lodash.defer';

import suppress from '../suppress/suppress';
import drawToolConfig from './draw-tool-config';

const DrawTool = () => {
  // holds all information about the state of the shape being created or edited
  const DEFAULTS = {
    isConsistent: true,
    type: null,
    layer: null,
    markers: [],
    markersPrev: [],
    markersMaxCount: drawToolConfig.MAX_MARKERS,
    area: 0,
    areaTxt: '',
    distance: 0,
    distanceTxt: ''
  };

  let currentShape = { ...DEFAULTS };

  // holds all publicly available information about the last consistent state of the current shape
  const shapeInfo = {};
  updateShapeInfo(currentShape); // initialise to initial current shape

  // holds all information of the leaflet.draw drawing and editing structures
  const drawTool = {
    drawingMode: drawToolConfig.DRAWING_MODE.NONE,
    drawnItems: null,
    drawShapeHandler: null,
    editShapeHandler: null,
    lastEvent: null,
    timeout: null
  };

  // these callback methods will be called on a finished polygon and on a change of drawing mode
  let _onFinishPolygon;
  let _onDrawingMode;
  let _onUpdateShape;

  return {
    initialize,
    isEnabled,
    enable,
    disable,
    cancel,
    setPolygon,
    shape: shapeInfo
  };

  // initialise factory; initialise draw tool, register callback methods and register events
  function initialize(map, onFinish, onDrawingMode, onUpdateShape) {
    currentShape = { ...DEFAULTS };

    initDrawTool(map);
    _onFinishPolygon = onFinish; // callback method to call on finish draw/edit polygon
    _onDrawingMode = onDrawingMode; // callback method to call on change of drawing mode
    _onUpdateShape = onUpdateShape; // callback method to call on change of shape

    registerDrawEvents();
    registerMapEvents();
  }

  // triggered when a polygon has finished drawing or editing
  function onFinishPolygon() {
    if (typeof _onFinishPolygon === 'function') {
      // call any registered callback function, applyAsync because triggered by a leaflet event
      _onFinishPolygon(shapeInfo);
    }
  }

  // triggered when a polygon has changed to a new valid state
  function onChangePolygon() {
    // add class to drawn polygon
    if (currentShape.layer && currentShape.layer._path) {
      L.DomUtil.addClass(currentShape.layer._path, 'c-map__leaflet-drawn-polygon');
    }

    // update the publicly available shape info, applyAsync because triggered by a leaflet event
    updateShapeInfo();
    // triggered when the drawing mode has changed
    if (typeof _onDrawingMode === 'function') {
      defer(() => {});
      // call any registered callback function, applyAsync because triggered by a leaflet event
      _onDrawingMode(drawTool.drawingMode);
    }
  }

  // Construct a polygon from a array of coordinates
  function setPolygon(latLngs) {
    deletePolygon(); // delete any existing polygon
    if (latLngs.length > 0) {
      createPolygon(new L.Polygon(latLngs));
    }
    updateShape();
  }

  // Delete an existing polygon
  function deletePolygon() {
    if (currentShape.layer) {
      currentShape.layer.off('click', toggleEditModeOnShapeClick);
      drawTool.drawnItems.removeLayer(currentShape.layer);
      drawTool.map.fire(L.Draw.Event.DELETED, {
        layers: currentShape.layer
      });
      currentShape.layer = null; // No current layer after delete polygon
    }
  }

  // Create a new polygon by registering the layer, show the layer and register a click
  // handler to start/end edit
  function createPolygon(layer) {
    currentShape.layer = layer;
    drawTool.drawnItems.addLayer(layer);
    layer.on('click', toggleEditModeOnShapeClick);
  }

  // Called when a polygon is finished (end draw or end edit)
  function finishPolygon() {
    // Silently change the drawing mode
    setDrawingMode(drawToolConfig.DRAWING_MODE.NONE);
    onFinishPolygon();
  }

  // updates the drawing mode and trigger any callback method
  function setDrawingMode(drawingMode) {
    if (drawTool.drawingMode !== drawingMode) {
      drawTool.drawingMode = drawingMode;
      _onDrawingMode(drawingMode);
    }
  }

  // Initialisation of the draw tool, initialise drawing and register required objects
  // in the drawTool object
  function initDrawTool(map) {
    L.drawLocal.format = drawToolConfig.format;

    drawTool.map = map;
    drawTool.drawnItems = new L.FeatureGroup();
    drawTool.drawShapeHandler = new L.Draw.Polygon(drawTool.map, drawToolConfig.draw.polygon);

    const editConfig = { ...drawToolConfig.edit };
    editConfig.featureGroup = drawTool.drawnItems;
    const editToolbar = new L.EditToolbar(editConfig);

    drawTool.editShapeHandler = editToolbar.getModeHandlers(drawTool.map)[0].handler;

    drawTool.map.addLayer(drawTool.drawnItems);
  }

  // enforce the maximum markers limit and the non-intersection of line segments limit
  function enforceLimits() {
    if (!currentShape.isConsistent) {
      const markersPrev = { ...currentShape.markersPrev }; // restore previous state

      deletePolygon(); // delete current polygon

      defer(() => {
        setPolygon(markersPrev); // restore previous polygon
        updateShape();
      });
    } else {
      // check for auto close of shape in drawing mode
      autoClose();
    }
  }

  // Auto close polygon when in drawing mode and max markers has been reached
  function autoClose() {
    if (drawTool.drawingMode === drawToolConfig.DRAWING_MODE.DRAW &&
      currentShape.markers.length === currentShape.markersMaxCount) {
      defer(() => disable());
    }
  }

  // handle any leaflet.draw event
  function handleDrawEvent(eventName, e) {
    const handlers = {
      // Triggered when the user has chosen to draw a particular vector or marker
      DRAWSTART: () => setDrawingMode(drawToolConfig.DRAWING_MODE.DRAW),

      // Triggered when a vertex is created on a polyline or polygon
      DRAWVERTEX: bindLastDrawnMarker,

      // Triggered when a new vector or marker has been created
      CREATED: () => {
        createPolygon(e.layer);
        finishPolygon();
      },

      // Triggered when the user starts edit mode by clicking the edit tool button
      EDITSTART: () => setDrawingMode(drawToolConfig.DRAWING_MODE.EDIT),

      // Triggered when the user has finshed editing (edit mode) and saves edits
      EDITSTOP: finishPolygon,

      // Triggered when layers have been removed (and saved) from the FeatureGroup
      DELETED: () => {
        currentShape.layer = null;
      }
    };

    const handler = handlers[eventName];
    if (handler) {
      handler(e);
    }

    drawTool.lastEvent = eventName;
  }

  // Every leaflet.draw event is catched, thereby taking care that the shape is always up-to-date,
  // that all limits are respected and that the last consistent state gets exposed by the
  // drawing tool
  function registerDrawEvents() {
    Object.keys(L.Draw.Event).forEach((eventName) => {
      drawTool.map.on(L.Draw.Event[eventName], (e) => {
        if (eventName === 'DELETED') { // IE HACK
          suppress.start(300);
        }

        handleDrawEvent(eventName, e);

        updateShape(); // Update current shape and tooltip

        defer(() => {
          // Force Leaflet to enable TextSelection (tg-2728)
          L.DomUtil.enableTextSelection();

          // Execute this code after leaflet.draw has finished the event
          enforceLimits(); // max vertices, auto close when max reached
          if (currentShape.isConsistent) {
            onChangePolygon(); // trigger change on new consistent state of the polygon
          }
        });
      });
    });
  }

  // register any non-leaflet.draw events
  function registerMapEvents() {
    // Click outside shape => delete shape
    drawTool.map.on('click', () => {
      if (suppress.isBusy()) {
        return;
      }

      // In edit mode => disable()
      if (drawTool.drawingMode === drawToolConfig.DRAWING_MODE.EDIT) {
        disable();
      } else if (drawTool.drawingMode !== drawToolConfig.DRAWING_MODE.DRAW && currentShape.layer) {
        // If not in Draw or EDIT mode and a polygon exists
        // then the current polygon gets deleted
        // Note: In draw mode the click on map adds a new marker
        deletePolygon();
        updateShape();
        onFinishPolygon();
        disable();
      }
    });
  }

  // Click on the shape toggles EDIT mode
  function toggleEditModeOnShapeClick(e) {
    if (suppress.isBusy()) {
      return;
    }
    L.DomEvent.stop(e);
    toggle();
  }

  // toggle between draw/edit (enable) and show mode (null)
  function toggle() {
    return isEnabled() ? disable() : enable();
  }

  function isEnabled() {
    // isEnabled => shape is being created or being edited
    return drawTool.drawingMode !== drawToolConfig.DRAWING_MODE.NONE;
  }

  // start draw or edit mode for current layer or start create mode for new shape
  // the outside only knows enabled or disabled, internally the mode is further defined
  // in DRAW or EDIT
  function enable() {
    if (!isEnabled()) {
      if (currentShape.layer) { // Shape exists, start edit
        drawTool.editShapeHandler.enable();
      } else { // Shape does not yet exist, start draw
        drawTool.drawShapeHandler.enable();
      }
    }
  }

  // end of draw or edit mode => in create mode complete shape, in edit mode save shape
  function disable() {
    if (isEnabled()) {
      if (drawTool.drawingMode === drawToolConfig.DRAWING_MODE.DRAW) {
        if (currentShape.markers.length > 1) {
          // Close the polyline between the first and last points
          drawTool.drawShapeHandler.completeShape();
        } else {
          drawTool.drawShapeHandler.disable();
        }
      } else {
        drawTool.editShapeHandler.save(); // Save the layer geometries
        drawTool.editShapeHandler.disable();
      }
      setDrawingMode(drawToolConfig.DRAWING_MODE.NONE);
    }
  }

  // Cancel drawing => disable the draw tool and do not save anything
  // that has been drawn
  function cancel() {
    if (isEnabled()) {
      if (drawTool.drawingMode === drawToolConfig.DRAWING_MODE.DRAW) {
        drawTool.drawShapeHandler.disable();
      } else {
        drawTool.editShapeHandler.disable();
      }
      // Silently change the drawing mode
      setDrawingMode(drawToolConfig.DRAWING_MODE.NONE);
    }
  }

  // Shape method for shape.info
  // while drawing the polygon is not closed => distance is distance of the lines
  // When editing the polygon is closed => distance is surrounding
  // When only tow points => distance is line lenght
  function getDistance(latLngs, isClosed) {
    return latLngs.reduce((total, latlng, i) => {
      if (i > 0) {
        const dist = latlng.distanceTo(latLngs[i - 1]);
        total += dist;
      }
      return total;
    }, isClosed && latLngs.length > 2 ? latLngs[0].distanceTo(latLngs[latLngs.length - 1]) : 0);
  }

  // Update the internal information about the current shape
  function updateShape() {
    const DISTANCE_IN_KILOMETERS = 1000; // Show in km starting from this #meters, else show in m

    let latLngs = [];
    let area = 0;
    let distance = 0;
    let intersects = false;

    if (currentShape.layer) {
      latLngs = currentShape.layer.getLatLngs()[0];
      distance = getDistance(latLngs, true);
      area = L.GeometryUtil.geodesicArea(latLngs);
      intersects = currentShape.layer.intersects();
    } else if (drawTool.drawShapeHandler._markers &&
      drawTool.drawShapeHandler._markers.length > 0) {
      latLngs = drawTool.drawShapeHandler._markers.map((m) => m._latlng);
      area = drawTool.drawShapeHandler._area;
      distance = getDistance(latLngs, false);
    }

    currentShape.markersPrev = { ...currentShape.markers };
    currentShape.markers = latLngs.map(({
      lat,
      lng
    }) => [lat, lng]);
    currentShape.area = area;
    currentShape.areaTxt = L.GeometryUtil.readableArea(
      area,
      drawToolConfig.draw.polygon.metric,
      drawToolConfig.draw.polygon.precision
    );
    currentShape.distance = distance;
    if (distance >= DISTANCE_IN_KILOMETERS) {
      currentShape.distanceTxt =
        L.GeometryUtil.formattedNumber(distance / DISTANCE_IN_KILOMETERS, 2) + ' km';
    } else {
      currentShape.distanceTxt = L.GeometryUtil.formattedNumber(distance, 1) + ' m';
    }
    currentShape.intersects = intersects;

    currentShape.isConsistent = !(
      currentShape.markers.length > currentShape.markersMaxCount || currentShape.intersects
    );

    if (currentShape.isConsistent) {
      L.drawLocal.edit.handlers.edit.tooltip.text = currentShape.areaTxt;
      L.drawLocal.edit.handlers.edit.tooltip.subtext = currentShape.distanceTxt;
      updateShapeInfo(); // update public shape info of new consistent state of the polygon
    }

    if (currentShape.isConsistent && typeof _onUpdateShape === 'function') {
      // call any registered callback function, applyAsync because triggered by a leaflet event
      _onUpdateShape(currentShape);
    }
  }

  // Updates the publicly available info for the current shape
  // Only to be called when shape is in a consistent state
  function updateShapeInfo() {
    // Copy a set of properties of the current shape into the shapeInfo object
    ['type', 'markers', 'markersMaxCount', 'area', 'areaTxt', 'distance', 'distanceTxt']
    .forEach((key) => {
      shapeInfo[key] = currentShape[key];
    });
  }

  // delete a marker in DRAW mode
  function deleteMarker(marker) {
    const drawShapeHandler = drawTool.drawShapeHandler;
    const markers = drawShapeHandler._markers; // is always an array
    const index = markers.findIndex((m) => m._leaflet_id === marker._leaflet_id);
    let nDelete = markers.length - index; // Delete all from last to marker, inclusive
    while (nDelete-- > 0) {
      // Remove the last vertex from the polyline, removes polyline from map if only one point
      // exists
      drawShapeHandler.deleteLastVertex();
    }
  }

  // returns the last marker that was added to the polygon (only called in draw mode)
  function getLastDrawnMarker() {
    const drawShapeHandler = drawTool.drawShapeHandler;
    return drawShapeHandler._markers[drawShapeHandler._markers.length - 1];
  }

  // bind last marker in DRAW mode to deleteMarker
  // bind first marker in DRAW mode to close polygon (by calling disable())
  function bindLastDrawnMarker() {
    const lastMarker = getLastDrawnMarker();
    const isFirstMarker = drawTool.drawShapeHandler._markers.length === 1;

    suppress.start(300);
    ['mousedown', 'click'].forEach((key) => lastMarker.on(key, () => {
      if (suppress.isBusy()) {
        return;
      }

      if (drawTool.drawShapeHandler.enabled() && isFirstMarker) {
        const isLineOrPolygon = currentShape.markers.length > 1;
        disable(); // Includes auto close for any line or polygon
        if (!isLineOrPolygon) {
          // Reopen draw mode to place first marker somewhere else
          enable();
        }
      } else {
        deleteMarker(lastMarker);
      }
    }));
  }
};

export default DrawTool();
/* eslint-enable no-use-before-define,no-underscore-dangle */
<|endoftext|>


<commit_before>/*
Copyright 2015, 2016 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

'use strict';

var React = require('react');
var sdk = require('matrix-react-sdk')
var dis = require('matrix-react-sdk/lib/dispatcher');
var MatrixClientPeg = require("matrix-react-sdk/lib/MatrixClientPeg");
var rate_limited_func = require('matrix-react-sdk/lib/ratelimitedfunc');

module.exports = React.createClass({
    displayName: 'RightPanel',

    Phase : {
        MemberList: 'MemberList',
        FileList: 'FileList',
        MemberInfo: 'MemberInfo',
    },

    componentWillMount: function() {
        this.dispatcherRef = dis.register(this.onAction);
        var cli = MatrixClientPeg.get();
        cli.on("RoomState.members", this.onRoomStateMember);
    },

    componentWillUnmount: function() {
        dis.unregister(this.dispatcherRef);
        if (MatrixClientPeg.get()) {
            MatrixClientPeg.get().removeListener("RoomState.members", this.onRoomStateMember);
        }
    },

    getInitialState: function() {
        return {
            phase : this.Phase.MemberList
        }
    },

    onMemberListButtonClick: function() {
        if (this.props.collapsed) {
            this.setState({ phase: this.Phase.MemberList });
            dis.dispatch({
                action: 'show_right_panel',
            });
        }
        else {
            dis.dispatch({
                action: 'hide_right_panel',
            });
        }
    },

    onRoomStateMember: function(ev, state, member) {
        // redraw the badge on the membership list
        if (this.state.phase == this.Phase.MemberList && member.roomId === this.props.roomId) {
            this._delayedUpdate();
        }
        else if (this.state.phase === this.Phase.MemberInfo && member.roomId === this.props.roomId &&
                member.userId === this.state.member.userId) {
            // refresh the member info (e.g. new power level)
            this._delayedUpdate();
        }
    },

    _delayedUpdate: new rate_limited_func(function() {
        this.forceUpdate();
    }, 500),

    onAction: function(payload) {
        if (payload.action === "view_user") {
            dis.dispatch({
                action: 'show_right_panel',
            });
            if (payload.member) {
                this.setState({
                    phase: this.Phase.MemberInfo,
                    member: payload.member,
                });
            }
            else {
                this.setState({
                    phase: this.Phase.MemberList
                });
            }
        }
        if (payload.action === "view_room") {
            if (this.state.phase === this.Phase.MemberInfo) {
                this.setState({
                    phase: this.Phase.MemberList
                });
            }
        }
    },

    render: function() {
        var MemberList = sdk.getComponent('rooms.MemberList');
        var TintableSvg = sdk.getComponent("elements.TintableSvg");
        var buttonGroup;
        var panel;

        var filesHighlight;
        var membersHighlight;
        if (!this.props.collapsed) {
            if (this.state.phase == this.Phase.MemberList || this.state.phase === this.Phase.MemberInfo) {
                membersHighlight =

;
            }
            else if (this.state.phase == this.Phase.FileList) {
                filesHighlight =

;
            }
        }

        var membersBadge;
        if ((this.state.phase == this.Phase.MemberList || this.state.phase === this.Phase.MemberInfo) && this.props.roomId) {
            var cli = MatrixClientPeg.get();
            var room = cli.getRoom(this.props.roomId);
            if (room) {
                membersBadge =
{ room.getJoinedMembers().length }
;
            }
        }

        if (this.props.roomId) {
            buttonGroup =

                            { membersBadge }
                            <TintableSvg src="img/icons-people.svg" width="25" height="25"/>
                            { membersHighlight }

                            <TintableSvg src="img/files.svg" width="17" height="22"/>
                            { filesHighlight }

;

            if (!this.props.collapsed) {
                if(this.state.phase == this.Phase.MemberList) {
                    panel = <MemberList roomId={this.props.roomId} key={this.props.roomId} />
                }
                else if(this.state.phase == this.Phase.MemberInfo) {
                    var MemberInfo = sdk.getComponent('rooms.MemberInfo');
                    panel = <MemberInfo roomId={this.props.roomId} member={this.state.member} key={this.props.roomId} />
                }
            }
        }

        if (!panel) {
            panel =

;
        }

        var classes = "mx_RightPanel mx_fadable";
        if (this.props.collapsed) {
            classes += " collapsed";
        }

        return (

                    { buttonGroup }

                { panel }

        );
    }
});

<commit_msg>make /user URLs work<commit_after>/*
Copyright 2015, 2016 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

'use strict';

var React = require('react');
var sdk = require('matrix-react-sdk');
var Matrix = require("matrix-js-sdk");
var dis = require('matrix-react-sdk/lib/dispatcher');
var MatrixClientPeg = require("matrix-react-sdk/lib/MatrixClientPeg");
var rate_limited_func = require('matrix-react-sdk/lib/ratelimitedfunc');

module.exports = React.createClass({
    displayName: 'RightPanel',

    Phase : {
        MemberList: 'MemberList',
        FileList: 'FileList',
        MemberInfo: 'MemberInfo',
    },

    componentWillMount: function() {
        this.dispatcherRef = dis.register(this.onAction);
        var cli = MatrixClientPeg.get();
        cli.on("RoomState.members", this.onRoomStateMember);
    },

    componentWillUnmount: function() {
        dis.unregister(this.dispatcherRef);
        if (MatrixClientPeg.get()) {
            MatrixClientPeg.get().removeListener("RoomState.members", this.onRoomStateMember);
        }
    },

    getInitialState: function() {
        if (this.props.userId) {
            var member = new Matrix.RoomMember(null, this.props.userId);
            return {
                phase: this.Phase.MemberInfo,
                member: member,
            }
        }
        else {
            return {
                phase: this.Phase.MemberList
            }
        }
    },

    onMemberListButtonClick: function() {
        if (this.props.collapsed) {
            this.setState({ phase: this.Phase.MemberList });
            dis.dispatch({
                action: 'show_right_panel',
            });
        }
        else {
            dis.dispatch({
                action: 'hide_right_panel',
            });
        }
    },

    onRoomStateMember: function(ev, state, member) {
        // redraw the badge on the membership list
        if (this.state.phase == this.Phase.MemberList && member.roomId === this.props.roomId) {
            this._delayedUpdate();
        }
        else if (this.state.phase === this.Phase.MemberInfo && member.roomId === this.props.roomId &&
                member.userId === this.state.member.userId) {
            // refresh the member info (e.g. new power level)
            this._delayedUpdate();
        }
    },

    _delayedUpdate: new rate_limited_func(function() {
        this.forceUpdate();
    }, 500),

    onAction: function(payload) {
        if (payload.action === "view_user") {
            dis.dispatch({
                action: 'show_right_panel',
            });
            if (payload.member) {
                this.setState({
                    phase: this.Phase.MemberInfo,
                    member: payload.member,
                });
            }
            else {
                this.setState({
                    phase: this.Phase.MemberList
                });
            }
        }
        else if (payload.action === "view_room") {
            if (this.state.phase === this.Phase.MemberInfo) {
                this.setState({
                    phase: this.Phase.MemberList
                });
            }
        }
    },

    render: function() {
        var MemberList = sdk.getComponent('rooms.MemberList');
        var TintableSvg = sdk.getComponent("elements.TintableSvg");
        var buttonGroup;
        var panel;

        var filesHighlight;
        var membersHighlight;
        if (!this.props.collapsed) {
            if (this.state.phase == this.Phase.MemberList || this.state.phase === this.Phase.MemberInfo) {
                membersHighlight =

;
            }
            else if (this.state.phase == this.Phase.FileList) {
                filesHighlight =

;
            }
        }

        var membersBadge;
        if ((this.state.phase == this.Phase.MemberList || this.state.phase === this.Phase.MemberInfo) && this.props.roomId) {
            var cli = MatrixClientPeg.get();
            var room = cli.getRoom(this.props.roomId);
            if (room) {
                membersBadge =
{ room.getJoinedMembers().length }
;
            }
        }

        if (this.props.roomId) {
            buttonGroup =

                            { membersBadge }
                            <TintableSvg src="img/icons-people.svg" width="25" height="25"/>
                            { membersHighlight }

                            <TintableSvg src="img/files.svg" width="17" height="22"/>
                            { filesHighlight }

;
        }

        if (!this.props.collapsed) {
            if(this.props.roomId && this.state.phase == this.Phase.MemberList) {
                panel = <MemberList roomId={this.props.roomId} key={this.props.roomId} />
            }
            else if(this.state.phase == this.Phase.MemberInfo) {
                var MemberInfo = sdk.getComponent('rooms.MemberInfo');
                panel = <MemberInfo member={this.state.member} key={this.props.roomId || this.props.userId} />
            }
        }

        if (!panel) {
            panel =

;
        }

        var classes = "mx_RightPanel mx_fadable";
        if (this.props.collapsed) {
            classes += " collapsed";
        }

        return (

                    { buttonGroup }

                { panel }

        );
    }
});

<|endoftext|>


<commit_before>/*
    Get Zamboni site configuration data, including waffle switches and FXA
    info.
*/
define('site_config', ['defer', 'requests', 'settings', 'urls'],
    function(defer, requests, settings, urls) {

    function fetch() {
        var def = defer.Deferred();
        requests.get(urls.api.url('site-config')).done(function(data) {
            settings.fxa_auth_url = data.fxa.fxa_auth_url;
            settings.fxa_auth_state = data.fxa.fxa_auth_state;
            settings.switches = data.waffle.switches || [];
            def.resolve(data);
        }).always(function() {
            def.resolve();
        });

        return def.promise();
    }

    return {
        'fetch': fetch,
        'promise': fetch(),
    };
});
<commit_msg>upstream site config<commit_after>/*
    Get Zamboni site configuration data, including waffle switches and FXA
    info.
*/
define('site_config', ['defer', 'requests', 'settings', 'underscore', 'urls'],
    function(defer, requests, settings, _, urls) {

    function fetch() {
        var def = defer.Deferred();
        requests.get(urls.api.unsigned.url('site-config')).done(function(data) {
            if (data.hasOwnProperty('fxa')) {
                settings.fxa_auth_url = data.fxa.fxa_auth_url;
                settings.fxa_auth_state = data.fxa.fxa_auth_state;
            }
            if (data.waffle.switches && _.isArray(data.waffle.switches)) {
                settings.switches = data.waffle.switches;
            }
            def.resolve(data);
        }).always(function() {
            def.resolve();
        });

        return def.promise();
    }

    return {
        'fetch': fetch,
        'promise': fetch(),
    };
});
<|endoftext|>