<commit_before>import React from "react";
import { bindActionCreators } from "redux";
import { connect } from "react-redux";
import injectJSS from "react-jss";

import { openLightbox, closeLightbox } from "../actions";

const styles = {
  Lightbox: {
    background: "#000",
    display: "flex",
    "-webkit-box-align": "center",
    "-ms-flex-align": "center",
    alignItems: "center",
    display: "-webkit-box",
    display: "-ms-flexbox",
    display: "flex",
    height: "100%",
    "-webkit-box-pack": "center",
    "-ms-flex-pack": "center",
    justifyContent: "center",
    left: 0,
    padding: "44px 0 0",
    position: "fixed",
    top: 0,
    width: "100%!important",
    zIndex: 10000,
  },
  closeButton: {
    background: "transparent",
    border: 0,
    cursor: "pointer",
    height: "24px",
    left: "auto",
    position: "absolute",
    right: "35px",
    top: "35px",
    width: "24px",
  },
};

const Lightbox = ({
  classes,
  children,
  lightboxIsOpen,
  openLightbox,
  closeLightbox,
}) => {
  if (lightboxIsOpen) {
    return (

        <button onClick={closeLightbox} className={classes.closeButton} />

    );
  } else {
    return ;
  }
};

const mapStateToProps = state => ({
  lightboxIsOpen: state.core.lightboxIsOpen,
});

const mapDispatchToProps = dispatch => {
  return bindActionCreators({ openLightbox, closeLightbox }, dispatch);
};

export default connect(mapStateToProps, mapDispatchToProps)(
  injectJSS(styles)(Lightbox),
);
<commit_msg>lightbox X buton<commit_after>import React from "react";
import { bindActionCreators } from "redux";
import { connect } from "react-redux";
import injectJSS from "react-jss";

import { openLightbox, closeLightbox } from "../actions";

const styles = {
  Lightbox: {
    background: "#000",
    display: "flex",
    "-webkit-box-align": "center",
    "-ms-flex-align": "center",
    alignItems: "center",
    display: "-webkit-box",
    display: "-ms-flexbox",
    display: "flex",
    height: "100%",
    "-webkit-box-pack": "center",
    "-ms-flex-pack": "center",
    justifyContent: "center",
    left: 0,
    padding: "44px 0 0",
    position: "fixed",
    top: 0,
    width: "100%!important",
    zIndex: 10000,
  },
  closeButton: {
    background: "transparent",
    border: 0,
    cursor: "pointer",
    height: "24px",
    left: "auto",
    position: "absolute",
    right: "35px",
    top: "35px",
    width: "24px",
    "&:before, &:after": {
      position: "absolute",
      content: '" "',
      top: 0,
      left: "12px",
      height: "24px",
      width: "2px",
      backgroundColor: "#fff",
    },
    "&:before": {
      transform: "rotate(45deg)",
    },
    "&:after": {
      transform: "rotate(-45deg)",
    },
  },
};

const Lightbox = ({
  classes,
  children,
  lightboxIsOpen,
  openLightbox,
  closeLightbox,
}) => {
  if (lightboxIsOpen) {
    return (

        <button onClick={closeLightbox} className={classes.closeButton}></button>
        {children}

    );
  } else {
    return ;
  }
};

const mapStateToProps = state => ({
  lightboxIsOpen: state.core.lightboxIsOpen,
});

const mapDispatchToProps = dispatch => {
  return bindActionCreators({ openLightbox, closeLightbox }, dispatch);
};

export default connect(mapStateToProps, mapDispatchToProps)(
  injectJSS(styles)(Lightbox),
);
<|endoftext|>


<commit_before>/**
 * 例)
 * var cw = new ChatWork({token: 'xxx'})
 * cw.sendMessage({room_id: xx, body: xx});
 */
var ChatWork = function(config)
{
  this.base_url = 'https://api.chatwork.com/v1';
  this.headers  = {'X-ChatWorkToken': config.token};
};

/**
 * メッセージ送信
 */
ChatWork.prototype.sendMessage = function(params)
{
  var post_data = {
    'body': params.body
  }

  this.post('/rooms/'+ params.room_id +'/messages', post_data);
}

/**
 * マイチャットへのメッセージを送信
 */
ChatWork.prototype.sendMessageToMyChat = function(message)
{
  var mydata = this.get('/me');

  this.sendMessage({
    'body': message,
    'room_id': mydata.room_id
  });
}

/**
 * タスク追加
 */
ChatWork.prototype.sendTask = function(params)
{
  var to_ids = params.to_id_list.join(',');
  var post_data = {
    'body': params.body,
    'to_ids': to_ids,
    'limit': params.limit
  };

  this.post('/rooms/'+ params.room_id +'/tasks', post_data);
}

/**
 * 自分のタスク一覧を取得
 */
ChatWork.prototype.getMyTasks = function(params)
{
  return this.get('/my/tasks', params);
}

ChatWork.prototype._sendRequest = function(params)
{
  var url = this.base_url + params.path;
  var options = {
    'method': params.method,
    'headers': this.headers,
    'payload': params.payload || {}
  };

  result = UrlFetchApp.fetch(url, options);

  // リクエストに成功していたら結果を解析して返す
  if (result.getResponseCode() == 200) {
    return Utilities.jsonParse(result.getContentText())
  }
};

ChatWork.prototype.post = function(endpoint, post_data)
{
  return this._sendRequest({
    'method': 'post',
    'path': endpoint,
    'payload': post_data
  });
}

ChatWork.prototype.get = function(endpoint, get_data)
{
  get_data = get_data || {};

  var path = endpoint

  // get_dataがあればクエリーを生成する
  // かなり簡易的なので必要に応じて拡張する
  var query_string_list = [];
  for (var key in get_data) {
    query_string_list.push(encodeURIComponent(key) + '=' + encodeURIComponent(get_data[key]));
  }

  if (query_string_list.length > 0) {
   path += '?' + query_string_list.join('&');
  }

  return this._sendRequest({
    'method': 'get',
    'path': path
  });
}
<commit_msg>ChatWorkClientは factory を介して利用するように変更<commit_after>
(function(global){
  var ChatWork = (function() {

    function ChatWork(config) {
      this.base_url = 'https://api.chatwork.com/v1';
      this.headers  = {'X-ChatWorkToken': config.token};
    }

    /**
    * メッセージ送信
    */
    ChatWork.prototype.sendMessage = function(params) {
      var post_data = {
        'body': params.body
      };

      this.post('/rooms/'+ params.room_id +'/messages', post_data);
    };

    /**
    * マイチャットへのメッセージを送信
    */
    ChatWork.prototype.sendMessageToMyChat = function(message) {
      var mydata = this.get('/me');

      this.sendMessage({
        'body': message,
        'room_id': mydata.room_id
      });
    };

    /**
    * タスク追加
    */
    ChatWork.prototype.sendTask = function(params) {
      var to_ids = params.to_id_list.join(',');
      var post_data = {
        'body': params.body,
        'to_ids': to_ids,
        'limit': params.limit
      };

      this.post('/rooms/'+ params.room_id +'/tasks', post_data);
    };

    /**
    * 自分のタスク一覧を取得
    */
    ChatWork.prototype.getMyTasks = function(params) {
      return this.get('/my/tasks', params);
    };

    ChatWork.prototype._sendRequest = function(params)
    {
      var url = this.base_url + params.path;
      var options = {
        'method': params.method,
        'headers': this.headers,
        'payload': params.payload || {}
      };

      result = UrlFetchApp.fetch(url, options);

      // リクエストに成功していたら結果を解析して返す
      if (result.getResponseCode() == 200) {
        return Utilities.jsonParse(result.getContentText());
      }
    };

    ChatWork.prototype.post = function(endpoint, post_data) {
      return this._sendRequest({
        'method': 'post',
        'path': endpoint,
        'payload': post_data
      });
    };

    ChatWork.prototype.get = function(endpoint, get_data) {
      get_data = get_data || {};

      var path = endpoint;

      // get_dataがあればクエリーを生成する
      // かなり簡易的なので必要に応じて拡張する
      var query_string_list = [];
      for (var key in get_data) {
        query_string_list.push(encodeURIComponent(key) + '=' + encodeURIComponent(get_data[key]));
      }

      if (query_string_list.length > 0) {
        path += '?' + query_string_list.join('&');
      }

      return this._sendRequest({
        'method': 'get',
        'path': path
      });
    };

    return ChatWork;
  })();

  global.ChatWork = ChatWork;

})(this);

/**
 * ChatWorkClientの作成
 *
 *
利用例

 *

 * var cw = ChatWorkClient.factory({token: xxx});
 * cw.sendMessage({room_id: xx, body: xx});
 *

 * @param {assoc} config
 */
function factory(config) {
  return new ChatWork(config);
}<|endoftext|>


<commit_before>module.exports = HTTPDuplex

var http = require('http')
  , util = require('util')
  , stream = require('stream')
if (process.version.match(/^\v0\.8/)) stream = require('readable-stream')

util.inherits(HTTPDuplex, stream.Duplex)
function HTTPDuplex(req, options) {
  var self = this

  if (! (self instanceof HTTPDuplex)) return new HTTPDuplex(req, options)

  stream.Duplex.call(self, options)
  self.req = http.request(req)
  self.req.on('response', function (resp) {
    self._resp = resp
    resp.on('data', function (c) {
      if (!self.push(c)) self._resp.pause()
    })
    resp.on('end', function() {
      self.push(null)
    })
  })
  self._resp = null
}

HTTPDuplex.prototype._read = function (n) {
  if (this._resp) this._resp.resume()
}

HTTPDuplex.prototype._write = function (chunk, encoding, cb) {
  return this.req.write(chunk, encoding, cb)
}

HTTPDuplex.prototype.end = function (chunk, encoding, cb) {
  return this.req.end(chunk, encoding, cb)
}
<commit_msg>expose an event in the duplex stream for the response.<commit_after>module.exports = HTTPDuplex

var http = require('http')
  , util = require('util')
  , stream = require('stream')
if (process.version.match(/^\v0\.8/)) stream = require('readable-stream')

util.inherits(HTTPDuplex, stream.Duplex)
function HTTPDuplex(req, options) {
  var self = this

  if (! (self instanceof HTTPDuplex)) return new HTTPDuplex(req, options)

  stream.Duplex.call(self, options)
  self.req = http.request(req)
  self.req.on('response', function (resp) {
    self._resp = resp
    self.emit('response', resp)

    resp.on('data', function (c) {
      if (!self.push(c)) self._resp.pause()
    })
    resp.on('end', function() {
      self.push(null)
    })
  })
  self._resp = null
}

HTTPDuplex.prototype._read = function (n) {
  if (this._resp) this._resp.resume()
}

HTTPDuplex.prototype._write = function (chunk, encoding, cb) {
  return this.req.write(chunk, encoding, cb)
}

HTTPDuplex.prototype.end = function (chunk, encoding, cb) {
  return this.req.end(chunk, encoding, cb)
}
<|endoftext|>


<commit_before>import * as React from "react";
import PropTypes from "prop-types";
import Button, { buttonTypes } from "@crave/farmblocks-button";
import InputText from "@crave/farmblocks-input-text";
import { fontSizes } from "@crave/farmblocks-theme";
import values from "object.values";

import selectorSizes from "../constants/selectorSizes";
import Wrapper from "../styledComponents/AmountSelector";

class AmountSelectors extends React.Component {
  state = {
    value: this.props.value,
    validationMessages: this.props.validationMessages
  };

  onChange = event => {
    const value = typeof event === "number" ? event : event.target.value;
    const parsedValue = parseFloat(value) || 0;

    if (parsedValue >= this.props.min && parsedValue <= this.props.max) {
      this.setState({
        value: parsedValue,
        validationMessages: []
      });

      return this.props.onChange(parsedValue);
    }

    this.setState({
      validationMessages: ["Invalid value"]
    });
  };

  decrement = () => {
    const value = this.state.value - this.props.step;

    this.onChange(Math.max(value, this.props.min));
  };

  increment = () => {
    const value = this.state.value + this.props.step;

    this.onChange(Math.min(value, this.props.max));
  };

  render() {
    return (
      <Wrapper size={this.props.size}>
        <Button
          className="decreaseButton"
          type={buttonTypes.SECONDARY}
          size={this.props.size}
          icon="wg-minus"
          disabled={this.state.value === this.props.min}
          onClick={this.decrement}
          noTooltip
        />

          <InputText
            type="number"
            min={this.props.min}
            max={this.props.max}
            step={this.props.step}
            value={this.state.value}
            readOnly={this.props.disableTyping}
            onKeyDown={this.onKeyDown}
            onChange={this.onChange}
            size={4}
            validationMessages={this.state.validationMessages}
            fontSize={fontSizes[this.props.size]}
          />

        <Button
          className="increaseButton"
          type={buttonTypes.SECONDARY}
          size={this.props.size}
          icon="wg-add"
          disabled={this.state.value === this.props.max}
          onClick={this.increment}
          tooltipText="There is no more available amount."
        />
      </Wrapper>
    );
  }

  static propTypes = {
    value: PropTypes.number,
    step: PropTypes.number,
    min: PropTypes.number,
    max: PropTypes.number,
    onChange: PropTypes.func,
    disableTyping: PropTypes.bool,
    validationMessages: PropTypes.arrayOf(PropTypes.string),
    size: PropTypes.oneOf(values(selectorSizes))
  };

  static defaultProps = {
    value: 0,
    step: 1,
    min: 0,
    max: Number.MAX_VALUE,
    onChange: () => false,
    disableTyping: false,
    size: selectorSizes.MEDIUM
  };
}

export default AmountSelectors;
<commit_msg>feat(amount-selector): format value to fixed 2 after button click or onblur<commit_after>import * as React from "react";
import PropTypes from "prop-types";
import Button, { buttonTypes } from "@crave/farmblocks-button";
import InputText from "@crave/farmblocks-input-text";
import { fontSizes } from "@crave/farmblocks-theme";
import values from "object.values";

import selectorSizes from "../constants/selectorSizes";
import Wrapper from "../styledComponents/AmountSelector";

class AmountSelectors extends React.Component {
  state = {
    value: this.props.value,
    displayValue: this.props.value,
    validationMessages: this.props.validationMessages
  };

  onChange = (event, cb) => {
    const value = typeof event === "number" ? event : event.target.value;
    const parsedValue = parseFloat(value) || 0;

    if (parsedValue >= this.props.min && parsedValue <= this.props.max) {
      this.setState(
        {
          value: parsedValue,
          validationMessages: []
        },
        cb
      );

      return this.props.onChange(parsedValue);
    }

    this.setState({
      validationMessages: ["Invalid value"]
    });
  };

  updateDisplayValue = () => {
    this.setState({
      displayValue: this.state.value.toFixed(2)
    });
  };

  decrement = () => {
    const value = this.state.value - this.props.step;

    this.onChange(Math.max(value, this.props.min), this.updateDisplayValue);
  };

  increment = () => {
    const value = this.state.value + this.props.step;

    this.onChange(Math.min(value, this.props.max), this.updateDisplayValue);
  };

  render() {
    return (
      <Wrapper size={this.props.size}>
        <Button
          className="decreaseButton"
          type={buttonTypes.SECONDARY}
          size={this.props.size}
          icon="wg-minus"
          disabled={this.state.value === this.props.min}
          onClick={this.decrement}
          noTooltip
        />

          <InputText
            type="number"
            min={this.props.min}
            max={this.props.max}
            step={this.props.step}
            value={this.state.displayValue}
            readOnly={this.props.disableTyping}
            onKeyDown={this.onKeyDown}
            onChange={this.onChange}
            onBlur={this.updateDisplayValue}
            size={4}
            validationMessages={this.state.validationMessages}
            fontSize={fontSizes[this.props.size]}
          />

        <Button
          className="increaseButton"
          type={buttonTypes.SECONDARY}
          size={this.props.size}
          icon="wg-add"
          disabled={this.state.value === this.props.max}
          onClick={this.increment}
          tooltipText="There is no more available amount."
        />
      </Wrapper>
    );
  }

  static propTypes = {
    value: PropTypes.number,
    step: PropTypes.number,
    min: PropTypes.number,
    max: PropTypes.number,
    onChange: PropTypes.func,
    disableTyping: PropTypes.bool,
    validationMessages: PropTypes.arrayOf(PropTypes.string),
    size: PropTypes.oneOf(values(selectorSizes))
  };

  static defaultProps = {
    value: 0,
    step: 1,
    min: 0,
    max: Number.MAX_VALUE,
    onChange: () => false,
    disableTyping: false,
    size: selectorSizes.MEDIUM
  };
}

export default AmountSelectors;
<|endoftext|>


<commit_before>/*
 * patternlab-node - v1.2.0 - 2016
 *
 * Brian Muenzenmeyer, Geoffrey Pursell, and the web community.
 * Licensed under the MIT license.
 *
 * Many thanks to Brad Frost and Dave Olsen for inspiration, encouragement, and advice.
 *
 */

"use strict";

var path = require('path');
var fs = require('fs-extra');
var of = require('./object_factory');

// PRIVATE FUNCTIONS

function addToPatternPaths(patternlab, bucketName, pattern) {
  //this is messy, could use a refactor.
  patternlab.patternPaths[bucketName][pattern.patternName] = pattern.subdir.replace(/\\/g, '/') + "/" + pattern.fileName;
}

//todo: refactor this as a method on the pattern object itself once we merge dev with pattern-engines branch
function isPatternExcluded(pattern) {
  // returns whether or not the first character of the pattern filename is an underscore, or excluded
  return pattern.fileName.charAt(0) === '_';
}

// Returns the array of patterns to be rendered in the styleguide view and
// linked to in the pattern navigation. Checks if patterns are excluded.
function assembleStyleguidePatterns(patternlab) {
  var styleguideExcludes = patternlab.config.styleGuideExcludes;
  var styleguidePatterns = [];

  if (styleguideExcludes && styleguideExcludes.length) {
    for (var i = 0; i < patternlab.patterns.length; i++) {

      // skip underscore-prefixed files
      if (isPatternExcluded(patternlab.patterns[i])) {
        if (patternlab.config.debug) {
          console.log('Omitting ' + patternlab.patterns[i].key + " from styleguide pattern exclusion.");
        }
        continue;
      }

      var key = patternlab.patterns[i].key;
      var typeKey = key.substring(0, key.indexOf('-'));
      var isExcluded = (styleguideExcludes.indexOf(typeKey) > -1);
      if (!isExcluded) {
        styleguidePatterns.push(patternlab.patterns[i]);
      }
    }
  } else {
    styleguidePatterns = patternlab.patterns;
  }

  return styleguidePatterns;
}

function buildNavigation(patternlab) {
  for (var i = 0; i < patternlab.patterns.length; i++) {

    var pattern = patternlab.patterns[i];
    var bucketName = pattern.name.replace(/\\/g, '-').split('-')[1];

    // skip underscore-prefixed files. don't create a bucket on account of an underscored pattern
    if (isPatternExcluded(pattern)) {
      continue;
    }

    //check if the bucket already exists
    var bucketIndex = patternlab.bucketIndex.indexOf(bucketName);
    if (bucketIndex === -1) {
      //add the bucket
      var bucket = new of.oBucket(bucketName);

      //add patternPath and viewAllPath
      patternlab.patternPaths[bucketName] = {};
      patternlab.viewAllPaths[bucketName] = {};

      //get the navItem
      var navItemName = pattern.subdir.split('/').pop();
      navItemName = navItemName.replace(/(\d).(-)/g, '');

      //get the navSubItem
      var navSubItemName = pattern.patternName.replace(/-/g, ' ');

      //test whether the pattern struture is flat or not - usually due to a template or page
      var flatPatternItem = false;
      if (navItemName === bucketName) {
        flatPatternItem = true;
      }

      //assume the navItem does not exist.
      var navItem = new of.oNavItem(navItemName);

      //assume the navSubItem does not exist.
      var navSubItem = new of.oNavSubItem(navSubItemName);
      navSubItem.patternPath = pattern.patternLink;
      navSubItem.patternPartial = bucketName + "-" + pattern.patternName; //add the hyphenated name

      //add the patternState if it exists
      if (pattern.patternState) {
        navSubItem.patternState = pattern.patternState;
      }

      //if it is flat - we should not add the pattern to patternPaths
      if (flatPatternItem) {

        bucket.patternItems.push(navSubItem);

        //add to patternPaths
        addToPatternPaths(patternlab, bucketName, pattern);

      } else {

        bucket.navItems.push(navItem);
        bucket.navItemsIndex.push(navItemName);
        navItem.navSubItems.push(navSubItem);
        navItem.navSubItemsIndex.push(navSubItemName);

        //add to patternPaths
        addToPatternPaths(patternlab, bucketName, pattern);

        //add the navViewAllItem
        var navViewAllItem = new of.oNavSubItem("View All");
        navViewAllItem.patternPath = pattern.subdir.slice(0, pattern.subdir.indexOf(pattern.patternGroup) + pattern.patternGroup.length) + "/index.html";
        navViewAllItem.patternPartial = "viewall-" + pattern.patternGroup;

        bucket.patternItems.push(navViewAllItem);
        patternlab.viewAllPaths[bucketName].viewall = pattern.subdir.slice(0, pattern.subdir.indexOf(pattern.patternGroup) + pattern.patternGroup.length);

      }

      //add the bucket.
      patternlab.buckets.push(bucket);
      patternlab.bucketIndex.push(bucketName);

      //done

    } else {
      //find the bucket
      bucket = patternlab.buckets[bucketIndex];

      //get the navItem
      //if there is one or more slashes in the subdir, get everything after
      //the last slash. if no slash, get the whole subdir string and strip
      //any numeric + hyphen prefix
      navItemName = pattern.subdir.split('/').pop().replace(/^\d*\-/, '');

      //get the navSubItem
      navSubItemName = pattern.patternName.replace(/-/g, ' ');

      //assume the navSubItem does not exist.
      navSubItem = new of.oNavSubItem(navSubItemName);
      navSubItem.patternPath = pattern.patternLink;
      navSubItem.patternPartial = bucketName + "-" + pattern.patternName; //add the hyphenated name

      //add the patternState if it exists
      if (pattern.patternState) {
        navSubItem.patternState = pattern.patternState;
      }

      //test whether the pattern struture is flat or not - usually due to a template or page
      flatPatternItem = false;
      if (navItemName === bucketName) {
        flatPatternItem = true;
      }

      //if it is flat - we should not add the pattern to patternPaths
      if (flatPatternItem) {
        //add the navItem to patternItems
        bucket.patternItems.push(navSubItem);

        //add to patternPaths
        addToPatternPaths(patternlab, bucketName, pattern);

      } else {

        // only do this if pattern is included
        //check to see if navItem exists
        var navItemIndex = bucket.navItemsIndex.indexOf(navItemName);
        if (navItemIndex === -1) {
          navItem = new of.oNavItem(navItemName);

          //add the navItem and navSubItem
          navItem.navSubItems.push(navSubItem);
          navItem.navSubItemsIndex.push(navSubItemName);
          bucket.navItems.push(navItem);
          bucket.navItemsIndex.push(navItemName);

        } else {
          //add the navSubItem
          navItem = bucket.navItems[navItemIndex];
          navItem.navSubItems.push(navSubItem);
          navItem.navSubItemsIndex.push(navSubItemName);
        }

        //check if we are moving to a new sub section in the next loop
        if (!patternlab.patterns[i + 1] || pattern.patternSubGroup !== patternlab.patterns[i + 1].patternSubGroup) {

          //add the navViewAllSubItem
          var navViewAllSubItem = new of.oNavSubItem("");
          navViewAllSubItem.patternName = "View All";
          navViewAllSubItem.patternPath = pattern.flatPatternPath + "/index.html";
          navViewAllSubItem.patternPartial = "viewall-" + pattern.patternGroup + "-" + pattern.patternSubGroup;

          navItem.navSubItems.push(navViewAllSubItem);
          navItem.navSubItemsIndex.push("View All");
        }

        // just add to patternPaths
        addToPatternPaths(patternlab, bucketName, pattern);
      }
    }

    patternlab.viewAllPaths[bucketName][pattern.patternSubGroup] = pattern.flatPatternPath;
  }
  return bucketIndex;
}

function buildViewAllPages(mainPageHead, mainPageFoot, mainPageHeadHtml, mainPageFootHtml, pattern_assembler, patternlab) {
  var paths = patternlab.config.paths;
  var prevSubdir = '';
  var prevGroup = '';
  var i;

  for (i = 0; i < patternlab.patterns.length; i++) {
    // skip underscore-prefixed files
    if (isPatternExcluded(patternlab.patterns[i])) {
      if (patternlab.config.debug) {
        console.log('Omitting ' + patternlab.patterns[i].key + " from view all rendering.");
      }
      continue;
    }

    var pattern = patternlab.patterns[i];

    //create the view all for the section
    // check if the current section is different from the previous one
    if (pattern.patternGroup !== prevGroup) {
      prevGroup = pattern.patternGroup;

      var viewAllPatterns = [];
      var patternPartial = "viewall-" + pattern.patternGroup;
      var j;

      for (j = 0; j < patternlab.patterns.length; j++) {
        if (patternlab.patterns[j].patternGroup === pattern.patternGroup) {
          //again, skip any sibling patterns to the current one that may have underscores
          if (isPatternExcluded(patternlab.patterns[j])) {
            if (patternlab.config.debug) {
              console.log('Omitting ' + patternlab.patterns[j].key + " from view all sibling rendering.");
            }
            continue;
          }

          viewAllPatterns.push(patternlab.patterns[j]);
        }
      }

      var viewAllTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'templates/viewall.mustache'), 'utf8');
      var viewAllHtml = pattern_assembler.renderPattern(viewAllTemplate, {partials: viewAllPatterns, patternPartial: patternPartial, cacheBuster: patternlab.cacheBuster });
      fs.outputFileSync(paths.public.patterns + pattern.subdir.slice(0, pattern.subdir.indexOf(pattern.patternGroup) + pattern.patternGroup.length) + '/index.html', mainPageHead + viewAllHtml + mainPageFoot);
    }

    //create the view all for the subsection
    // check if the current sub section is different from the previous one
    if (pattern.subdir !== prevSubdir) {
      prevSubdir = pattern.subdir;

      viewAllPatterns = [];
      patternPartial = "viewall-" + pattern.patternGroup + "-" + pattern.patternSubGroup;

      for (j = 0; j < patternlab.patterns.length; j++) {
        if (patternlab.patterns[j].subdir === pattern.subdir) {
          //again, skip any sibling patterns to the current one that may have underscores
          if (isPatternExcluded(patternlab.patterns[j])) {
            if (patternlab.config.debug) {
              console.log('Omitting ' + patternlab.patterns[j].key + " from view all sibling rendering.");
            }
            continue;
          }

          viewAllPatterns.push(patternlab.patterns[j]);
        }
      }

      var viewAllTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'templates/viewall.mustache'), 'utf8');
      var viewAllHtml = pattern_assembler.renderPattern(viewAllTemplate, {partials: viewAllPatterns, patternPartial: patternPartial, cacheBuster: patternlab.cacheBuster});
      fs.outputFileSync(paths.public.patterns + pattern.flatPatternPath + '/index.html', mainPageHeadHtml + viewAllHtml + mainPageFootHtml);
    }
  }
}

function sortPatterns(patternsArray) {
  return patternsArray.sort(function (a, b) {
    if (a.name > b.name) {
      return 1;
    }
    if (a.name < b.name) {
      return -1;
    }

    // a must be equal to b
    return 0;
  });
}

// MAIN BUILDER FUNCTION

function buildFrontEnd(patternlab) {
  var pa = require('./pattern_assembler');
  var mh = require('./media_hunter');
  var pattern_assembler = new pa();
  var media_hunter = new mh();
  var styleguidePatterns = [];
  var paths = patternlab.config.paths;

  patternlab.buckets = [];
  patternlab.bucketIndex = [];
  patternlab.patternPaths = {};
  patternlab.viewAllPaths = {};

  //sort all patterns explicitly.
  patternlab.patterns = sortPatterns(patternlab.patterns);

  //find mediaQueries
  media_hunter.find_media_queries('./source/css', patternlab);

  // check if patterns are excluded, if not add them to styleguidePatterns
  styleguidePatterns = assembleStyleguidePatterns(patternlab);

  //also add the cachebuster value. slight chance this could collide with a user that has defined cacheBuster as a value
  patternlab.data.cacheBuster = patternlab.cacheBuster;

  //get the main page head and foot and render them
  var mainPageHead = patternlab.userHead.extendedTemplate.replace('{% pattern-lab-head %}', patternlab.header);
  var mainPageHeadHtml = pattern_assembler.renderPattern(mainPageHead, patternlab.data);
  var mainPageFoot = patternlab.userFoot.extendedTemplate.replace('{% pattern-lab-foot %}', patternlab.footer);
  var mainPageFootHtml = pattern_assembler.renderPattern(mainPageFoot, patternlab.data);

  //build the styleguide
  var styleguideTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'templates/styleguide.mustache'), 'utf8');
  var styleguideHtml = pattern_assembler.renderPattern(styleguideTemplate, {partials: styleguidePatterns, cacheBuster: patternlab.cacheBuster});

  fs.outputFileSync(path.resolve(paths.public.styleguide, 'html/styleguide.html'), mainPageHeadHtml + styleguideHtml + mainPageFootHtml);

  //build the viewall pages
  buildViewAllPages(mainPageHead, mainPageFoot, mainPageHeadHtml, mainPageFootHtml, pattern_assembler, patternlab);

  //build the patternlab website
  var patternlabSiteTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'templates/index.mustache'), 'utf8');

  //loop through all patterns.to build the navigation
  //todo: refactor this someday
  //GTP: totally doing that right now
  buildNavigation(patternlab);

  //the patternlab site requires a lot of partials to be rendered!

  //patternNav
  var patternNavTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'templates/partials/patternNav.mustache'), 'utf8');
  var patternNavPartialHtml = pattern_assembler.renderPattern(patternNavTemplate, patternlab);

  //ishControls
  var ishControlsTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'templates/partials/ishControls.mustache'), 'utf8');
  patternlab.config.mqs = patternlab.mediaQueries;
  var ishControlsPartialHtml = pattern_assembler.renderPattern(ishControlsTemplate, patternlab.config);

  //patternPaths
  var patternPathsTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'templates/partials/patternPaths.mustache'), 'utf8');
  var patternPathsPartialHtml = pattern_assembler.renderPattern(patternPathsTemplate, {'patternPaths': JSON.stringify(patternlab.patternPaths)});

  //viewAllPaths
  var viewAllPathsTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'templates/partials/viewAllPaths.mustache'), 'utf8');
  var viewAllPathsPartialHtml = pattern_assembler.renderPattern(viewAllPathsTemplate, {'viewallpaths': JSON.stringify(patternlab.viewAllPaths)});

  //render the patternlab template, with all partials
  var patternlabSiteHtml = pattern_assembler.renderPattern(patternlabSiteTemplate, {
    defaultPattern: patternlab.config.defaultPattern || 'all',
    cacheBuster: patternlab.cacheBuster
  }, {
    'ishControls': ishControlsPartialHtml,
    'patternNav': patternNavPartialHtml,
    'patternPaths': patternPathsPartialHtml,
    'viewAllPaths': viewAllPathsPartialHtml
  });
  fs.outputFileSync(path.resolve(paths.public.root, 'index.html'), patternlabSiteHtml);
}

module.exports = buildFrontEnd;
<commit_msg>factor out variable declarations and nav item name getting<commit_after>/*
 * patternlab-node - v1.2.0 - 2016
 *
 * Brian Muenzenmeyer, Geoffrey Pursell, and the web community.
 * Licensed under the MIT license.
 *
 * Many thanks to Brad Frost and Dave Olsen for inspiration, encouragement, and advice.
 *
 */

"use strict";

var path = require('path');
var fs = require('fs-extra');
var of = require('./object_factory');

// PRIVATE FUNCTIONS

function addToPatternPaths(patternlab, bucketName, pattern) {
  //this is messy, could use a refactor.
  patternlab.patternPaths[bucketName][pattern.patternName] = pattern.subdir.replace(/\\/g, '/') + "/" + pattern.fileName;
}

//todo: refactor this as a method on the pattern object itself once we merge dev with pattern-engines branch
function isPatternExcluded(pattern) {
  // returns whether or not the first character of the pattern filename is an underscore, or excluded
  return pattern.fileName.charAt(0) === '_';
}

// Returns the array of patterns to be rendered in the styleguide view and
// linked to in the pattern navigation. Checks if patterns are excluded.
function assembleStyleguidePatterns(patternlab) {
  var styleguideExcludes = patternlab.config.styleGuideExcludes;
  var styleguidePatterns = [];

  if (styleguideExcludes && styleguideExcludes.length) {
    for (var i = 0; i < patternlab.patterns.length; i++) {

      // skip underscore-prefixed files
      if (isPatternExcluded(patternlab.patterns[i])) {
        if (patternlab.config.debug) {
          console.log('Omitting ' + patternlab.patterns[i].key + " from styleguide pattern exclusion.");
        }
        continue;
      }

      var key = patternlab.patterns[i].key;
      var typeKey = key.substring(0, key.indexOf('-'));
      var isExcluded = (styleguideExcludes.indexOf(typeKey) > -1);
      if (!isExcluded) {
        styleguidePatterns.push(patternlab.patterns[i]);
      }
    }
  } else {
    styleguidePatterns = patternlab.patterns;
  }

  return styleguidePatterns;
}

function buildNavigation(patternlab) {
  for (var i = 0; i < patternlab.patterns.length; i++) {

    var pattern = patternlab.patterns[i];
    var bucketName = pattern.name.replace(/\\/g, '-').split('-')[1];

    // skip underscore-prefixed files. don't create a bucket on account of an underscored pattern
    if (isPatternExcluded(pattern)) {
      continue;
    }

    var navItemName;
    var navSubItemName;
    var flatPatternItem;
    var navItem;
    var navSubItem;
    var navViewAllItem;

    //get the navItem
    //if there is one or more slashes in the subdir, get everything after
    //the last slash. if no slash, get the whole subdir string and strip
    //any numeric + hyphen prefix
    navItemName = pattern.subdir.split('/').pop().replace(/^\d*\-/, '');
    //get the navSubItem
    navSubItemName = pattern.patternName.replace(/-/g, ' ');

    //check if the bucket already exists
    var bucketIndex = patternlab.bucketIndex.indexOf(bucketName);
    if (bucketIndex === -1) {
      //add the bucket
      var bucket = new of.oBucket(bucketName);

      //add patternPath and viewAllPath
      patternlab.patternPaths[bucketName] = {};
      patternlab.viewAllPaths[bucketName] = {};

      //test whether the pattern struture is flat or not - usually due to a template or page
      flatPatternItem = false;
      if (navItemName === bucketName) {
        flatPatternItem = true;
      }

      //assume the navItem does not exist.
      navItem = new of.oNavItem(navItemName);

      //assume the navSubItem does not exist.
      navSubItem = new of.oNavSubItem(navSubItemName);
      navSubItem.patternPath = pattern.patternLink;
      navSubItem.patternPartial = bucketName + "-" + pattern.patternName; //add the hyphenated name

      //add the patternState if it exists
      if (pattern.patternState) {
        navSubItem.patternState = pattern.patternState;
      }

      //if it is flat - we should not add the pattern to patternPaths
      if (flatPatternItem) {

        bucket.patternItems.push(navSubItem);

        //add to patternPaths
        addToPatternPaths(patternlab, bucketName, pattern);

      } else {

        bucket.navItems.push(navItem);
        bucket.navItemsIndex.push(navItemName);
        navItem.navSubItems.push(navSubItem);
        navItem.navSubItemsIndex.push(navSubItemName);

        //add to patternPaths
        addToPatternPaths(patternlab, bucketName, pattern);

        //add the navViewAllItem
        navViewAllItem = new of.oNavSubItem("View All");
        navViewAllItem.patternPath = pattern.subdir.slice(0, pattern.subdir.indexOf(pattern.patternGroup) + pattern.patternGroup.length) + "/index.html";
        navViewAllItem.patternPartial = "viewall-" + pattern.patternGroup;

        bucket.patternItems.push(navViewAllItem);
        patternlab.viewAllPaths[bucketName].viewall = pattern.subdir.slice(0, pattern.subdir.indexOf(pattern.patternGroup) + pattern.patternGroup.length);

      }

      //add the bucket.
      patternlab.buckets.push(bucket);
      patternlab.bucketIndex.push(bucketName);

      //done

    } else {
      //find the bucket
      bucket = patternlab.buckets[bucketIndex];

      //assume the navSubItem does not exist.
      navSubItem = new of.oNavSubItem(navSubItemName);
      navSubItem.patternPath = pattern.patternLink;
      navSubItem.patternPartial = bucketName + "-" + pattern.patternName; //add the hyphenated name

      //add the patternState if it exists
      if (pattern.patternState) {
        navSubItem.patternState = pattern.patternState;
      }

      //test whether the pattern struture is flat or not - usually due to a template or page
      flatPatternItem = false;
      if (navItemName === bucketName) {
        flatPatternItem = true;
      }

      //if it is flat - we should not add the pattern to patternPaths
      if (flatPatternItem) {
        //add the navItem to patternItems
        bucket.patternItems.push(navSubItem);

        //add to patternPaths
        addToPatternPaths(patternlab, bucketName, pattern);

      } else {

        // only do this if pattern is included
        //check to see if navItem exists
        var navItemIndex = bucket.navItemsIndex.indexOf(navItemName);
        if (navItemIndex === -1) {
          navItem = new of.oNavItem(navItemName);

          //add the navItem and navSubItem
          navItem.navSubItems.push(navSubItem);
          navItem.navSubItemsIndex.push(navSubItemName);
          bucket.navItems.push(navItem);
          bucket.navItemsIndex.push(navItemName);

        } else {
          //add the navSubItem
          navItem = bucket.navItems[navItemIndex];
          navItem.navSubItems.push(navSubItem);
          navItem.navSubItemsIndex.push(navSubItemName);
        }

        //check if we are moving to a new sub section in the next loop
        if (!patternlab.patterns[i + 1] || pattern.patternSubGroup !== patternlab.patterns[i + 1].patternSubGroup) {

          //add the navViewAllSubItem
          var navViewAllSubItem = new of.oNavSubItem("");
          navViewAllSubItem.patternName = "View All";
          navViewAllSubItem.patternPath = pattern.flatPatternPath + "/index.html";
          navViewAllSubItem.patternPartial = "viewall-" + pattern.patternGroup + "-" + pattern.patternSubGroup;

          navItem.navSubItems.push(navViewAllSubItem);
          navItem.navSubItemsIndex.push("View All");
        }

        // just add to patternPaths
        addToPatternPaths(patternlab, bucketName, pattern);
      }
    }

    patternlab.viewAllPaths[bucketName][pattern.patternSubGroup] = pattern.flatPatternPath;
  }
  return bucketIndex;
}

function buildViewAllPages(mainPageHead, mainPageFoot, mainPageHeadHtml, mainPageFootHtml, pattern_assembler, patternlab) {
  var paths = patternlab.config.paths;
  var prevSubdir = '';
  var prevGroup = '';
  var i;

  for (i = 0; i < patternlab.patterns.length; i++) {
    // skip underscore-prefixed files
    if (isPatternExcluded(patternlab.patterns[i])) {
      if (patternlab.config.debug) {
        console.log('Omitting ' + patternlab.patterns[i].key + " from view all rendering.");
      }
      continue;
    }

    var pattern = patternlab.patterns[i];

    //create the view all for the section
    // check if the current section is different from the previous one
    if (pattern.patternGroup !== prevGroup) {
      prevGroup = pattern.patternGroup;

      var viewAllPatterns = [];
      var patternPartial = "viewall-" + pattern.patternGroup;
      var j;

      for (j = 0; j < patternlab.patterns.length; j++) {
        if (patternlab.patterns[j].patternGroup === pattern.patternGroup) {
          //again, skip any sibling patterns to the current one that may have underscores
          if (isPatternExcluded(patternlab.patterns[j])) {
            if (patternlab.config.debug) {
              console.log('Omitting ' + patternlab.patterns[j].key + " from view all sibling rendering.");
            }
            continue;
          }

          viewAllPatterns.push(patternlab.patterns[j]);
        }
      }

      var viewAllTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'templates/viewall.mustache'), 'utf8');
      var viewAllHtml = pattern_assembler.renderPattern(viewAllTemplate, {partials: viewAllPatterns, patternPartial: patternPartial, cacheBuster: patternlab.cacheBuster });
      fs.outputFileSync(paths.public.patterns + pattern.subdir.slice(0, pattern.subdir.indexOf(pattern.patternGroup) + pattern.patternGroup.length) + '/index.html', mainPageHead + viewAllHtml + mainPageFoot);
    }

    //create the view all for the subsection
    // check if the current sub section is different from the previous one
    if (pattern.subdir !== prevSubdir) {
      prevSubdir = pattern.subdir;

      viewAllPatterns = [];
      patternPartial = "viewall-" + pattern.patternGroup + "-" + pattern.patternSubGroup;

      for (j = 0; j < patternlab.patterns.length; j++) {
        if (patternlab.patterns[j].subdir === pattern.subdir) {
          //again, skip any sibling patterns to the current one that may have underscores
          if (isPatternExcluded(patternlab.patterns[j])) {
            if (patternlab.config.debug) {
              console.log('Omitting ' + patternlab.patterns[j].key + " from view all sibling rendering.");
            }
            continue;
          }

          viewAllPatterns.push(patternlab.patterns[j]);
        }
      }

      var viewAllTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'templates/viewall.mustache'), 'utf8');
      var viewAllHtml = pattern_assembler.renderPattern(viewAllTemplate, {partials: viewAllPatterns, patternPartial: patternPartial, cacheBuster: patternlab.cacheBuster});
      fs.outputFileSync(paths.public.patterns + pattern.flatPatternPath + '/index.html', mainPageHeadHtml + viewAllHtml + mainPageFootHtml);
    }
  }
}

function sortPatterns(patternsArray) {
  return patternsArray.sort(function (a, b) {
    if (a.name > b.name) {
      return 1;
    }
    if (a.name < b.name) {
      return -1;
    }

    // a must be equal to b
    return 0;
  });
}

// MAIN BUILDER FUNCTION

function buildFrontEnd(patternlab) {
  var pa = require('./pattern_assembler');
  var mh = require('./media_hunter');
  var pattern_assembler = new pa();
  var media_hunter = new mh();
  var styleguidePatterns = [];
  var paths = patternlab.config.paths;

  patternlab.buckets = [];
  patternlab.bucketIndex = [];
  patternlab.patternPaths = {};
  patternlab.viewAllPaths = {};

  //sort all patterns explicitly.
  patternlab.patterns = sortPatterns(patternlab.patterns);

  //find mediaQueries
  media_hunter.find_media_queries('./source/css', patternlab);

  // check if patterns are excluded, if not add them to styleguidePatterns
  styleguidePatterns = assembleStyleguidePatterns(patternlab);

  //also add the cachebuster value. slight chance this could collide with a user that has defined cacheBuster as a value
  patternlab.data.cacheBuster = patternlab.cacheBuster;

  //get the main page head and foot and render them
  var mainPageHead = patternlab.userHead.extendedTemplate.replace('{% pattern-lab-head %}', patternlab.header);
  var mainPageHeadHtml = pattern_assembler.renderPattern(mainPageHead, patternlab.data);
  var mainPageFoot = patternlab.userFoot.extendedTemplate.replace('{% pattern-lab-foot %}', patternlab.footer);
  var mainPageFootHtml = pattern_assembler.renderPattern(mainPageFoot, patternlab.data);

  //build the styleguide
  var styleguideTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'templates/styleguide.mustache'), 'utf8');
  var styleguideHtml = pattern_assembler.renderPattern(styleguideTemplate, {partials: styleguidePatterns, cacheBuster: patternlab.cacheBuster});

  fs.outputFileSync(path.resolve(paths.public.styleguide, 'html/styleguide.html'), mainPageHeadHtml + styleguideHtml + mainPageFootHtml);

  //build the viewall pages
  buildViewAllPages(mainPageHead, mainPageFoot, mainPageHeadHtml, mainPageFootHtml, pattern_assembler, patternlab);

  //build the patternlab website
  var patternlabSiteTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'templates/index.mustache'), 'utf8');

  //loop through all patterns.to build the navigation
  //todo: refactor this someday
  //GTP: totally doing that right now
  buildNavigation(patternlab);

  //the patternlab site requires a lot of partials to be rendered!

  //patternNav
  var patternNavTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'templates/partials/patternNav.mustache'), 'utf8');
  var patternNavPartialHtml = pattern_assembler.renderPattern(patternNavTemplate, patternlab);

  //ishControls
  var ishControlsTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'templates/partials/ishControls.mustache'), 'utf8');
  patternlab.config.mqs = patternlab.mediaQueries;
  var ishControlsPartialHtml = pattern_assembler.renderPattern(ishControlsTemplate, patternlab.config);

  //patternPaths
  var patternPathsTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'templates/partials/patternPaths.mustache'), 'utf8');
  var patternPathsPartialHtml = pattern_assembler.renderPattern(patternPathsTemplate, {'patternPaths': JSON.stringify(patternlab.patternPaths)});

  //viewAllPaths
  var viewAllPathsTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'templates/partials/viewAllPaths.mustache'), 'utf8');
  var viewAllPathsPartialHtml = pattern_assembler.renderPattern(viewAllPathsTemplate, {'viewallpaths': JSON.stringify(patternlab.viewAllPaths)});

  //render the patternlab template, with all partials
  var patternlabSiteHtml = pattern_assembler.renderPattern(patternlabSiteTemplate, {
    defaultPattern: patternlab.config.defaultPattern || 'all',
    cacheBuster: patternlab.cacheBuster
  }, {
    'ishControls': ishControlsPartialHtml,
    'patternNav': patternNavPartialHtml,
    'patternPaths': patternPathsPartialHtml,
    'viewAllPaths': viewAllPathsPartialHtml
  });
  fs.outputFileSync(path.resolve(paths.public.root, 'index.html'), patternlabSiteHtml);
}

module.exports = buildFrontEnd;
<|endoftext|>


<commit_before>/**
 *
 * This component is the skeleton around the actual pages, and should only
 * contain code that should be seen on all pages. (e.g. navigation bar)
 *
 */

import React from 'react';
import { useIntl } from 'react-intl';
import { CheckPagePermissions, NoContent } from '@strapi/helper-plugin';
import { Layout, HeaderLayout, ContentLayout } from '@strapi/parts/Layout';
import { Main } from '@strapi/parts/Main';
import pluginPermissions from '../../permissions';
import { getTrad } from '../../utils';
// import HomePage from '../HomePage';

const ComingSoon = () => {
  const { formatMessage } = useIntl();
  console.log(pluginPermissions);

  return (
    <Layout>
      <Main>
        <HeaderLayout
          title={formatMessage({
            id: getTrad('plugin.name'),
            defaultMessage: 'Documentation',
          })}
        />
        <ContentLayout>
          <NoContent
            content={{
              id: getTrad('coming.soon'),
              defaultMessage:
                'This content is currently under construction and will be back in a few weeks!',
            }}
          />
        </ContentLayout>
      </Main>
    </Layout>
  );
};

function App() {
  return (
    <CheckPagePermissions permissions={pluginPermissions.main}>
      {/* <HomePage /> */}
      <ComingSoon />
    </CheckPagePermissions>
  );
}

export default App;
<commit_msg>Remove log<commit_after>/**
 *
 * This component is the skeleton around the actual pages, and should only
 * contain code that should be seen on all pages. (e.g. navigation bar)
 *
 */

import React from 'react';
import { useIntl } from 'react-intl';
import { CheckPagePermissions, NoContent } from '@strapi/helper-plugin';
import { Layout, HeaderLayout, ContentLayout } from '@strapi/parts/Layout';
import { Main } from '@strapi/parts/Main';
import pluginPermissions from '../../permissions';
import { getTrad } from '../../utils';
// import HomePage from '../HomePage';

const ComingSoon = () => {
  const { formatMessage } = useIntl();

  return (
    <Layout>
      <Main>
        <HeaderLayout
          title={formatMessage({
            id: getTrad('plugin.name'),
            defaultMessage: 'Documentation',
          })}
        />
        <ContentLayout>
          <NoContent
            content={{
              id: getTrad('coming.soon'),
              defaultMessage:
                'This content is currently under construction and will be back in a few weeks!',
            }}
          />
        </ContentLayout>
      </Main>
    </Layout>
  );
};

function App() {
  return (
    <CheckPagePermissions permissions={pluginPermissions.main}>
      {/* <HomePage /> */}
      <ComingSoon />
    </CheckPagePermissions>
  );
}

export default App;
<|endoftext|>


<commit_before>"use strict";

module.exports = function defaultTemplate(cfg) {
    const data = cfg.data;
    const head = cfg.head;
    const html = cfg.html;

    const wildcatConfig = cfg.wildcatConfig;
    const clientSettings = wildcatConfig.clientSettings;
    const generalSettings = wildcatConfig.generalSettings;

    const entry = clientSettings.entry;
    const hotReload = clientSettings.hotReload;
    const hotReloader = clientSettings.hotReloader;
    const renderHandler = clientSettings.renderHandler;
    const reactRootElementID = clientSettings.reactRootElementID;
    const indexedDBModuleCache = clientSettings.indexedDBModuleCache;

    const staticUrl = generalSettings.staticUrl;
    const socketUrl = staticUrl.replace("http", "ws");

    return `
<!doctype html>

        <meta charset="utf-8" />
        ${head.title.toString()}
        ${head.meta.toString()}
        ${head.link.toString()}

${html}

        ${indexedDBModuleCache ? `
        ` : ``}

`.trim();
};
<commit_msg>fix(react-wildcat-handoff): Expire client-side cache on server restart<commit_after>"use strict";

const NOW = Date.now();

module.exports = function defaultTemplate(cfg) {
    const data = cfg.data;
    const head = cfg.head;
    const html = cfg.html;

    const wildcatConfig = cfg.wildcatConfig;
    const clientSettings = wildcatConfig.clientSettings;
    const generalSettings = wildcatConfig.generalSettings;

    const entry = clientSettings.entry;
    const hotReload = clientSettings.hotReload;
    const hotReloader = clientSettings.hotReloader;
    const renderHandler = clientSettings.renderHandler;
    const reactRootElementID = clientSettings.reactRootElementID;
    const indexedDBModuleCache = clientSettings.indexedDBModuleCache;

    const staticUrl = generalSettings.staticUrl;
    const socketUrl = staticUrl.replace("http", "ws");

    return `
<!doctype html>

        <meta charset="utf-8" />
        ${head.title.toString()}
        ${head.meta.toString()}
        ${head.link.toString()}

${html}

        ${indexedDBModuleCache ? `
        ` : ``}

`.trim();
};
<|endoftext|>


<commit_before>// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The SFC licenses this file
// to you 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.

import { action, observable, computed, toJS } from "mobx";
import uuidv4 from "uuid/v4";
import naturalCompare from "string-natural-compare";
import TestCase from "../../models/TestCase";
import Suite from "../../models/Suite";

export default class ProjectStore {
  @observable id = uuidv4();
  @observable modified = false;
  @observable name = "";
  @observable url = "";
  @observable plugins = [];
  @observable _tests = [];
  @observable _suites = [];
  @observable _urls = [];

  constructor(name = "Untitled Project") {
    this.name = name;
    this.toJS = this.toJS.bind(this);
  }

  @computed get suites() {
    return this._suites.sort((s1, s2) => (
      naturalCompare(s1.name, s2.name)
    ));
  }

  @computed get tests() {
    return this._tests.sort((t1, t2) => (
      naturalCompare(t1.name, t2.name)
    ));
  }

  @computed get urls() {
    return this._urls.sort();
  }

  @action.bound setUrl(url) {
    this.url = url;
  }

  @action.bound addUrl(url) {
    this._urls.push(url);
  }

  @action.bound changeName(name) {
    this.name = name;
  }

  @action.bound setModified() {
    this.modified = true;
  }

  @action.bound createSuite(...argv) {
    const suite = new Suite(undefined, ...argv);
    this._suites.push(suite);

    return suite;
  }

  @action.bound deleteSuite(suite) {
    this._suites.remove(suite);
  }

  @action.bound createTestCase(...argv) {
    const test = new TestCase(undefined, ...argv);
    this.addTestCase(test);

    return test;
  }

  @action.bound addTestCase(test) {
    if (!test || test.constructor.name !== "TestCase") {
      throw new Error(`Expected to receive TestCase instead received ${test ? test.constructor.name : test}`);
    } else {
      let foundNumber = 0;
      // handle duplicate names -> name (1)
      // by using the sorted array we can do it in one read of the array
      this.tests.forEach((t) => {
        if (t.name === (foundNumber ? `${test.name} (${foundNumber})` : test.name))
          foundNumber++;
      });
      if (foundNumber) {
        test.name = `${test.name} (${foundNumber})`;
      }
      this._tests.push(test);
    }
  }

  @action.bound deleteTestCase(test) {
    if (!test || test.constructor.name !== "TestCase") {
      throw new Error(`Expected to receive TestCase instead received ${test ? test.constructor.name : test}`);
    } else {
      this.suites.forEach(suite => {
        suite.removeTestCase(test);
      });
      this._tests.remove(test);
    }
  }

  @action.bound registerPlugin(plugin) {
    const existsInPlugins = this.plugins.findIndex(p => p.id === plugin.id);
    if (existsInPlugins !== -1) {
      this.plugins[existsInPlugins] = plugin;
    } else {
      this.plugins.push(plugin);
    }
  }

  @action.bound fromJS(jsRep) {
    this.name = jsRep.name;
    this.setUrl(jsRep.url);
    this._tests.replace(jsRep.tests.map(TestCase.fromJS));
    this._suites.replace(jsRep.suites.map((suite) => Suite.fromJS(suite, this.tests)));
    this._urls.replace(jsRep.urls);
    this.plugins.replace(jsRep.plugins);
    this.id = jsRep.id || uuidv4();
    this.modified = false;
  }

  toJS() {
    return toJS({
      id: this.id,
      name: this.name,
      url: this.url,
      tests: this._tests.map(t => t.export()),
      suites: this._suites.map(s => s.export()),
      urls: this._urls,
      plugins: this.plugins
    });
  }
}
<commit_msg>keep the url bar unique<commit_after>// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The SFC licenses this file
// to you 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.

import { action, observable, computed, toJS } from "mobx";
import uuidv4 from "uuid/v4";
import naturalCompare from "string-natural-compare";
import TestCase from "../../models/TestCase";
import Suite from "../../models/Suite";

export default class ProjectStore {
  @observable id = uuidv4();
  @observable modified = false;
  @observable name = "";
  @observable url = "";
  @observable plugins = [];
  @observable _tests = [];
  @observable _suites = [];
  @observable _urls = [];

  constructor(name = "Untitled Project") {
    this.name = name;
    this.toJS = this.toJS.bind(this);
  }

  @computed get suites() {
    return this._suites.sort((s1, s2) => (
      naturalCompare(s1.name, s2.name)
    ));
  }

  @computed get tests() {
    return this._tests.sort((t1, t2) => (
      naturalCompare(t1.name, t2.name)
    ));
  }

  @computed get urls() {
    return this._urls.sort();
  }

  @action.bound setUrl(url) {
    this.url = url;
  }

  @action.bound addUrl(url) {
    if (!this._urls.find((u) => (u === url)))
      this._urls.push(url);
  }

  @action.bound addCurrentUrl() {
    this.addUrl(this.url);
  }

  @action.bound changeName(name) {
    this.name = name;
  }

  @action.bound setModified() {
    this.modified = true;
  }

  @action.bound createSuite(...argv) {
    const suite = new Suite(undefined, ...argv);
    this._suites.push(suite);

    return suite;
  }

  @action.bound deleteSuite(suite) {
    this._suites.remove(suite);
  }

  @action.bound createTestCase(...argv) {
    const test = new TestCase(undefined, ...argv);
    this.addTestCase(test);

    return test;
  }

  @action.bound addTestCase(test) {
    if (!test || test.constructor.name !== "TestCase") {
      throw new Error(`Expected to receive TestCase instead received ${test ? test.constructor.name : test}`);
    } else {
      let foundNumber = 0;
      // handle duplicate names -> name (1)
      // by using the sorted array we can do it in one read of the array
      this.tests.forEach((t) => {
        if (t.name === (foundNumber ? `${test.name} (${foundNumber})` : test.name))
          foundNumber++;
      });
      if (foundNumber) {
        test.name = `${test.name} (${foundNumber})`;
      }
      this._tests.push(test);
    }
  }

  @action.bound deleteTestCase(test) {
    if (!test || test.constructor.name !== "TestCase") {
      throw new Error(`Expected to receive TestCase instead received ${test ? test.constructor.name : test}`);
    } else {
      this.suites.forEach(suite => {
        suite.removeTestCase(test);
      });
      this._tests.remove(test);
    }
  }

  @action.bound registerPlugin(plugin) {
    const existsInPlugins = this.plugins.findIndex(p => p.id === plugin.id);
    if (existsInPlugins !== -1) {
      this.plugins[existsInPlugins] = plugin;
    } else {
      this.plugins.push(plugin);
    }
  }

  @action.bound fromJS(jsRep) {
    this.name = jsRep.name;
    this.setUrl(jsRep.url);
    this._tests.replace(jsRep.tests.map(TestCase.fromJS));
    this._suites.replace(jsRep.suites.map((suite) => Suite.fromJS(suite, this.tests)));
    this._urls.replace(jsRep.urls);
    this.plugins.replace(jsRep.plugins);
    this.id = jsRep.id || uuidv4();
    this.modified = false;
  }

  toJS() {
    return toJS({
      id: this.id,
      name: this.name,
      url: this.url,
      tests: this._tests.map(t => t.export()),
      suites: this._suites.map(s => s.export()),
      urls: this._urls,
      plugins: this.plugins
    });
  }
}
<|endoftext|>


<commit_before>
var _ = require('underscore');

var Service = exports.Service = function (options) {
    this._system = options.system;
    this._methods = options.methods;
    this.name = options.system.name;

    var ServiceInstance = this.ServiceInstance = function (system, socket, session) {
	this.system = system;
	this.socket = socket;
	this.session = session;
    };

    _.extend(ServiceInstance.prototype, options.methods, {
	trigger: function (name, data) {
	    var _this = this;
	    this.socket.emit(_this.system.channel, {
		subject: 'trigger'
		, trigger: name
		, data: data
	    });
	}
    });
};

_.extend(Service.prototype, {
    serve: function (socket, session) {
	var _service = this;
	socket.on(_service._system.name, function (msg) {
	    if (_service._methods.hasOwnProperty(msg.method)) {
		var instance = new _service.ServiceInstance(_service._system.get(msg.id), socket, session);
		instance[msg.method](msg.data);
	    }
	    else {
		console.log('ignored service call ', msg);
	    }
	});
	socket.emit(_service._system.name);
    }
});<commit_msg>Add service responses in service.<commit_after>
var _ = require('underscore');

var Service = exports.Service = function (options) {
    this._system = options.system;
    this._methods = options.methods;
    this.name = options.system.name;

    var ServiceInstance = this.ServiceInstance = function (system, socket, session) {
	this.system = system;
	this.socket = socket;
	this.session = session;
    };

    _.extend(ServiceInstance.prototype, options.methods, {
	trigger: function (name, data) {
	    var _this = this;
	    this.socket.emit(_this.system.channel, {
		subject: 'trigger'
		, trigger: name
		, data: data
	    });
	}
    });
};

_.extend(Service.prototype, {
    serve: function (socket, session) {
	var _service = this
	, name = _service._system.name
	;
	socket.on(name, function (msg) {
	    if (_service._methods.hasOwnProperty(msg.method)) {
		var instance = new _service.ServiceInstance(_service._system.get(msg.id), socket, session);
		instance[msg.method](msg.data);
	    }
	    else if (msg.check) {
		socket.emit(name);
	    }
	    else {
		console.log('ignored service call ', msg);
	    }
	});
	socket.emit(_service._system.name);
    }
});<|endoftext|>


<commit_before>/*
 * Copyright 2013-2017 the original author or authors.
 *
 * 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.
 */

/* global glowroot, moment, HandlebarsRendering */

glowroot.filter('gtBytes', function () {
  return HandlebarsRendering.formatBytes;
});

glowroot.filter('gtMillis', function () {
  return HandlebarsRendering.formatMillis;
});

glowroot.filter('gtCount', function () {
  return HandlebarsRendering.formatCount;
});

glowroot.filter('gtDuration', function () {
  return function (input) {
    if (input === undefined) {
      return '';
    }
    var duration = moment.duration(input);
    var parts = [];
    if (duration.days() >= 1) {
      parts.push(Math.floor(duration.days()) + 'd');
    }
    if (duration.hours() >= 1) {
      parts.push(Math.floor(duration.hours()) + 'h');
    }
    if (duration.minutes() >= 1) {
      parts.push(Math.floor(duration.minutes()) + 'm');
    }
    if (duration.seconds() >= 1) {
      parts.push(Math.floor(duration.seconds()) + 's');
    }
    return parts.join(' ');
  };
});

glowroot.filter('gtGaugeValue', function () {
  return function (value) {
    var nonScaledValue;
    if (value < 1000000) {
      nonScaledValue = parseFloat(value.toPrecision(6));
    } else {
      nonScaledValue = Math.round(value);
    }
    return nonScaledValue.toLocaleString(undefined, {maximumFractionDigits: 20});
  };
});

glowroot.filter('gtOnOff', function () {
  return function (input) {
    return input ? 'ON' : 'OFF';
  };
});

glowroot.filter('gtTypeaheadClassHighlight', [
  '$sce',
  function ($sce) {
    function escapeRegexp(queryToEscape) {
      return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
    }
    return function (matchItem, query) {
      if (!query) {
        return matchItem;
      }
      matchItem = matchItem.replace(new RegExp('^' + escapeRegexp(query), 'gi'), '$&');
      matchItem = matchItem.replace(new RegExp('\\.(' + escapeRegexp(query) + ')', 'gi'), '.$1');
      matchItem = matchItem.replace(new RegExp('\\$(' + escapeRegexp(query) + ')', 'gi'), '$$1');
      return $sce.trustAsHtml(matchItem);
    };
  }
]);
<commit_msg>Improve incident duration display<commit_after>/*
 * Copyright 2013-2017 the original author or authors.
 *
 * 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.
 */

/* global glowroot, moment, HandlebarsRendering */

glowroot.filter('gtBytes', function () {
  return HandlebarsRendering.formatBytes;
});

glowroot.filter('gtMillis', function () {
  return HandlebarsRendering.formatMillis;
});

glowroot.filter('gtCount', function () {
  return HandlebarsRendering.formatCount;
});

glowroot.filter('gtDuration', function () {
  return function (input) {
    if (input === undefined) {
      return '';
    }
    var duration = moment.duration(input);
    var parts = [];
    var days = duration.days();
    if (days >= 1) {
      parts.push(Math.floor(days) + 'd');
    }
    var hours = duration.hours();
    if (parts.length || hours >= 1) {
      parts.push(Math.floor(hours) + 'h');
    }
    var minutes = duration.minutes();
    if (parts.length || minutes >= 1) {
      parts.push(Math.floor(minutes) + 'm');
    }
    var seconds = duration.seconds();
    if (parts.length || seconds >= 1) {
      parts.push(Math.floor(seconds) + 's');
    }
    if (!parts.length) {
      return input + 'ms';
    }
    return parts.join(' ');
  };
});

glowroot.filter('gtGaugeValue', function () {
  return function (value) {
    var nonScaledValue;
    if (value < 1000000) {
      nonScaledValue = parseFloat(value.toPrecision(6));
    } else {
      nonScaledValue = Math.round(value);
    }
    return nonScaledValue.toLocaleString(undefined, {maximumFractionDigits: 20});
  };
});

glowroot.filter('gtOnOff', function () {
  return function (input) {
    return input ? 'ON' : 'OFF';
  };
});

glowroot.filter('gtTypeaheadClassHighlight', [
  '$sce',
  function ($sce) {
    function escapeRegexp(queryToEscape) {
      return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
    }
    return function (matchItem, query) {
      if (!query) {
        return matchItem;
      }
      matchItem = matchItem.replace(new RegExp('^' + escapeRegexp(query), 'gi'), '$&');
      matchItem = matchItem.replace(new RegExp('\\.(' + escapeRegexp(query) + ')', 'gi'), '.$1');
      matchItem = matchItem.replace(new RegExp('\\$(' + escapeRegexp(query) + ')', 'gi'), '$$1');
      return $sce.trustAsHtml(matchItem);
    };
  }
]);
<|endoftext|>


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

"use strict";

treeherder.controller('MainCtrl', [
    '$scope', '$rootScope', '$routeParams', '$location', 'ThLog',
    'ThRepositoryModel', 'thPinboard',
    'thClassificationTypes', 'thEvents', '$interval', '$window',
    'ThExclusionProfileModel', 'thJobFilters', 'ThResultSetStore',
    'thDefaultRepo',
    function MainController(
        $scope, $rootScope, $routeParams, $location, ThLog,
        ThRepositoryModel, thPinboard,
        thClassificationTypes, thEvents, $interval, $window,
        ThExclusionProfileModel, thJobFilters, ThResultSetStore,
        thDefaultRepo) {

        var $log = new ThLog("MainCtrl");

        thClassificationTypes.load();

        $rootScope.getWindowTitle = function() {
            var ufc = $scope.getUnclassifiedFailureCount($rootScope.repoName);
            return "[" + ufc + "] " + $rootScope.repoName;
        };

        $scope.closeJob = function() {
            // Setting the selectedJob to null closes the bottom panel
            $rootScope.selectedJob = null;

            // Clear the selected job display style
            $rootScope.$emit(thEvents.clearJobStyles, $rootScope.selectedJob);

            // Reset selected job to null to initialize nav position
            ThResultSetStore.setSelectedJob($rootScope.repoName);
        };

        // Clear the job if it occurs in a particular area
        $scope.clearJobOnClick = function(event) {
            var element = event.target;
            // Suppress for various UI elements so selection is preserved
            var ignoreClear = element.hasAttribute("ignore-job-clear-on-click");

            if (!ignoreClear) {
                $scope.closeJob();
            }
        };

        // Disable single key shortcuts in specified shortcut events
        $scope.allowKeys = function() {
            Mousetrap.unbind(['i', 'j', 'n', 'k', 'p', 'space', 'u', 'r', 'c', 'f']);
        };

        // Process shortcut events
        $scope.processKeyboardInput = function(ev) {

            /* If the user is in an editable element or pressing shift
             * then disable keyboard events, unless otherwise enabled
             * in inputs by the 'mousetrap' class in markup */
            var activeElement = document.activeElement;
            if (activeElement.tagName === 'INPUT' ||
                activeElement.tagName === 'SELECT' ||
                activeElement.tagName === 'TEXTAREA' ||
                activeElement.isContentEditable || ev.keyCode === 16) {
                return;
            }

            /* In some cases we need to handle the digest cycle otherwise
             * we will see interaction delays. Where needed we use $scope.$evalAsync
             * for optimization but may use $timeout or $digest if required */

            // Shortcut: toggle display in-progress jobs (pending/running)
            Mousetrap.bind('i', function() {
                $scope.$evalAsync($scope.toggleInProgress());
            });

            // Shortcut: select previous job
            Mousetrap.bind('left', function() {
                $rootScope.$emit(thEvents.changeSelection,'previous');
            });

            // Shortcut: select next job
            Mousetrap.bind('right', function() {
                $rootScope.$emit(thEvents.changeSelection,'next');
            });

            // Shortcut: select next unclassified failure
            Mousetrap.bind(['j', 'n'], function() {
                $rootScope.$emit(thEvents.selectNextUnclassifiedFailure);
            });

            // Shortcut: select previous unclassified failure
            Mousetrap.bind(['k', 'p'], function() {
                $rootScope.$emit(thEvents.selectPreviousUnclassifiedFailure);
            });

            // Shortcut: pin selected job to pinboard
            Mousetrap.bind('space', function(ev) {
                // If a job is selected add it otherwise
                // let the browser handle the spacebar
                if ($scope.selectedJob) {
                    // Prevent page down propagating to the jobs panel
                    ev.preventDefault();

                    $scope.$evalAsync(
                        $rootScope.$emit(thEvents.jobPin, $rootScope.selectedJob)
                    );
                }
            });

            // Shortcut: display only unclassified failures
            Mousetrap.bind('u', function() {
                $scope.$evalAsync($scope.toggleUnclassifiedFailures);
            });

            // Shortcut: pin selected job to pinboard and add a related bug
            Mousetrap.bind('r', function(ev) {
                if ($scope.selectedJob) {
                    $rootScope.$emit(thEvents.addRelatedBug,
                                     $rootScope.selectedJob);

                    // Prevent shortcut key overflow during focus
                    ev.preventDefault();

                    $scope.$evalAsync(
                        $rootScope.$broadcast('focus-this', "related-bug-input")
                    );

                    /* Treat single key shortcuts as regular text during input.
                     * This prevents invocation of single key hotkeys like 'c'
                     * during bug number entry, which would cross focus the
                     * comments field. We validate numbers via the markup. */
                    $scope.$evalAsync($scope.allowKeys());
                }
            });

            // Shortcut: pin selected job to pinboard and enter classification
            Mousetrap.bind('c', function(ev) {
                if ($scope.selectedJob) {
                    $scope.$evalAsync(
                        $rootScope.$emit(thEvents.jobPin, $rootScope.selectedJob)
                    );

                    // Prevent shortcut key overflow during focus
                    ev.preventDefault();

                    $scope.$evalAsync(
                        $rootScope.$broadcast('focus-this', "classification-comment")
                    );

                    // Treat single key shortcuts as regular text during input
                    $scope.$evalAsync($scope.allowKeys());
                }
            });

            // Shortcut: enter a custom job or platform filter
            Mousetrap.bind('f', function(ev) {
                // Prevent shortcut key overflow during focus
                ev.preventDefault();

                angular.element('#platform-job-text-search-field').trigger('click');
            });

            // Shortcut: escape closes any open panels and clears selected job
            Mousetrap.bind('escape', function() {
                $scope.$evalAsync($scope.setFilterPanelShowing(false));
                $scope.$evalAsync($scope.setSettingsPanelShowing(false));
                $scope.$evalAsync($scope.setSheriffPanelShowing(false));
                $scope.$evalAsync($scope.closeJob());
            });

            // Shortcut: clear the pinboard
            Mousetrap.bind('ctrl+shift+u', function() {
                $scope.$evalAsync($rootScope.$emit(thEvents.clearPinboard));
            });

            // Shortcut: save pinboard classification and related bugs
            Mousetrap.bind('ctrl+enter', function() {
                $scope.$evalAsync($rootScope.$emit(thEvents.saveClassification));
            });

        };

        $scope.repoModel = ThRepositoryModel;

        $scope.getTopNavBarHeight = function() {
            return $("#th-global-top-nav-panel").find("#top-nav-main-panel").height();
        };

        // adjust the body padding so we can see all the job/resultset data
        // if the top navbar height has changed due to window width changes
        // or adding enough watched repos to wrap.
        $rootScope.$watch($scope.getTopNavBarHeight, function(newValue) {
            $("body").css("padding-top", newValue);
        });

        /**
         * The watched repos in the nav bar can be either on the left or the
         * right side of the screen and the drop-down menu may get cut off
         * if it pulls right while on the left side of the screen.
         * And it can change any time the user re-sizes the window, so we must
         * check this each time a drop-down is invoked.
         */
        $scope.setDropDownPull = function(event) {
            $log.debug("dropDown", event.target);
            var element = event.target.offsetParent;
            if (element.offsetLeft > $(window).width() / 2) {
                $(element).find(".dropdown-menu").addClass("pull-right");
            } else {
                $(element).find(".dropdown-menu").removeClass("pull-right");
            }

        };

        $scope.getUnclassifiedFailureCount = function(repoName) {
            return ThResultSetStore.getUnclassifiedFailureCount(repoName);
        };

        $scope.isSkippingExclusionProfiles = $location.search().exclusion_profile === 'false';

        $scope.toggleExcludedJobs = function() {
            if ($location.search().exclusion_profile === 'false') {
                $location.search('exclusion_profile', null);
            }else{
                $location.search('exclusion_profile', 'false');
            }
        };

        $scope.toggleUnclassifiedFailures = thJobFilters.toggleUnclassifiedFailures;

        $scope.toggleInProgress = function() {
            thJobFilters.toggleInProgress();
        };

        $scope.allExpanded = function(cls) {
            var fullList = $("." + cls);
            var visibleList = $("." + cls + ":visible");
            return fullList.length === visibleList.length;
        };

        $scope.allCollapsed = function(cls) {
            var visibleList = $("." + cls + ":visible");
            return visibleList.length === 0;
        };

        $scope.toggleAllJobsAndRevisions = function() {
            var collapse = ($scope.allCollapsed("job-list") &&
                            $scope.allCollapsed("revision-list"));
            $rootScope.$emit(
                thEvents.toggleAllJobs, collapse
            );
            $rootScope.$emit(
                thEvents.toggleAllRevisions, collapse
            );
        };

        $scope.toggleAllJobs = function(collapse) {
            collapse = collapse || $scope.allCollapsed("job-list");
            $rootScope.$emit(
                thEvents.toggleAllJobs, collapse
            );

        };

        $scope.toggleAllRevisions = function(collapse) {
            collapse = collapse || $scope.allCollapsed("revision-list");
            $rootScope.$emit(
                thEvents.toggleAllRevisions, collapse
            );

        };

        var getNewReloadTriggerParams = function() {
            return _.pick(
                $location.search(),
                ThResultSetStore.reloadOnChangeParameters
            );
        };

        $scope.cachedReloadTriggerParams = getNewReloadTriggerParams();

        // reload the page if certain params were changed in the URL.  For
        // others, such as filtering, just re-filter without reload.
        $rootScope.$on('$locationChangeSuccess', function() {

            // used to test for display of watched-repo-navbar
            $rootScope.locationPath = $location.path().replace('/', '');

            // used to avoid bad urls when the app redirects internally
            $rootScope.urlBasePath = $location.absUrl().split('?')[0];

            var newReloadTriggerParams = getNewReloadTriggerParams();
            // if we are just setting the repo to the default because none was
            // set initially, then don't reload the page.
            var defaulting = newReloadTriggerParams.repo === thDefaultRepo &&
                             !$scope.cachedReloadTriggerParams.repo;

            if (!defaulting && $scope.cachedReloadTriggerParams &&
                !_.isEqual(newReloadTriggerParams, $scope.cachedReloadTriggerParams)) {

                $window.location.reload();
            } else {
                $scope.cachedReloadTriggerParams = newReloadTriggerParams;
            }
        });

        $scope.changeRepo = function(repo_name) {
            //clear all filter params and revisions...
            $location.search({"repo": repo_name});
        };

        $scope.isFilterPanelShowing = false;
        $scope.setFilterPanelShowing = function(tf) {
            $scope.isFilterPanelShowing = tf;
        };

        $scope.isSettingsPanelShowing = false;
        $scope.setSettingsPanelShowing = function(tf) {
            $scope.isSettingsPanelShowing = tf;
        };

        $scope.isSheriffPanelShowing = false;
        $scope.setSheriffPanelShowing = function(tf) {
            if (tf) {
                // lazy fetching of exclusion profiles, because we don't
                // need them unless you're editing them on this page
                $rootScope.$emit(thEvents.initSheriffPanel);
            }
            $scope.isSheriffPanelShowing = tf;
        };

        $scope.pinboardCount = thPinboard.count;
        $scope.pinnedJobs = thPinboard.pinnedJobs;

    }
]);
<commit_msg>Bug 1089737 - Unbind left/right navigation in mousetrap inputs<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, you can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

treeherder.controller('MainCtrl', [
    '$scope', '$rootScope', '$routeParams', '$location', 'ThLog',
    'ThRepositoryModel', 'thPinboard',
    'thClassificationTypes', 'thEvents', '$interval', '$window',
    'ThExclusionProfileModel', 'thJobFilters', 'ThResultSetStore',
    'thDefaultRepo',
    function MainController(
        $scope, $rootScope, $routeParams, $location, ThLog,
        ThRepositoryModel, thPinboard,
        thClassificationTypes, thEvents, $interval, $window,
        ThExclusionProfileModel, thJobFilters, ThResultSetStore,
        thDefaultRepo) {

        var $log = new ThLog("MainCtrl");

        thClassificationTypes.load();

        $rootScope.getWindowTitle = function() {
            var ufc = $scope.getUnclassifiedFailureCount($rootScope.repoName);
            return "[" + ufc + "] " + $rootScope.repoName;
        };

        $scope.closeJob = function() {
            // Setting the selectedJob to null closes the bottom panel
            $rootScope.selectedJob = null;

            // Clear the selected job display style
            $rootScope.$emit(thEvents.clearJobStyles, $rootScope.selectedJob);

            // Reset selected job to null to initialize nav position
            ThResultSetStore.setSelectedJob($rootScope.repoName);
        };

        // Clear the job if it occurs in a particular area
        $scope.clearJobOnClick = function(event) {
            var element = event.target;
            // Suppress for various UI elements so selection is preserved
            var ignoreClear = element.hasAttribute("ignore-job-clear-on-click");

            if (!ignoreClear) {
                $scope.closeJob();
            }
        };

        // Disable single key shortcuts in specified shortcut events
        $scope.allowKeys = function() {
            Mousetrap.unbind([
                'i',     // Toggle display in-progress jobs (pending/running)
                'j',     // Select next unclassified failure
                'n',     // Select next unclassified failure
                'k',     // Select previous unclassified failure
                'p',     // Select previous unclassified failure
                'space', // Pin selected job to pinboard
                'u',     // Display only unclassified failures
                'r',     // Pin selected job and add related bug
                'c',     // Pin selected job and add classification
                'f',     // Enter a custom job or platform filter
                'left',  // Select previous job
                'right'  // Select next job
            ]);
        };

        // Process shortcut events
        $scope.processKeyboardInput = function(ev) {

            /* If the user is in an editable element or pressing shift
             * then disable keyboard events, unless otherwise enabled
             * in inputs by the 'mousetrap' class in markup */
            var activeElement = document.activeElement;
            if (activeElement.tagName === 'INPUT' ||
                activeElement.tagName === 'SELECT' ||
                activeElement.tagName === 'TEXTAREA' ||
                activeElement.isContentEditable || ev.keyCode === 16) {
                return;
            }

            /* In some cases we need to handle the digest cycle otherwise
             * we will see interaction delays. Where needed we use $scope.$evalAsync
             * for optimization but may use $timeout or $digest if required */

            // Shortcut: toggle display in-progress jobs (pending/running)
            Mousetrap.bind('i', function() {
                $scope.$evalAsync($scope.toggleInProgress());
            });

            // Shortcut: select previous job
            Mousetrap.bind('left', function() {
                $rootScope.$emit(thEvents.changeSelection,'previous');
            });

            // Shortcut: select next job
            Mousetrap.bind('right', function() {
                $rootScope.$emit(thEvents.changeSelection,'next');
            });

            // Shortcut: select next unclassified failure
            Mousetrap.bind(['j', 'n'], function() {
                $rootScope.$emit(thEvents.selectNextUnclassifiedFailure);
            });

            // Shortcut: select previous unclassified failure
            Mousetrap.bind(['k', 'p'], function() {
                $rootScope.$emit(thEvents.selectPreviousUnclassifiedFailure);
            });

            // Shortcut: pin selected job to pinboard
            Mousetrap.bind('space', function(ev) {
                // If a job is selected add it otherwise
                // let the browser handle the spacebar
                if ($scope.selectedJob) {
                    // Prevent page down propagating to the jobs panel
                    ev.preventDefault();

                    $scope.$evalAsync(
                        $rootScope.$emit(thEvents.jobPin, $rootScope.selectedJob)
                    );
                }
            });

            // Shortcut: display only unclassified failures
            Mousetrap.bind('u', function() {
                $scope.$evalAsync($scope.toggleUnclassifiedFailures);
            });

            // Shortcut: pin selected job to pinboard and add a related bug
            Mousetrap.bind('r', function(ev) {
                if ($scope.selectedJob) {
                    $rootScope.$emit(thEvents.addRelatedBug,
                                     $rootScope.selectedJob);

                    // Prevent shortcut key overflow during focus
                    ev.preventDefault();

                    $scope.$evalAsync(
                        $rootScope.$broadcast('focus-this', "related-bug-input")
                    );

                    /* Treat single key shortcuts as regular text during input.
                     * This prevents invocation of single key hotkeys like 'c'
                     * during bug number entry, which would cross focus the
                     * comments field. We validate numbers via the markup. */
                    $scope.$evalAsync($scope.allowKeys());
                }
            });

            // Shortcut: pin selected job to pinboard and enter classification
            Mousetrap.bind('c', function(ev) {
                if ($scope.selectedJob) {
                    $scope.$evalAsync(
                        $rootScope.$emit(thEvents.jobPin, $rootScope.selectedJob)
                    );

                    // Prevent shortcut key overflow during focus
                    ev.preventDefault();

                    $scope.$evalAsync(
                        $rootScope.$broadcast('focus-this', "classification-comment")
                    );

                    // Treat single key shortcuts as regular text during input
                    $scope.$evalAsync($scope.allowKeys());
                }
            });

            // Shortcut: enter a custom job or platform filter
            Mousetrap.bind('f', function(ev) {
                // Prevent shortcut key overflow during focus
                ev.preventDefault();

                angular.element('#platform-job-text-search-field').trigger('click');
            });

            // Shortcut: escape closes any open panels and clears selected job
            Mousetrap.bind('escape', function() {
                $scope.$evalAsync($scope.setFilterPanelShowing(false));
                $scope.$evalAsync($scope.setSettingsPanelShowing(false));
                $scope.$evalAsync($scope.setSheriffPanelShowing(false));
                $scope.$evalAsync($scope.closeJob());
            });

            // Shortcut: clear the pinboard
            Mousetrap.bind('ctrl+shift+u', function() {
                $scope.$evalAsync($rootScope.$emit(thEvents.clearPinboard));
            });

            // Shortcut: save pinboard classification and related bugs
            Mousetrap.bind('ctrl+enter', function() {
                $scope.$evalAsync($rootScope.$emit(thEvents.saveClassification));
            });

        };

        $scope.repoModel = ThRepositoryModel;

        $scope.getTopNavBarHeight = function() {
            return $("#th-global-top-nav-panel").find("#top-nav-main-panel").height();
        };

        // adjust the body padding so we can see all the job/resultset data
        // if the top navbar height has changed due to window width changes
        // or adding enough watched repos to wrap.
        $rootScope.$watch($scope.getTopNavBarHeight, function(newValue) {
            $("body").css("padding-top", newValue);
        });

        /**
         * The watched repos in the nav bar can be either on the left or the
         * right side of the screen and the drop-down menu may get cut off
         * if it pulls right while on the left side of the screen.
         * And it can change any time the user re-sizes the window, so we must
         * check this each time a drop-down is invoked.
         */
        $scope.setDropDownPull = function(event) {
            $log.debug("dropDown", event.target);
            var element = event.target.offsetParent;
            if (element.offsetLeft > $(window).width() / 2) {
                $(element).find(".dropdown-menu").addClass("pull-right");
            } else {
                $(element).find(".dropdown-menu").removeClass("pull-right");
            }

        };

        $scope.getUnclassifiedFailureCount = function(repoName) {
            return ThResultSetStore.getUnclassifiedFailureCount(repoName);
        };

        $scope.isSkippingExclusionProfiles = $location.search().exclusion_profile === 'false';

        $scope.toggleExcludedJobs = function() {
            if ($location.search().exclusion_profile === 'false') {
                $location.search('exclusion_profile', null);
            }else{
                $location.search('exclusion_profile', 'false');
            }
        };

        $scope.toggleUnclassifiedFailures = thJobFilters.toggleUnclassifiedFailures;

        $scope.toggleInProgress = function() {
            thJobFilters.toggleInProgress();
        };

        $scope.allExpanded = function(cls) {
            var fullList = $("." + cls);
            var visibleList = $("." + cls + ":visible");
            return fullList.length === visibleList.length;
        };

        $scope.allCollapsed = function(cls) {
            var visibleList = $("." + cls + ":visible");
            return visibleList.length === 0;
        };

        $scope.toggleAllJobsAndRevisions = function() {
            var collapse = ($scope.allCollapsed("job-list") &&
                            $scope.allCollapsed("revision-list"));
            $rootScope.$emit(
                thEvents.toggleAllJobs, collapse
            );
            $rootScope.$emit(
                thEvents.toggleAllRevisions, collapse
            );
        };

        $scope.toggleAllJobs = function(collapse) {
            collapse = collapse || $scope.allCollapsed("job-list");
            $rootScope.$emit(
                thEvents.toggleAllJobs, collapse
            );

        };

        $scope.toggleAllRevisions = function(collapse) {
            collapse = collapse || $scope.allCollapsed("revision-list");
            $rootScope.$emit(
                thEvents.toggleAllRevisions, collapse
            );

        };

        var getNewReloadTriggerParams = function() {
            return _.pick(
                $location.search(),
                ThResultSetStore.reloadOnChangeParameters
            );
        };

        $scope.cachedReloadTriggerParams = getNewReloadTriggerParams();

        // reload the page if certain params were changed in the URL.  For
        // others, such as filtering, just re-filter without reload.
        $rootScope.$on('$locationChangeSuccess', function() {

            // used to test for display of watched-repo-navbar
            $rootScope.locationPath = $location.path().replace('/', '');

            // used to avoid bad urls when the app redirects internally
            $rootScope.urlBasePath = $location.absUrl().split('?')[0];

            var newReloadTriggerParams = getNewReloadTriggerParams();
            // if we are just setting the repo to the default because none was
            // set initially, then don't reload the page.
            var defaulting = newReloadTriggerParams.repo === thDefaultRepo &&
                             !$scope.cachedReloadTriggerParams.repo;

            if (!defaulting && $scope.cachedReloadTriggerParams &&
                !_.isEqual(newReloadTriggerParams, $scope.cachedReloadTriggerParams)) {

                $window.location.reload();
            } else {
                $scope.cachedReloadTriggerParams = newReloadTriggerParams;
            }
        });

        $scope.changeRepo = function(repo_name) {
            //clear all filter params and revisions...
            $location.search({"repo": repo_name});
        };

        $scope.isFilterPanelShowing = false;
        $scope.setFilterPanelShowing = function(tf) {
            $scope.isFilterPanelShowing = tf;
        };

        $scope.isSettingsPanelShowing = false;
        $scope.setSettingsPanelShowing = function(tf) {
            $scope.isSettingsPanelShowing = tf;
        };

        $scope.isSheriffPanelShowing = false;
        $scope.setSheriffPanelShowing = function(tf) {
            if (tf) {
                // lazy fetching of exclusion profiles, because we don't
                // need them unless you're editing them on this page
                $rootScope.$emit(thEvents.initSheriffPanel);
            }
            $scope.isSheriffPanelShowing = tf;
        };

        $scope.pinboardCount = thPinboard.count;
        $scope.pinnedJobs = thPinboard.pinnedJobs;

    }
]);
<|endoftext|>