<commit_before>import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Context from '../../Context';
import withContext from 'components/Wrappers/withContext';
import UsernameText from 'components/Texts/UsernameText';
import Button from 'components/Button';
import LikeButton from 'components/Buttons/LikeButton';
import Likers from 'components/Likers';
import { connect } from 'react-redux';
import UserListModal from 'components/Modals/UserListModal';
import InputForm from 'components/Texts/InputForm';
import Comment from './Comment';
import { borderRadius, Color } from 'constants/css';
import LongText from 'components/Texts/LongText';
import ContentLink from 'components/ContentLink';
import { timeSince } from 'helpers/timeStampHelpers';
import RewardStatus from 'components/RewardStatus';
import XPRewardInterface from 'components/XPRewardInterface';
import ErrorBoundary from 'components/Wrappers/ErrorBoundary';
import Icon from 'components/Icon';
import { determineXpButtonDisabled } from 'helpers';
import { uploadComment } from 'helpers/requestHelpers';
import { css } from 'emotion';

class TargetContent extends Component {
  static propTypes = {
    authLevel: PropTypes.number,
    canStar: PropTypes.bool,
    dispatch: PropTypes.func.isRequired,
    feedId: PropTypes.number,
    myId: PropTypes.number,
    onAttachStar: PropTypes.func.isRequired,
    onDeleteComment: PropTypes.func.isRequired,
    onEditComment: PropTypes.func.isRequired,
    onEditRewardComment: PropTypes.func.isRequired,
    onLikeContent: PropTypes.func.isRequired,
    onTargetCommentSubmit: PropTypes.func.isRequired,
    profilePicId: PropTypes.number,
    rootObj: PropTypes.object,
    rootType: PropTypes.string.isRequired,
    targetObj: PropTypes.object,
    username: PropTypes.string
  };

  state = {
    userListModalShown: false,
    replyInputShown: false,
    xpRewardInterfaceShown: false
  };

  render() {
    const {
      authLevel,
      canStar,
      myId,
      onAttachStar,
      onDeleteComment,
      onEditComment,
      onEditRewardComment,
      rootObj,
      profilePicId,
      rootType,
      targetObj: {
        subject,
        comment,
        comment: { comments = [], stars = [] } = {},
        type
      },
      username
    } = this.props;
    const {
      userListModalShown,
      replyInputShown,
      xpRewardInterfaceShown
    } = this.state;
    let userLikedThis = false;
    let userIsUploader;
    let userCanStarThis;
    let uploader = {};
    if (comment && !comment.notFound) {
      uploader = comment.uploader;
      for (let i = 0; i < comment.likes.length; i++) {
        if (comment.likes[i].id === myId) userLikedThis = true;
      }
      userIsUploader = myId === comment.uploader.id;
      userCanStarThis =
        !userIsUploader && canStar && authLevel > comment.uploader.authLevel;
    } else {
      uploader = subject?.uploader || uploader;
    }
    return (
      <ErrorBoundary
        className={css`
          font-size: 1.6rem;
          white-space: pre-wrap;
          overflow-wrap: break-word;
          word-break: break-word;
          border-radius: ${borderRadius};
          border-top: 1px solid ${Color.inputBorderGray()};
          border-bottom: 1px solid ${Color.inputBorderGray()};
          padding-top: 1rem;
          padding-right: 0;
          padding-left: 0;
          background: ${Color.wellGray()};
          margin-bottom: 2rem;
          line-height: 1.5;
          .buttons {
            margin-top: 2rem;
            display: flex;
            width: 100%;
            justify-content: space-between;
          }
          .detail-block {
            display: flex;
            justify-content: space-between;
          }
          .root-content {
            color: ${Color.darkerGray()};
            font-weight: bold;
          }
          .timestamp {
            color: ${Color.gray()};
            font-size: 1.2rem;
          }
        `}
        style={{
          paddingBottom:
            stars &&
            stars.length > 0 &&
            !replyInputShown &&
            !xpRewardInterfaceShown
              ? 0
              : '1rem'
        }}
      >

          {subject &&
            (subject.notFound ? (

                Subject removed / no longer available

            ) : (

                      <ContentLink
                        content={{ id: subject.id, title: 'Subject: ' }}
                        type="subject"
                        style={{ color: Color.green() }}
                      />

                      <UsernameText user={subject.uploader} />

                        ({timeSince(subject.timeStamp)})

                    {subject.title}

                  {subject.description && (
                    <LongText
                      className={css`
                        margin-top: 1rem;
                      `}
                    >
                      {subject.description}
                    </LongText>
                  )}

            ))}
          {comment &&
            (comment.notFound ? (

                Comment removed / no longer available

            ) : (

                        <UsernameText
                          user={comment.uploader}
                          color={Color.blue()}
                        />{' '}
                        <ContentLink
                          content={{
                            id: comment.id,
                            title: `${
                              type === 'reply'
                                ? 'replied'
                                : type === 'comment'
                                ? 'commented'
                                : 'responded'
                            }:`
                          }}
                          type="comment"
                          style={{ color: Color.green() }}
                        />

                          ({timeSince(comment.timeStamp)})

                    <LongText style={{ marginTop: '1rem' }}>
                      {comment.content}
                    </LongText>

                  <ErrorBoundary className="buttons">

 0 ? '0.5rem' : 0
                        }}
                      >
                        <LikeButton
                          contentType="comment"
                          contentId={comment.id}
                          onClick={this.onLikeClick}
                          liked={userLikedThis}
                          small
                        />
                        <Button
                          style={{ marginLeft: '1rem' }}
                          transparent
                          onClick={this.onReplyClick}
                        >
                          <Icon icon="comment-alt" />
                          Reply
                        </Button>

                      <Likers
                        className="content-panel__likes"
                        userId={myId}
                        likes={comment.likes}
                        onLinkClick={() =>
                          this.setState({ userListModalShown: true })
                        }
                      />

                      {canStar && userCanStarThis && (
                        <Button
                          love
                          disabled={this.determineXpButtonDisabled()}
                          onClick={() =>
                            this.setState({ xpRewardInterfaceShown: true })
                          }
                        >
                          <Icon icon="certificate" />

                            {this.determineXpButtonDisabled() || 'Reward'}

                        </Button>
                      )}

                  </ErrorBoundary>

                {xpRewardInterfaceShown && (
                  <XPRewardInterface
                    contentType={'comment'}
                    contentId={comment.id}
                    difficulty={this.determineDifficulty({
                      rootObj,
                      rootType,
                      subject
                    })}
                    uploaderId={comment.uploader.id}
                    stars={comment.stars}
                    onRewardSubmit={data => {
                      this.setState({ xpRewardInterfaceShown: false });
                      onAttachStar(data);
                    }}
                  />
                )}
                <RewardStatus
                  difficulty={this.determineDifficulty({
                    rootObj,
                    rootType,
                    subject
                  })}
                  onCommentEdit={onEditRewardComment}
                  style={{
                    marginTop:
                      comment.likes.length > 0 || xpRewardInterfaceShown
                        ? '0.5rem'
                        : '1rem'
                  }}
                  stars={comment.stars}
                  uploaderName={uploader.username}
                />
                {replyInputShown && (
                  <InputForm
                    innerRef={ref => (this.InputForm = ref)}
                    style={{
                      marginTop: comment.likes.length > 0 ? '0.5rem' : '1rem',
                      padding: '0 1rem'
                    }}
                    autoFocus
                    onSubmit={this.onSubmit}
                    rows={4}
                    placeholder={`Write a reply...`}
                  />
                )}
                {comments.length > 0 && (

                    {comments.map(comment => (
                      <Comment
                        key={comment.id}
                        comment={comment}
                        username={username}
                        userId={myId}
                        profilePicId={profilePicId}
                        onDelete={onDeleteComment}
                        onEditDone={onEditComment}
                      />
                    ))}

                )}
                {userListModalShown && (
                  <UserListModal
                    onHide={() => this.setState({ userListModalShown: false })}
                    title="People who liked this comment"
                    users={comment.likes}
                    description="(You)"
                  />
                )}

            ))}

      </ErrorBoundary>
    );
  }

  determineXpButtonDisabled = () => {
    const {
      targetObj: { type, comment, subject },
      myId,
      rootObj
    } = this.props;
    const { xpRewardInterfaceShown } = this.state;
    const stars =
      type === 'comment' || type === 'reply' ? comment.stars : subject.stars;
    return determineXpButtonDisabled({
      difficulty: rootObj.difficulty || subject?.difficulty,
      stars,
      myId,
      xpRewardInterfaceShown
    });
  };

  determineDifficulty = ({ rootType, rootObj, subject }) => {
    const rootDifficulty =
      rootType !== 'video'
        ? rootObj.difficulty
        : rootObj.difficulty > 0
        ? 1
        : 0;
    return subject?.difficulty || rootDifficulty;
  };

  onLikeClick = likes => {
    const {
      targetObj: { comment },
      onLikeContent
    } = this.props;
    onLikeContent({ likes, type: 'comment', contentId: comment.id });
  };

  onReplyClick = () => {
    const { replyInputShown } = this.state;
    if (!replyInputShown) return this.setState({ replyInputShown: true });
    this.InputForm.focus();
  };

  onSubmit = async content => {
    const {
      dispatch,
      feedId,
      rootType,
      rootObj,
      targetObj: { comment = {} },
      onTargetCommentSubmit
    } = this.props;
    const data = await uploadComment({
      content,
      parent: {
        type: rootType,
        id: rootObj.id
      },
      rootCommentId: comment.commentId,
      targetCommentId: comment.id,
      dispatch
    });
    if (data) onTargetCommentSubmit(data, feedId);
  };
}

export default connect(
  state => ({
    authLevel: state.UserReducer.authLevel,
    canStar: state.UserReducer.canStar,
    username: state.UserReducer.username,
    profilePicId: state.UserReducer.profilePicId
  }),
  dispatch => ({ dispatch })
)(withContext({ Component: TargetContent, Context }));
<commit_msg>minor bug fix<commit_after>import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Context from '../../Context';
import withContext from 'components/Wrappers/withContext';
import UsernameText from 'components/Texts/UsernameText';
import Button from 'components/Button';
import LikeButton from 'components/Buttons/LikeButton';
import Likers from 'components/Likers';
import { connect } from 'react-redux';
import UserListModal from 'components/Modals/UserListModal';
import InputForm from 'components/Texts/InputForm';
import Comment from './Comment';
import { borderRadius, Color } from 'constants/css';
import LongText from 'components/Texts/LongText';
import ContentLink from 'components/ContentLink';
import { timeSince } from 'helpers/timeStampHelpers';
import RewardStatus from 'components/RewardStatus';
import XPRewardInterface from 'components/XPRewardInterface';
import ErrorBoundary from 'components/Wrappers/ErrorBoundary';
import Icon from 'components/Icon';
import { determineXpButtonDisabled } from 'helpers';
import { uploadComment } from 'helpers/requestHelpers';
import { css } from 'emotion';

class TargetContent extends Component {
  static propTypes = {
    authLevel: PropTypes.number,
    canStar: PropTypes.bool,
    dispatch: PropTypes.func.isRequired,
    feedId: PropTypes.number,
    myId: PropTypes.number,
    onAttachStar: PropTypes.func.isRequired,
    onDeleteComment: PropTypes.func.isRequired,
    onEditComment: PropTypes.func.isRequired,
    onEditRewardComment: PropTypes.func.isRequired,
    onLikeContent: PropTypes.func.isRequired,
    onTargetCommentSubmit: PropTypes.func.isRequired,
    profilePicId: PropTypes.number,
    rootObj: PropTypes.object,
    rootType: PropTypes.string.isRequired,
    targetObj: PropTypes.object,
    username: PropTypes.string
  };

  state = {
    userListModalShown: false,
    replyInputShown: false,
    xpRewardInterfaceShown: false
  };

  render() {
    const {
      authLevel,
      canStar,
      myId,
      onAttachStar,
      onDeleteComment,
      onEditComment,
      onEditRewardComment,
      rootObj,
      profilePicId,
      rootType,
      targetObj: {
        subject,
        comment,
        comment: { comments = [], stars = [] } = {},
        type
      },
      username
    } = this.props;
    const {
      userListModalShown,
      replyInputShown,
      xpRewardInterfaceShown
    } = this.state;
    let userLikedThis = false;
    let userIsUploader;
    let userCanStarThis;
    let uploader = {};
    if (comment && !comment.notFound) {
      uploader = comment.uploader;
      for (let i = 0; i < comment.likes.length; i++) {
        if (comment.likes[i].id === myId) userLikedThis = true;
      }
      userIsUploader = myId === comment.uploader.id;
      userCanStarThis =
        !userIsUploader && canStar && authLevel > comment.uploader.authLevel;
    } else {
      uploader = subject?.uploader || uploader;
    }
    return (
      <ErrorBoundary
        className={css`
          font-size: 1.6rem;
          white-space: pre-wrap;
          overflow-wrap: break-word;
          word-break: break-word;
          border-radius: ${borderRadius};
          border-top: 1px solid ${Color.inputBorderGray()};
          border-bottom: 1px solid ${Color.inputBorderGray()};
          padding-top: 1rem;
          padding-right: 0;
          padding-left: 0;
          background: ${Color.wellGray()};
          margin-bottom: 2rem;
          line-height: 1.5;
          .buttons {
            margin-top: 2rem;
            display: flex;
            width: 100%;
            justify-content: space-between;
          }
          .detail-block {
            display: flex;
            justify-content: space-between;
          }
          .root-content {
            color: ${Color.darkerGray()};
            font-weight: bold;
          }
          .timestamp {
            color: ${Color.gray()};
            font-size: 1.2rem;
          }
        `}
        style={{
          paddingBottom:
            stars &&
            stars.length > 0 &&
            !replyInputShown &&
            !xpRewardInterfaceShown
              ? 0
              : '1rem'
        }}
      >

          {subject &&
            (subject.notFound ? (

                Subject removed / no longer available

            ) : (

                      <ContentLink
                        content={{ id: subject.id, title: 'Subject: ' }}
                        type="subject"
                        style={{ color: Color.green() }}
                      />

                      <UsernameText user={subject.uploader} />

                        ({timeSince(subject.timeStamp)})

                    {subject.title}

                  {subject.description && (
                    <LongText
                      className={css`
                        margin-top: 1rem;
                      `}
                    >
                      {subject.description}
                    </LongText>
                  )}

            ))}
          {comment &&
            (comment.notFound ? (

                Comment removed / no longer available

            ) : (

                        <UsernameText
                          user={comment.uploader}
                          color={Color.blue()}
                        />{' '}
                        <ContentLink
                          content={{
                            id: comment.id,
                            title: `${
                              type === 'reply'
                                ? 'replied'
                                : type === 'comment'
                                ? 'commented'
                                : 'responded'
                            }:`
                          }}
                          type="comment"
                          style={{ color: Color.green() }}
                        />

                          ({timeSince(comment.timeStamp)})

                    <LongText style={{ marginTop: '1rem' }}>
                      {comment.content}
                    </LongText>

                  <ErrorBoundary className="buttons">

 0 ? '0.5rem' : 0
                        }}
                      >
                        <LikeButton
                          contentType="comment"
                          contentId={comment.id}
                          onClick={this.onLikeClick}
                          liked={userLikedThis}
                          small
                        />
                        <Button
                          style={{ marginLeft: '1rem' }}
                          transparent
                          onClick={this.onReplyClick}
                        >
                          <Icon icon="comment-alt" />
                          Reply
                        </Button>

                      <Likers
                        className="content-panel__likes"
                        userId={myId}
                        likes={comment.likes}
                        onLinkClick={() =>
                          this.setState({ userListModalShown: true })
                        }
                      />

                      {canStar && userCanStarThis && (
                        <Button
                          love
                          disabled={this.determineXpButtonDisabled()}
                          onClick={() =>
                            this.setState({ xpRewardInterfaceShown: true })
                          }
                        >
                          <Icon icon="certificate" />

                            {this.determineXpButtonDisabled() || 'Reward'}

                        </Button>
                      )}

                  </ErrorBoundary>

                {xpRewardInterfaceShown && (
                  <XPRewardInterface
                    contentType={'comment'}
                    contentId={comment.id}
                    difficulty={this.determineDifficulty({
                      rootObj,
                      rootType,
                      subject
                    })}
                    uploaderId={comment.uploader.id}
                    stars={comment.stars}
                    onRewardSubmit={data => {
                      this.setState({ xpRewardInterfaceShown: false });
                      onAttachStar(data);
                    }}
                  />
                )}
                <RewardStatus
                  difficulty={this.determineDifficulty({
                    rootObj,
                    rootType,
                    subject
                  })}
                  onCommentEdit={onEditRewardComment}
                  style={{
                    marginTop:
                      comment.likes.length > 0 || xpRewardInterfaceShown
                        ? '0.5rem'
                        : '1rem'
                  }}
                  stars={comment.stars}
                  uploaderName={uploader.username}
                />
                {replyInputShown && (
                  <InputForm
                    innerRef={ref => (this.InputForm = ref)}
                    style={{
                      marginTop: comment.likes.length > 0 ? '0.5rem' : '1rem',
                      padding: '0 1rem'
                    }}
                    autoFocus
                    onSubmit={this.onSubmit}
                    rows={4}
                    placeholder={`Write a reply...`}
                  />
                )}
                {comments.length > 0 && (

                    {comments.map(comment => (
                      <Comment
                        key={comment.id}
                        comment={comment}
                        username={username}
                        userId={myId}
                        profilePicId={profilePicId}
                        onDelete={onDeleteComment}
                        onEditDone={onEditComment}
                      />
                    ))}

                )}
                {userListModalShown && (
                  <UserListModal
                    onHide={() => this.setState({ userListModalShown: false })}
                    title="People who liked this comment"
                    users={comment.likes}
                    description="(You)"
                  />
                )}

            ))}

      </ErrorBoundary>
    );
  }

  determineXpButtonDisabled = () => {
    const {
      targetObj: { type, comment, subject },
      myId,
      rootObj,
      rootType
    } = this.props;
    const { xpRewardInterfaceShown } = this.state;
    const stars =
      type === 'comment' || type === 'reply' ? comment.stars : subject.stars;
    return determineXpButtonDisabled({
      difficulty: this.determineDifficulty({ rootObj, rootType, subject }),
      stars,
      myId,
      xpRewardInterfaceShown
    });
  };

  determineDifficulty = ({ rootType, rootObj, subject }) => {
    const rootDifficulty =
      rootType !== 'video'
        ? rootObj.difficulty
        : rootObj.difficulty > 0
        ? 1
        : 0;
    return subject?.difficulty || rootDifficulty;
  };

  onLikeClick = likes => {
    const {
      targetObj: { comment },
      onLikeContent
    } = this.props;
    onLikeContent({ likes, type: 'comment', contentId: comment.id });
  };

  onReplyClick = () => {
    const { replyInputShown } = this.state;
    if (!replyInputShown) return this.setState({ replyInputShown: true });
    this.InputForm.focus();
  };

  onSubmit = async content => {
    const {
      dispatch,
      feedId,
      rootType,
      rootObj,
      targetObj: { comment = {} },
      onTargetCommentSubmit
    } = this.props;
    const data = await uploadComment({
      content,
      parent: {
        type: rootType,
        id: rootObj.id
      },
      rootCommentId: comment.commentId,
      targetCommentId: comment.id,
      dispatch
    });
    if (data) onTargetCommentSubmit(data, feedId);
  };
}

export default connect(
  state => ({
    authLevel: state.UserReducer.authLevel,
    canStar: state.UserReducer.canStar,
    username: state.UserReducer.username,
    profilePicId: state.UserReducer.profilePicId
  }),
  dispatch => ({ dispatch })
)(withContext({ Component: TargetContent, Context }));
<|endoftext|>


<commit_before>// NOTE: run this test independently as
// npm test test/lib/container.js

require('co-mocha');
var sinon = require('sinon');
var Promise = require('bluebird');

var child_process = require('child_process');

var Container = require('../../lib/Container');

//require('nock').restore()

describe('Container', function() {
  describe('events', function() {
    it('fires a generic stateChange event', function(done) {
      var container = new Container({});

      var event = sinon.spy();
      var stateChange = function() {
        event.called.should.be.ok;

        var args = Array.prototype.slice.call(arguments);
        args.should.eql(['stopping']);

        done();
      };

      container.on('stopping', event);
      container.on('stateChange', stateChange);

      // stub out stop method on internal container
      container.container = {stop: sinon.spy()};

      container.stop();
    });
  });

  describe.only('stats', function() {
    var container, containerInfo;

    before(function*() {
      container = new Container({
        docker: {
          socketPath: '/var/run/docker.sock'
        },
        image: 'proboci/ubuntu-14.04-lamp',
        imageConfig: {
          'proboci/ubuntu-14.04-lamp': {
            services: []
          }
        },
        build: {
          ref: null,
          id: null
        }
      });

      Promise.promisifyAll(container);

      // will start the container too
      containerInfo = yield container.create();
      container.containerId = containerInfo.Id;
    });

    after(function*() {
      yield container.remove({force: true});
    });

    it('image size', function* () {
      var size = yield container.imageSizeAsync(containerInfo.Image);
      size.should.be.a.Number;
    });

    it('container size', function* () {
      // test 1: make sure execing and parsing works
      var stubs = sinon.stub(child_process, 'exec').yields(null, '123 /var/lib/...', '');
      try {
        var size = yield container.containerSizeAsync();
        size.should.be.a.Number;
      }
      finally {
        stubs.restore();
      }

      // test 2: error handling
      try {
        yield container.containerSizeAsync();
        throw new Error('Should not get here');
      } catch (e) {
        e.message.should.eql(`Command failed: /bin/sh -c du -bs /var/lib/docker/aufs/diff/${container.containerId}\ndu: cannot access ‘/var/lib/docker/aufs/diff/${container.containerId}’: Permission denied\n`);
      }

    });
  });
});
<commit_msg>skip container tests because they need proper environment to run in and more refactoring to work with nock<commit_after>// NOTE: run this test independently as
// npm test test/lib/container.js

require('co-mocha');
var sinon = require('sinon');
var Promise = require('bluebird');

var child_process = require('child_process');

var Container = require('../../lib/Container');

//require('nock').restore()

describe.skip('Container', function() {
  describe('events', function() {
    it('fires a generic stateChange event', function(done) {
      var container = new Container({});

      var event = sinon.spy();
      var stateChange = function() {
        event.called.should.be.ok;

        var args = Array.prototype.slice.call(arguments);
        args.should.eql(['stopping']);

        done();
      };

      container.on('stopping', event);
      container.on('stateChange', stateChange);

      // stub out stop method on internal container
      container.container = {stop: sinon.spy()};

      container.stop();
    });
  });

  describe('stats', function() {
    var container, containerInfo;

    before(function*() {
      container = new Container({
        docker: {
          socketPath: '/var/run/docker.sock'
        },
        image: 'proboci/ubuntu-14.04-lamp',
        imageConfig: {
          'proboci/ubuntu-14.04-lamp': {
            services: []
          }
        },
        build: {
          ref: null,
          id: null
        }
      });

      Promise.promisifyAll(container);

      // will start the container too
      containerInfo = yield container.create();
      container.containerId = containerInfo.Id;
    });

    after(function*() {
      yield container.remove({force: true});
    });

    it('image size', function* () {
      var size = yield container.imageSizeAsync(containerInfo.Image);
      size.should.be.a.Number;
    });

    it('container size', function* () {
      // test 1: make sure execing and parsing works
      var stubs = sinon.stub(child_process, 'exec').yields(null, '123 /var/lib/...', '');
      try {
        var size = yield container.containerSizeAsync();
        size.should.be.a.Number;
      }
      finally {
        stubs.restore();
      }

      // test 2: error handling
      try {
        yield container.containerSizeAsync();
        throw new Error('Should not get here');
      } catch (e) {
        e.message.should.eql(`Command failed: /bin/sh -c du -bs /var/lib/docker/aufs/diff/${container.containerId}\ndu: cannot access ‘/var/lib/docker/aufs/diff/${container.containerId}’: Permission denied\n`);
      }

    });
  });
});
<|endoftext|>


<commit_before>var librato_init = require('../lib/librato.js').init,
    http = require('http'),
    events = require('events'),
    server_port = 36001;

module.exports = {
  setUp: function(callback) {
    this.server = http.createServer();
    this.server.listen(server_port, '127.0.0.1', function() {
      callback();
    });

    this.emitter = new events.EventEmitter();
    this.api_mock = function(validRequest, errorResponse, callback) {
      return function(req, res) {
        var data = '';
        req.on('data', function(chunk) {
          data += chunk;
        });
        req.on('end', function() {
          var body = JSON.parse(data);
          if (validRequest) {
            res.writeHead(200, {});
            res.end('');
            callback(req, res, body);
          } else {
            res.writeHead(400, {'content-type': 'application/json'});
            res.end(JSON.stringify(errorResponse));
            callback(req, res, body);
          }
        });

      };
    };

    // Librato Backend
    librato_init(null, {
      debug: false,
      librato: {
        email: '-@-',
        token: '-',
        api: 'http://127.0.0.1:' + server_port,
        writeToLegacy: false
      }
    }, this.emitter);
  },

  tearDown: function (callback) {
    this.server.close(function() {
      callback();
    });
  },

  testValidMeasurementNoTags: function(test) {
    test.expect(4);
    var metrics = {
      gauges: {
        my_gauge: 1
      }
    };

    this.server.once('request', this.api_mock(true, {}, function(req, res, body) {
      var measurement = body.measurements[0];
      test.ok(measurement);
      test.equal(measurement.name, "my_gauge");
      test.equal(measurement.value, 1);
      test.deepEqual(measurement.tags, {});
      test.done();

    }));

    this.emitter.emit('flush', 123, metrics);
  },

  testValidMeasurementSingleTag: function(test) {
    test.expect(4);
    var metrics = {
      gauges: {
        "my_gauge#foo=bar": 1
      }
    };

    this.server.once('request', this.api_mock(true, {}, function(req, res, body) {
      var measurement = body.measurements[0];
      test.ok(measurement);
      test.equal(measurement.name, "my_gauge");
      test.equal(measurement.value, 1);
      test.deepEqual(measurement.tags, {foo: "bar"});
      test.done();
    }));

    this.emitter.emit('flush', 123, metrics);
  },

  testValidMeasurementMultipleTags: function(test) {
    test.expect(4);
    var metrics = {
      gauges: {
        "my_gauge#foo=bar,biz=baz": 1
      }
    };

    this.server.once('request', this.api_mock(true, {}, function(req, res, body) {
      var measurement = body.measurements[0];
      test.ok(measurement);
      test.equal(measurement.name, "my_gauge");
      test.equal(measurement.value, 1);
      test.deepEqual(measurement.tags, {foo: "bar", biz: "baz"});
      test.done();
    }));

    this.emitter.emit('flush', 123, metrics);
  },

  testIgnoreBrokenMetrics: function(test) {
    test.expect(5);
    var metrics = {
      gauges: {
        cool_gauge: 123,
        bad_counter: 321
      }
    };

    var errors = {
      errors: {
        params: {
          type: [
            "'bad_counter'" +
              " is a counter, but was" +
              " submitted as different type"
          ]
        }
      }
    };

    // Simulate failure...
    this.server.once('request', this.api_mock(false, errors, function(req, res, body) {
      var gauges = {};
      for (var k in body.measurements) {
        gauges[body.measurements[k].name] = body.measurements[k].value;
      }

      test.ok(gauges.cool_gauge);
      test.ok(gauges.bad_counter);
      test.equal(res.statusCode, 400);

      setTimeout(function() {
        this.server.once('request', this.api_mock(true, {}, function(req, res, body) {
          var gauges = {};
          for (var k in body.measurements) {
            gauges[body.measurements[k].name] = body.measurements[k].value;
          }
          test.ok(gauges.cool_gauge);
          test.strictEqual(gauges.bad_counter, undefined);
          test.done();
        }));
        this.emitter.emit('flush', 123, metrics);
      }.bind(this));
    }.bind(this)));

    this.emitter.emit('flush', 123, metrics);

  },

  testTimers: function(test) {
    test.expect(7);
    var metrics = {
      timers: {
        "my_timer#tag=foo": [41, 73.5]
      },
      timer_data: {
        "my_timer#tag=foo": null
      }
    };

    this.server.once('request', this.api_mock(true, {}, function(req, res, body) {
      var measurement = body.measurements[0];
      test.ok(measurement);
      test.equal(measurement.name, "my_timer");
      test.equal(measurement.value, undefined);
      test.equal(measurement.min, 41);
      test.equal(measurement.max, 73.5);
      test.equal(measurement.sum, 114.5);
      test.deepEqual(measurement.tags, {tag: "foo"});
      test.done();
    }));

    this.emitter.emit('flush', 123, metrics);
  }
};
<commit_msg>Fix flapper<commit_after>var librato_init = require('../lib/librato.js').init,
    http = require('http'),
    events = require('events'),
    server_port = 36001;

module.exports = {
  setUp: function(callback) {
    this.server = http.createServer();
    this.server.listen(server_port, '127.0.0.1', function() {
      callback();
    });

    this.emitter = new events.EventEmitter();
    this.api_mock = function(validRequest, errorResponse, callback) {
      return function(req, res) {
        var data = '';
        req.on('data', function(chunk) {
          data += chunk;
        });
        req.on('end', function() {
          var body = JSON.parse(data);
          if (validRequest) {
            res.writeHead(200, {});
            res.end('');
            callback(req, res, body);
          } else {
            res.writeHead(400, {'content-type': 'application/json'});
            res.end(JSON.stringify(errorResponse));
            callback(req, res, body);
          }
        });

      };
    };

    // Librato Backend
    librato_init(null, {
      debug: false,
      librato: {
        email: '-@-',
        token: '-',
        api: 'http://127.0.0.1:' + server_port,
        writeToLegacy: false
      }
    }, this.emitter);
  },

  tearDown: function (callback) {
    this.server.close(function() {
      callback();
    });
  },

  testValidMeasurementNoTags: function(test) {
    test.expect(4);
    var metrics = {
      gauges: {
        my_gauge: 1
      }
    };

    this.server.once('request', this.api_mock(true, {}, function(req, res, body) {
      var measurement = body.measurements[0];
      test.ok(measurement);
      test.equal(measurement.name, "my_gauge");
      test.equal(measurement.value, 1);
      test.deepEqual(measurement.tags, {});
      test.done();

    }));

    this.emitter.emit('flush', 123, metrics);
  },

  testValidMeasurementSingleTag: function(test) {
    test.expect(4);
    var metrics = {
      gauges: {
        "my_gauge#foo=bar": 1
      }
    };

    this.server.once('request', this.api_mock(true, {}, function(req, res, body) {
      var measurement = body.measurements[0];
      test.ok(measurement);
      test.equal(measurement.name, "my_gauge");
      test.equal(measurement.value, 1);
      test.deepEqual(measurement.tags, {foo: "bar"});
      test.done();
    }));

    this.emitter.emit('flush', 123, metrics);
  },

  testValidMeasurementMultipleTags: function(test) {
    test.expect(4);
    var metrics = {
      gauges: {
        "my_gauge#foo=bar,biz=baz": 1
      }
    };

    this.server.once('request', this.api_mock(true, {}, function(req, res, body) {
      var measurement = body.measurements[0];
      test.ok(measurement);
      test.equal(measurement.name, "my_gauge");
      test.equal(measurement.value, 1);
      test.deepEqual(measurement.tags, {foo: "bar", biz: "baz"});
      test.done();
    }));

    this.emitter.emit('flush', 123, metrics);
  },

  testIgnoreBrokenMetrics: function(test) {
    test.expect(5);
    var metrics = {
      gauges: {
        cool_gauge: 123,
        bad_counter: 321
      }
    };

    var errors = {
      errors: {
        params: {
          type: [
            "'bad_counter'" +
              " is a counter, but was" +
              " submitted as different type"
          ]
        }
      }
    };

    // Simulate failure...
    this.server.once('request', this.api_mock(false, errors, function(req, res, body) {
      var gauges = {};
      for (var k in body.measurements) {
        gauges[body.measurements[k].name] = body.measurements[k].value;
      }

      test.ok(gauges.cool_gauge);
      test.ok(gauges.bad_counter);
      test.equal(res.statusCode, 400);

      setTimeout(function() {
        this.server.once('request', this.api_mock(true, {}, function(req, res, body) {
          var gauges = {};
          for (var k in body.measurements) {
            gauges[body.measurements[k].name] = body.measurements[k].value;
          }
          test.ok(gauges.cool_gauge);
          test.strictEqual(gauges.bad_counter, undefined);
          test.done();
        }));
        this.emitter.emit('flush', 123, metrics);
      }.bind(this), 500);
    }.bind(this)));

    this.emitter.emit('flush', 123, metrics);

  },

  testTimers: function(test) {
    test.expect(7);
    var metrics = {
      timers: {
        "my_timer#tag=foo": [41, 73.5]
      },
      timer_data: {
        "my_timer#tag=foo": null
      }
    };

    this.server.once('request', this.api_mock(true, {}, function(req, res, body) {
      var measurement = body.measurements[0];
      test.ok(measurement);
      test.equal(measurement.name, "my_timer");
      test.equal(measurement.value, undefined);
      test.equal(measurement.min, 41);
      test.equal(measurement.max, 73.5);
      test.equal(measurement.sum, 114.5);
      test.deepEqual(measurement.tags, {tag: "foo"});
      test.done();
    }));

    this.emitter.emit('flush', 123, metrics);
  }
};
<|endoftext|>


<commit_before>import { parseNeed } from "./parse-need.js";
import Immutable from "immutable";
import won from "../../won-es6.js";

export function addNeed(needs, jsonldNeed, isOwned) {
  let newState;
  let parsedNeed = parseNeed(jsonldNeed, isOwned);

  if (parsedNeed && parsedNeed.get("uri")) {
    let existingNeed = needs.get(parsedNeed.get("uri"));
    const isExistingOwnedNeed = existingNeed && existingNeed.get("isOwned");

    if (existingNeed) {
      if (isOwned || isExistingOwnedNeed) {
        parsedNeed = parsedNeed
          .set("connections", existingNeed.get("connections"))
          .set("isOwned", true);
      } else if (!isOwned) {
        parsedNeed = parsedNeed
          .set("connections", existingNeed.get("connections"))
          .set("isOwned", false);
      }

      const heldNeedUris = parsedNeed.get("holds");
      if (heldNeedUris.size > 0) {
        heldNeedUris.map(needUri => {
          if (!needs.get(needUri) || !needs.getIn([needUri, "isOwned"])) {
            needs = addTheirNeedToLoad(needs, needUri);
          }
        });
      }

      const groupMemberUris = parsedNeed.get("groupMembers");
      if (groupMemberUris.size > 0) {
        groupMemberUris.map(needUri => {
          if (!needs.get(needUri) || !needs.getIn([needUri, "isOwned"])) {
            needs = addTheirNeedToLoad(needs, needUri);
          }
        });
      }
    }

    return needs.set(parsedNeed.get("uri"), parsedNeed);
  } else {
    console.error("Tried to add invalid need-object: ", jsonldNeed);
    newState = needs;
  }

  return newState;
}

function addNeedInLoading(needs, needUri, state, isOwned) {
  const oldNeed = needs.get(needUri);
  if (oldNeed) {
    return needs;
  } else {
    let need = Immutable.fromJS({
      uri: needUri,
      isOwned: isOwned,
      state: state,
      connections: Immutable.Map(),
    });
    return needs.setIn([needUri], need);
  }
}

function addTheirNeedInLoading(needs, needUri) {
  const oldNeed = needs.get(needUri);
  if (oldNeed && oldNeed.get("isOwned")) {
    return needs;
  } else {
    let need = Immutable.fromJS({
      uri: needUri,
      isOwned: false,
      connections: Immutable.Map(),
    });
    return needs.setIn([needUri], need);
  }
}

export function addTheirNeedToLoad(needs, needUri) {
  const oldNeed = needs.get(needUri);
  if (oldNeed && oldNeed.get("isOwned")) {
    return needs;
  } else {
    let need = Immutable.fromJS({
      uri: needUri,
      isOwned: false,
      connections: Immutable.Map(),
    });
    return needs.setIn([needUri], need);
  }
}

export function addOwnActiveNeedsInLoading(needs, needUris) {
  let newState = needs;
  needUris &&
    needUris.forEach(needUri => {
      newState = addNeedInLoading(
        newState,
        needUri,
        won.WON.ActiveCompacted,
        true
      );
    });
  return newState;
}

export function addOwnInactiveNeedsInLoading(needs, needUris) {
  let newState = needs;
  needUris &&
    needUris.forEach(needUri => {
      newState = addNeedInLoading(
        newState,
        needUri,
        won.WON.InactiveCompacted,
        true
      );
    });
  return newState;
}

export function addTheirNeedsInLoading(needs, needUris) {
  let newState = needs;
  needUris &&
    needUris.forEach(needUri => {
      newState = addTheirNeedInLoading(newState, needUri);
    });
  return newState;
}

export function addOwnInactiveNeedsToLoad(needs, needUris) {
  let newState = needs;
  needUris &&
    needUris.forEach(needUri => {
      newState = addNeedToLoad(
        newState,
        needUri,
        won.WON.InactiveCompacted,
        true
      );
    });
  return newState;
}

function addNeedToLoad(needs, needUri, state, isOwned) {
  if (needs.get(needUri)) {
    return needs;
  } else {
    let need = Immutable.fromJS({
      uri: needUri,
      isOwned: isOwned,
      state: state,
      connections: Immutable.Map(),
    });
    return needs.setIn([needUri], need);
  }
}

export function addNeedInCreation(needs, needInCreation, needUri) {
  let newState;
  let need = Immutable.fromJS(needInCreation);

  if (need) {
    need = need.set("uri", needUri);
    need = need.set("isOwned", true);
    need = need.set("isBeingCreated", true);
    need = need.set("connections", Immutable.Map());

    let title = undefined;

    if (need.get("content")) {
      title = need.getIn(["content", "title"]);
    }

    if (need.get("seeks")) {
      title = need.getIn(["seeks", "title"]);
    }

    need = need.set("humanReadable", title);

    newState = needs.setIn([needUri], need);
  } else {
    console.error("Tried to add invalid need-object: ", needInCreation);
    newState = needs;
  }
  return newState;
}

export function markNeedAsRead(state, needUri) {
  const need = state.get(needUri);

  if (!need) {
    console.error("No need with needUri: <", needUri, ">");
    return state;
  }
  return state.setIn([needUri, "unread"], false);
}
<commit_msg>This should fix #2645<commit_after>import { parseNeed } from "./parse-need.js";
import Immutable from "immutable";
import won from "../../won-es6.js";

export function addNeed(needs, jsonldNeed, isOwned) {
  let newState;
  let parsedNeed = parseNeed(jsonldNeed, isOwned);

  if (parsedNeed && parsedNeed.get("uri")) {
    let existingNeed = needs.get(parsedNeed.get("uri"));
    const isExistingOwnedNeed = existingNeed && existingNeed.get("isOwned");

    if (existingNeed) {
      if (isOwned || isExistingOwnedNeed) {
        parsedNeed = parsedNeed
          .set("connections", existingNeed.get("connections"))
          .set("isOwned", true);
      } else if (!isOwned) {
        parsedNeed = parsedNeed
          .set("connections", existingNeed.get("connections"))
          .set("isOwned", false);
      }

      const heldNeedUris = parsedNeed.get("holds");
      if (heldNeedUris.size > 0) {
        heldNeedUris.map(needUri => {
          if (!needs.get(needUri) || !needs.getIn([needUri, "isOwned"])) {
            needs = addTheirNeedToLoad(needs, needUri);
          }
        });
      }

      const groupMemberUris = parsedNeed.get("groupMembers");
      if (groupMemberUris.size > 0) {
        groupMemberUris.map(needUri => {
          if (!needs.get(needUri) || !needs.getIn([needUri, "isOwned"])) {
            needs = addTheirNeedToLoad(needs, needUri);
          }
        });
      }
    }

    return needs.set(parsedNeed.get("uri"), parsedNeed);
  } else {
    console.error("Tried to add invalid need-object: ", jsonldNeed);
    newState = needs;
  }

  return newState;
}

function addNeedInLoading(needs, needUri, state, isOwned) {
  const oldNeed = needs.get(needUri);
  if (oldNeed) {
    return needs;
  } else {
    let need = Immutable.fromJS({
      uri: needUri,
      isOwned: isOwned,
      state: state,
      connections: Immutable.Map(),
    });
    return needs.setIn([needUri], need);
  }
}

function addTheirNeedInLoading(needs, needUri) {
  const oldNeed = needs.get(needUri);
  if (oldNeed) {
    return needs;
  } else {
    let need = Immutable.fromJS({
      uri: needUri,
      isOwned: false,
      connections: Immutable.Map(),
    });
    return needs.setIn([needUri], need);
  }
}

export function addTheirNeedToLoad(needs, needUri) {
  const oldNeed = needs.get(needUri);
  if (oldNeed) {
    return needs;
  } else {
    let need = Immutable.fromJS({
      uri: needUri,
      isOwned: false,
      connections: Immutable.Map(),
    });
    return needs.setIn([needUri], need);
  }
}

export function addOwnActiveNeedsInLoading(needs, needUris) {
  let newState = needs;
  needUris &&
    needUris.forEach(needUri => {
      newState = addNeedInLoading(
        newState,
        needUri,
        won.WON.ActiveCompacted,
        true
      );
    });
  return newState;
}

export function addOwnInactiveNeedsInLoading(needs, needUris) {
  let newState = needs;
  needUris &&
    needUris.forEach(needUri => {
      newState = addNeedInLoading(
        newState,
        needUri,
        won.WON.InactiveCompacted,
        true
      );
    });
  return newState;
}

export function addTheirNeedsInLoading(needs, needUris) {
  let newState = needs;
  needUris &&
    needUris.forEach(needUri => {
      newState = addTheirNeedInLoading(newState, needUri);
    });
  return newState;
}

export function addOwnInactiveNeedsToLoad(needs, needUris) {
  let newState = needs;
  needUris &&
    needUris.forEach(needUri => {
      newState = addNeedToLoad(
        newState,
        needUri,
        won.WON.InactiveCompacted,
        true
      );
    });
  return newState;
}

function addNeedToLoad(needs, needUri, state, isOwned) {
  if (needs.get(needUri)) {
    return needs;
  } else {
    let need = Immutable.fromJS({
      uri: needUri,
      isOwned: isOwned,
      state: state,
      connections: Immutable.Map(),
    });
    return needs.setIn([needUri], need);
  }
}

export function addNeedInCreation(needs, needInCreation, needUri) {
  let newState;
  let need = Immutable.fromJS(needInCreation);

  if (need) {
    need = need.set("uri", needUri);
    need = need.set("isOwned", true);
    need = need.set("isBeingCreated", true);
    need = need.set("connections", Immutable.Map());

    let title = undefined;

    if (need.get("content")) {
      title = need.getIn(["content", "title"]);
    }

    if (need.get("seeks")) {
      title = need.getIn(["seeks", "title"]);
    }

    need = need.set("humanReadable", title);

    newState = needs.setIn([needUri], need);
  } else {
    console.error("Tried to add invalid need-object: ", needInCreation);
    newState = needs;
  }
  return newState;
}

export function markNeedAsRead(state, needUri) {
  const need = state.get(needUri);

  if (!need) {
    console.error("No need with needUri: <", needUri, ">");
    return state;
  }
  return state.setIn([needUri, "unread"], false);
}
<|endoftext|>


<commit_before>/*!
 * ${copyright}
 */

sap.ui.define([
	"sap/ui/thirdparty/jquery",
	"sap/m/Input",
	"sap/m/library",
	"../config/datatable",
	"./datatable/filters/DataTableFilterDropDown",
	"./datatable/filters/DataTableFilterRange",
	"sap/ui/documentation/sdk/controller/util/Highlighter",
	"./DataTableUtil"
], function (
	$,
	Input,
	mobileLibrary,
	datatableConfig,
	DataTableFilterDropDown,
	DataTableFilterRange,
	Highlighter,
	DataTableUtil
) {
	"use strict";

	// shortcut for sap.m.InputType
	var InputType = mobileLibrary.InputType;

	/**
	 *
	 * @constructor
	 */
	function DataTable() {
		// reference to column object
		this.oColumns = [];

		// those are set before a column.draw method is called and
		// are used in the datatable search function to determinate
		// what filter should be applied
		this.oChangedFilters = [];
		this.aShownRows = [];

		// jQeury DataTable API
		this.API = null;
	}

	DataTable.DEFAULT_SORTING = "0,asc";
	DataTable.FILTER_CLASS_WRAPPER = "sapUiDocumentationDatatableFilterWrapper";

	DataTable.FILTER_TYPES = {
		REGEX: "REGEX",
		NORMAL: "NORMAL",
		NUMBER: "NUMBER",
		SELECT: "SELECT",
		CELL_RANGE: "CELL_RANGE",
		NUMBER_RANGE: "NUMBER_RANGE"
	};

	DataTable.prototype.destroy = function () {
		this.oColumns.forEach(function (oColumn) {
			if (oColumn.highlighter) {
				oColumn.highlighter.destroy();
                oColumn.highlighter = null;
			}

			oColumn.aControls.forEach(function (oControl) {
				oControl.destroy();
            });

            oColumn.aControls = [];
		});

		this.oColumns = [];
		this.API.destroy();
	};

	DataTable.prototype.get = function (sProp) {
		return this.oConfig[sProp];
	};

	DataTable.prototype.init = function (sId, oTable, oConfig) {
		this.sId = sId;

		this.oDomTable = oTable;
		this.oConfig = this.getConfig(sId, oConfig);
		// create datatable
		var API = $(oTable)
			.DataTable(
				Object.assign(
					this.oConfig,
					this.getLifeCycleMethods(sId, oConfig)
				)
			);

		API.on('draw', function () {

			if (this.get("highlight")) {
                var sTerms = API.search();

				if (sTerms || this.oChangedFilters.length) {
                    // global search or column filter has a value,
                    // loop through columns and apply global search value,
                    // filter value or both
                    this.oColumns.forEach(function (oColumn, iIndex) {
                        var sFilterValue = this.oChangedFilters[iIndex] && this.oChangedFilters[iIndex].value,
                            bIsArray = Array.isArray(sFilterValue); // filter type select

                        if (bIsArray) {
                            sFilterValue = sFilterValue.reduce(function (sResult, oCheckbox, iIndex) {
                                if (oCheckbox.value) {
                                    sResult += " " + oCheckbox.text;
                                }
                                return sResult;
                            }, "");
                        }

                        if (sFilterValue && !(typeof sFilterValue === "object" /* filter type range */ )) {
                            if (sTerms) {
					            sTerms += " " + sFilterValue;
                            } else {
                                sTerms = sFilterValue;
                            }
                        }

                        this.highlight(iIndex, sTerms);
                    }, this);

				} else {
                    // no filter has value, so we remove highlight
					this.highlight(null, "");
				}

			}

		}.bind(this));

		API.buttons().container()
			.insertBefore('#' + sId + '_length');

		API.on('column-visibility.dt', function (e, settings, iColumnIndex, bVisibleState) {
			this.onColumnVisibilityChange(iColumnIndex, bVisibleState);
		}.bind(this));

		this.oConfig.columns.forEach(function (oParams, iIndex) {
			this.onColumnVisibilityChange(iIndex, oParams.visible);
		}, this);

		return this;
	};

	DataTable.prototype.highlight = function (aColumnIndex, sTerms) {
		if (aColumnIndex === null) {
			// highlight all columns
			this.oColumns.forEach(function (oColumn) {
				oColumn.highlighter.highlight(sTerms);
			});

			return;
		}

		this.oColumns[aColumnIndex].highlighter.highlight(sTerms);
	};

	DataTable.prototype.onColumnVisibilityChange = function (iIndex, bVisible) {
		var oFilterHeader = this.oColumns[iIndex] && this.oColumns[iIndex].filterHeader,
			oColGroup = this.oDomTable.querySelector("colgroup"), // colgroup contains cols which can configure the whole column (ex. width, color, etc.)
			oColGroupChild;

		if (oColGroup) {
			oColGroupChild = oColGroup.children[iIndex];

			if (oColGroupChild) {
				oColGroupChild.classList.toggle("hidden", !bVisible);
			}
		}

		if (oFilterHeader) {
			oFilterHeader.toggle(bVisible);
		}
	};

	DataTable.prototype.handleSearch = function (settings, oData, index, rowData, counter) {
		var sEntryValue,
			aEntryValue,
			oChangedFilterValue,
			oChangedFilterControl,
			aShow = [],
			bShow;

		this.oChangedFilters.forEach(function (oChangedFilter, iIndex) {
			sEntryValue = oData[iIndex];
			oChangedFilterValue = oChangedFilter.value;
			oChangedFilterControl = oChangedFilter.control;

			if (oChangedFilterValue === "") {
				// filter value is probably deleted
				// show all entries
				return;
			}

			switch (true) {
				case oChangedFilterControl.hasStyleClass(DataTable.FILTER_TYPES.REGEX):
				case oChangedFilterControl.hasStyleClass(DataTable.FILTER_TYPES.NORMAL):
				case oChangedFilterControl.hasStyleClass(DataTable.FILTER_TYPES.ALPHA_NUMERIC):
				case oChangedFilterControl.hasStyleClass(DataTable.FILTER_TYPES.NUMBER):
					// filter if string is contained
					bShow = sEntryValue.toLowerCase().indexOf(oChangedFilterValue.toLowerCase()) > -1;
					break;

				case oChangedFilterControl.hasStyleClass(DataTable.FILTER_TYPES.NUMBER_RANGE):
					// filter by given range
					var min = oChangedFilterValue.from !== "" ? oChangedFilterValue.from : Number.MIN_SAFE_INTEGER,
						max = oChangedFilterValue.to !== "" ? oChangedFilterValue.to : Number.MAX_SAFE_INTEGER,
						current = parseFloat(sEntryValue) || 0;

					bShow = (isNaN(min) && isNaN(max)) ||
						(isNaN(min) && current <= max) ||
						(min <= current && isNaN(max)) ||
						(min <= current && current <= max);
					break;

				case oChangedFilterControl.hasStyleClass(DataTable.FILTER_TYPES.CELL_RANGE):
					// filter by given cell range
					var arr = sEntryValue.split("-"),
						fInputValue = parseFloat(oChangedFilterValue);

					bShow = arr[0] <= fInputValue && arr[1] >= fInputValue;
					break;

				case oChangedFilterControl.hasStyleClass(DataTable.FILTER_TYPES.SELECT):
					// select with multiple selectable options
					var hasChecked = oChangedFilterValue.some(function (checkBox) {
						return checkBox.value;
					});

					bShow = !hasChecked || (oChangedFilterValue.findIndex(function (checkBox) {
						aEntryValue = settings.aoData[index].anCells[iIndex].querySelectorAll("li");
						var aEntryValuesAsStrings = [];

						if (aEntryValue.length) {
							for (var i = 0; i < aEntryValue.length; i++) {
								aEntryValuesAsStrings[i] = aEntryValue[i].textContent;
							}
						} else {
							aEntryValuesAsStrings.push(sEntryValue);
						}

						return checkBox.value && (aEntryValuesAsStrings.indexOf(checkBox.text) > -1);
					}, this) > -1);
					break;

				default:
					bShow = true;
			}

			aShow.push(bShow);

		}, this);

		return aShow.indexOf(false) < 0;
	};

	DataTable.prototype.getConfig = function (sId, oConfig) {
		var aOrders = [],
			oNewConfig = JSON.parse(JSON.stringify(datatableConfig.getPreset()));

		oNewConfig.sapTableId = sId;

        // columnDefs is a plugin configuration which cares for sorting
		oNewConfig.columnDefs = [];

		if (oConfig) {

			oNewConfig.save = oConfig['save'] !== false;
			oNewConfig.searching = oConfig['search'] !== false;
			oNewConfig.highlight = oConfig['highlight'] !== false;

			if (oConfig['excel_export']) {
				oNewConfig.buttons.push('csv');
			}

			if (oConfig['paginate']) {
				var iPaginate = parseInt(oConfig['paginate']);
				oNewConfig.pageLength = iPaginate > 0 ? iPaginate : -1;
			}

			oNewConfig.columns = oConfig.columns.map(function (aColumnParams, iColIndex) {
				var result = {
					visible: true
				};

                result.visible = aColumnParams.visible !== false;

                if (aColumnParams.sort) {
                    // find if we already have configured a type of sorting create new config
                    // and push targets (columns)

                    var oSort = oNewConfig.columnDefs.find(function (oSort) {
                        return oSort.type === aColumnParams.sort;
                    });

                    if (oSort) {
                        oSort.targets.push(iColIndex);
                    } else {
                        oNewConfig.columnDefs.push({
                            type: aColumnParams.sort,
                            targets: [iColIndex]
                        });
                    }
                }

				return result;
			});

			oConfig['initial_sort'] = oConfig['initial_sort'] || DataTable.DEFAULT_SORTING;

			if (oConfig['initial_sort'] !== 'none') {
				aOrders = oConfig['initial_sort'].split(';');
				aOrders = aOrders.map(function (aItems) {
					return aItems.split(',');
				});
			}

			oNewConfig.order = aOrders;

		}

		return oNewConfig;
	};

	DataTable.prototype.onFilterChange = function (iColumnIndex, oOptions) {
		// modify global state
		// setting parameters before drawing of column
		this.oChangedFilters[iColumnIndex] = {
			control: oOptions.control,
			value: oOptions.value
		};

		this.API.columns(iColumnIndex).draw();
	};

	DataTable.prototype.getSelectOptions = function (iColumnIndex) {
		// loop through select options and map them to array
		var aOptions = [];

		this.API
			.columns(iColumnIndex)
			.data()
			.unique()
			.sort()[0]
			.forEach(function (sOption) {
				var oOption;

				if (aOptions.indexOf(sOption) > -1) {
					// if options is already in array return as we don't want duplicates
					return;
				}

				try {
					// some options are lists with list items (ul > li),
					// so we wrap them to jQuery objects and push their
					// values to the array of options if they are not already pushed

					// some options may contain special characters ( "(", ")", ";" ...)
					// this throws exception when we wrap them with jQuery and stops
					// javascript execution
					oOption = $(sOption);
				} catch (error) {
					oOption = null;
				}

				if (oOption && oOption.length > 0) {
					oOption.find('li').each(function (i, sOption) {
						if (aOptions.indexOf(sOption.textContent) < 0) {
							aOptions.push(sOption.textContent);
						}
					});
				} else {
					aOptions.push(sOption);
				}

			});

		aOptions.sort(DataTableUtil.sortAlphaNumeric);

		return aOptions;
	};

	DataTable.prototype.getLifeCycleMethods = function (sId, oConfig) {
		var that = this;

		return {
			initComplete: function () {
				that.API = this.api();

				// Create new table row to append filters
				var oTableHeader = $('#' + sId + ' thead'),
					oNewTableRow = $('<tr/>'),
					oFilterHeader,
					oHighlighter,
					iIndex = 0;

				this.api().columns().every(function () {
					// loop each column and create filter (table header(th)/filterHeader) from column filter params
					// append to the newly created table row
					// attach change events and modify state to use later when
					// table is about to redraw itself
					var iLocalIndex = iIndex,
						aColumnParams = oConfig.columns[iIndex],
						aOptions = [],
						oFilter,
						bIsTypeSelect = aColumnParams.filter === "select";

					oFilterHeader = $('<th/>');
					oFilterHeader.addClass(DataTable.FILTER_CLASS_WRAPPER);

					that.oColumns[iIndex] = {};
					that.oColumns[iIndex].aControls = [];
					that.oColumns[iIndex].filterHeader = oFilterHeader;

					if (that.get("highlight")) {
						oHighlighter = new Highlighter([].slice.call(this.nodes()), {
							useExternalStyles: false,
							shouldBeObserved: true,
							isCaseSensitive: false
						});

						that.oColumns[iIndex].highlighter = oHighlighter;
					}

					if (bIsTypeSelect) {
						aOptions = that.getSelectOptions(iIndex);
					}

					// prepare filter
					oFilter = DataTable.getFilterByType(aColumnParams.filter, aOptions);

					// append filter
					if (oFilter.control) {
						that.oColumns[iIndex].aControls.push(oFilter.control);

						oFilter.control.attachEvent(oFilter.event, function (oEvent) {
							that.onFilterChange(iLocalIndex, {
								value: oEvent.getParameter("value"),
								control: oFilter.control
							});
						});
						oFilter.control.placeAt(oFilterHeader);
					}

					oNewTableRow.append(oFilterHeader);

					iIndex++;
				});

				oTableHeader.append(oNewTableRow);
			}
		};
	};

	DataTable.getFilterByType = function (sTypeValue, aOptions) {
		var oControl, sEvent = "liveChange";

		switch (sTypeValue) {
			case 'number-range':
				oControl = new DataTableFilterRange({
					from: new Input({ type: InputType.Number, placeholder: "From" }),
					to: new Input({ type: InputType.Number, placeholder: "To" })
				}).addStyleClass(DataTable.FILTER_TYPES.NUMBER_RANGE);
				break;

			case 'select':
				sEvent = "change";
				oControl = new DataTableFilterDropDown({
					options: aOptions
				}).addStyleClass(DataTable.FILTER_TYPES.SELECT);
				break;

			case 'none':
				oControl = '';
				break;

			default:
				// inputs
				var sFilterType = DataTable.FILTER_TYPES.NORMAL,
					sInputType = InputType.Text;

				if (sTypeValue === 'regex') {
					sFilterType = DataTable.FILTER_TYPES.REGEX;
				} else if (sTypeValue === 'cell-range') {
					sFilterType = DataTable.FILTER_TYPES.CELL_RANGE;
					sInputType = InputType.Number;
				} else if (sTypeValue === 'number') {
					sFilterType = DataTable.FILTER_TYPES.NUMBER;
					sInputType = InputType.Number;
				}

				oControl = new Input({
					type: sInputType,
					placeholder: "Filter"
				}).addStyleClass(sFilterType);
		}

		return { control: oControl, event: sEvent };
	};

	return DataTable;
});<commit_msg>[FIX] Demo Kit: DataTable filter row formatting fixed<commit_after>/*!
 * ${copyright}
 */

sap.ui.define([
	"sap/ui/thirdparty/jquery",
	"sap/m/Input",
	"sap/m/library",
	"../config/datatable",
	"./datatable/filters/DataTableFilterDropDown",
	"./datatable/filters/DataTableFilterRange",
	"sap/ui/documentation/sdk/controller/util/Highlighter",
	"./DataTableUtil"
], function (
	$,
	Input,
	mobileLibrary,
	datatableConfig,
	DataTableFilterDropDown,
	DataTableFilterRange,
	Highlighter,
	DataTableUtil
) {
	"use strict";

	// shortcut for sap.m.InputType
	var InputType = mobileLibrary.InputType;

	/**
	 *
	 * @constructor
	 */
	function DataTable() {
		// reference to column object
		this.oColumns = [];

		// those are set before a column.draw method is called and
		// are used in the datatable search function to determinate
		// what filter should be applied
		this.oChangedFilters = [];
		this.aShownRows = [];

		// jQeury DataTable API
		this.API = null;
	}

	DataTable.DEFAULT_SORTING = "0,asc";
	DataTable.FILTER_CLASS_WRAPPER = "sapUiDocumentationDatatableFilterWrapper";

	DataTable.FILTER_TYPES = {
		REGEX: "REGEX",
		NORMAL: "NORMAL",
		NUMBER: "NUMBER",
		SELECT: "SELECT",
		CELL_RANGE: "CELL_RANGE",
		NUMBER_RANGE: "NUMBER_RANGE"
	};

	DataTable.prototype.destroy = function () {
		this.oColumns.forEach(function (oColumn) {
			if (oColumn.highlighter) {
				oColumn.highlighter.destroy();
                oColumn.highlighter = null;
			}

			oColumn.aControls.forEach(function (oControl) {
				oControl.destroy();
            });

            oColumn.aControls = [];
		});

		this.oColumns = [];
		this.API.destroy();
	};

	DataTable.prototype.get = function (sProp) {
		return this.oConfig[sProp];
	};

	DataTable.prototype.init = function (sId, oTable, oConfig) {
		this.sId = sId;

		this.oDomTable = oTable;
		this.oConfig = this.getConfig(sId, oConfig);
		// create datatable
		var API = $(oTable)
			.DataTable(
				Object.assign(
					this.oConfig,
					this.getLifeCycleMethods(sId, oConfig)
				)
			);

		API.on('draw', function () {

			if (this.get("highlight")) {
                var sTerms = API.search();

				if (sTerms || this.oChangedFilters.length) {
                    // global search or column filter has a value,
                    // loop through columns and apply global search value,
                    // filter value or both
                    this.oColumns.forEach(function (oColumn, iIndex) {
                        var sFilterValue = this.oChangedFilters[iIndex] && this.oChangedFilters[iIndex].value,
                            bIsArray = Array.isArray(sFilterValue); // filter type select

                        if (bIsArray) {
                            sFilterValue = sFilterValue.reduce(function (sResult, oCheckbox, iIndex) {
                                if (oCheckbox.value) {
                                    sResult += " " + oCheckbox.text;
                                }
                                return sResult;
                            }, "");
                        }

                        if (sFilterValue && !(typeof sFilterValue === "object" /* filter type range */ )) {
                            if (sTerms) {
					            sTerms += " " + sFilterValue;
                            } else {
                                sTerms = sFilterValue;
                            }
                        }

                        this.highlight(iIndex, sTerms);
                    }, this);

				} else {
                    // no filter has value, so we remove highlight
					this.highlight(null, "");
				}

			}

		}.bind(this));

		API.buttons().container()
			.insertBefore('#' + sId + '_length');

		API.on('column-visibility.dt', function (e, settings, iColumnIndex, bVisibleState) {
			this.onColumnVisibilityChange(iColumnIndex, bVisibleState);
		}.bind(this));

		this.oConfig.columns.forEach(function (oParams, iIndex) {
			this.onColumnVisibilityChange(iIndex, oParams.visible);
		}, this);

		return this;
	};

	DataTable.prototype.highlight = function (aColumnIndex, sTerms) {
		if (aColumnIndex === null) {
			// highlight all columns
			this.oColumns.forEach(function (oColumn) {
				oColumn.highlighter.highlight(sTerms);
			});

			return;
		}

		this.oColumns[aColumnIndex].highlighter.highlight(sTerms);
	};

	DataTable.prototype.onColumnVisibilityChange = function (iIndex, bVisible) {
		var oFilterHeader = this.oColumns[iIndex] && this.oColumns[iIndex].filterHeader,
			oColGroup = this.oDomTable.querySelector("colgroup"), // colgroup contains cols which can configure the whole column (ex. width, color, etc.)
			oColGroupChild;

		if (oColGroup) {
			oColGroupChild = oColGroup.children[iIndex];

			if (oColGroupChild) {
				oColGroupChild.classList.toggle("hidden", !bVisible);
			}
		}

		if (oFilterHeader) {
			oFilterHeader.toggle(bVisible);
		}
	};

	DataTable.prototype.handleSearch = function (settings, oData, index, rowData, counter) {
		var sEntryValue,
			aEntryValue,
			oChangedFilterValue,
			oChangedFilterControl,
			aShow = [],
			bShow;

		this.oChangedFilters.forEach(function (oChangedFilter, iIndex) {
			sEntryValue = oData[iIndex];
			oChangedFilterValue = oChangedFilter.value;
			oChangedFilterControl = oChangedFilter.control;

			if (oChangedFilterValue === "") {
				// filter value is probably deleted
				// show all entries
				return;
			}

			switch (true) {
				case oChangedFilterControl.hasStyleClass(DataTable.FILTER_TYPES.REGEX):
				case oChangedFilterControl.hasStyleClass(DataTable.FILTER_TYPES.NORMAL):
				case oChangedFilterControl.hasStyleClass(DataTable.FILTER_TYPES.ALPHA_NUMERIC):
				case oChangedFilterControl.hasStyleClass(DataTable.FILTER_TYPES.NUMBER):
					// filter if string is contained
					bShow = sEntryValue.toLowerCase().indexOf(oChangedFilterValue.toLowerCase()) > -1;
					break;

				case oChangedFilterControl.hasStyleClass(DataTable.FILTER_TYPES.NUMBER_RANGE):
					// filter by given range
					var min = oChangedFilterValue.from !== "" ? oChangedFilterValue.from : Number.MIN_SAFE_INTEGER,
						max = oChangedFilterValue.to !== "" ? oChangedFilterValue.to : Number.MAX_SAFE_INTEGER,
						current = parseFloat(sEntryValue) || 0;

					bShow = (isNaN(min) && isNaN(max)) ||
						(isNaN(min) && current <= max) ||
						(min <= current && isNaN(max)) ||
						(min <= current && current <= max);
					break;

				case oChangedFilterControl.hasStyleClass(DataTable.FILTER_TYPES.CELL_RANGE):
					// filter by given cell range
					var arr = sEntryValue.split("-"),
						fInputValue = parseFloat(oChangedFilterValue);

					bShow = arr[0] <= fInputValue && arr[1] >= fInputValue;
					break;

				case oChangedFilterControl.hasStyleClass(DataTable.FILTER_TYPES.SELECT):
					// select with multiple selectable options
					var hasChecked = oChangedFilterValue.some(function (checkBox) {
						return checkBox.value;
					});

					bShow = !hasChecked || (oChangedFilterValue.findIndex(function (checkBox) {
						aEntryValue = settings.aoData[index].anCells[iIndex].querySelectorAll("li");
						var aEntryValuesAsStrings = [];

						if (aEntryValue.length) {
							for (var i = 0; i < aEntryValue.length; i++) {
								aEntryValuesAsStrings[i] = aEntryValue[i].textContent;
							}
						} else {
							aEntryValuesAsStrings.push(sEntryValue);
						}

						return checkBox.value && (aEntryValuesAsStrings.indexOf(checkBox.text) > -1);
					}, this) > -1);
					break;

				default:
					bShow = true;
			}

			aShow.push(bShow);

		}, this);

		return aShow.indexOf(false) < 0;
	};

	DataTable.prototype.getConfig = function (sId, oConfig) {
		var aOrders = [],
			oNewConfig = JSON.parse(JSON.stringify(datatableConfig.getPreset()));

		oNewConfig.sapTableId = sId;

        // columnDefs is a plugin configuration which cares for sorting
		oNewConfig.columnDefs = [];

		if (oConfig) {

			oNewConfig.save = oConfig['save'] !== false;
			oNewConfig.searching = oConfig['search'] !== false;
			oNewConfig.highlight = oConfig['highlight'] !== false;

			if (oConfig['excel_export']) {
				oNewConfig.buttons.push('csv');
			}

			if (oConfig['paginate']) {
				var iPaginate = parseInt(oConfig['paginate']);
				oNewConfig.pageLength = iPaginate > 0 ? iPaginate : -1;
			}

			oNewConfig.columns = oConfig.columns.map(function (aColumnParams, iColIndex) {
				var result = {
					visible: true
				};

                result.visible = aColumnParams.visible !== false;

                if (aColumnParams.sort) {
                    // find if we already have configured a type of sorting create new config
                    // and push targets (columns)

                    var oSort = oNewConfig.columnDefs.find(function (oSort) {
                        return oSort.type === aColumnParams.sort;
                    });

                    if (oSort) {
                        oSort.targets.push(iColIndex);
                    } else {
                        oNewConfig.columnDefs.push({
                            type: aColumnParams.sort,
                            targets: [iColIndex]
                        });
                    }
                }

				return result;
			});

			oConfig['initial_sort'] = oConfig['initial_sort'] || DataTable.DEFAULT_SORTING;

			if (oConfig['initial_sort'] !== 'none') {
				aOrders = oConfig['initial_sort'].split(';');
				aOrders = aOrders.map(function (aItems) {
					return aItems.split(',');
				});
			}

			oNewConfig.order = aOrders;

		}

		return oNewConfig;
	};

	DataTable.prototype.onFilterChange = function (iColumnIndex, oOptions) {
		// modify global state
		// setting parameters before drawing of column
		this.oChangedFilters[iColumnIndex] = {
			control: oOptions.control,
			value: oOptions.value
		};

		this.API.columns(iColumnIndex).draw();
	};

	DataTable.prototype.getSelectOptions = function (iColumnIndex) {
		// loop through select options and map them to array
		var aOptions = [];

		this.API
			.columns(iColumnIndex)
			.data()
			.unique()
			.sort()[0]
			.forEach(function (sOption) {
				var oOption;

				if (aOptions.indexOf(sOption) > -1) {
					// if options is already in array return as we don't want duplicates
					return;
				}

				try {
					// some options are lists with list items (ul > li),
					// so we wrap them to jQuery objects and push their
					// values to the array of options if they are not already pushed

					// some options may contain special characters ( "(", ")", ";" ...)
					// this throws exception when we wrap them with jQuery and stops
					// javascript execution
					oOption = $(sOption);
				} catch (error) {
					oOption = null;
				}

				if (oOption && oOption.length > 0) {
					oOption.find('li').each(function (i, sOption) {
						if (aOptions.indexOf(sOption.textContent) < 0) {
							aOptions.push(sOption.textContent);
						}
					});
				} else {
					aOptions.push(sOption);
				}

			});

		aOptions.sort(DataTableUtil.sortAlphaNumeric);

		return aOptions;
	};

	DataTable.prototype.getLifeCycleMethods = function (sId, oConfig) {
		var that = this;

		return {
			initComplete: function () {
				that.API = this.api();

				// Create new table row to append filters
				var oTableHeader = $('#' + sId + ' > thead'),
					oNewTableRow = $('<tr/>'),
					oFilterHeader,
					oHighlighter,
					iIndex = 0;

				this.api().columns().every(function () {
					// loop each column and create filter (table header(th)/filterHeader) from column filter params
					// append to the newly created table row
					// attach change events and modify state to use later when
					// table is about to redraw itself
					var iLocalIndex = iIndex,
						aColumnParams = oConfig.columns[iIndex],
						aOptions = [],
						oFilter,
						bIsTypeSelect = aColumnParams.filter === "select";

					oFilterHeader = $('<th/>');
					oFilterHeader.addClass(DataTable.FILTER_CLASS_WRAPPER);

					that.oColumns[iIndex] = {};
					that.oColumns[iIndex].aControls = [];
					that.oColumns[iIndex].filterHeader = oFilterHeader;

					if (that.get("highlight")) {
						oHighlighter = new Highlighter([].slice.call(this.nodes()), {
							useExternalStyles: false,
							shouldBeObserved: true,
							isCaseSensitive: false
						});

						that.oColumns[iIndex].highlighter = oHighlighter;
					}

					if (bIsTypeSelect) {
						aOptions = that.getSelectOptions(iIndex);
					}

					// prepare filter
					oFilter = DataTable.getFilterByType(aColumnParams.filter, aOptions);

					// append filter
					if (oFilter.control) {
						that.oColumns[iIndex].aControls.push(oFilter.control);

						oFilter.control.attachEvent(oFilter.event, function (oEvent) {
							that.onFilterChange(iLocalIndex, {
								value: oEvent.getParameter("value"),
								control: oFilter.control
							});
						});
						oFilter.control.placeAt(oFilterHeader);
					}

					oNewTableRow.append(oFilterHeader);

					iIndex++;
				});

				oTableHeader.append(oNewTableRow);
			}
		};
	};

	DataTable.getFilterByType = function (sTypeValue, aOptions) {
		var oControl, sEvent = "liveChange";

		switch (sTypeValue) {
			case 'number-range':
				oControl = new DataTableFilterRange({
					from: new Input({ type: InputType.Number, placeholder: "From" }),
					to: new Input({ type: InputType.Number, placeholder: "To" })
				}).addStyleClass(DataTable.FILTER_TYPES.NUMBER_RANGE);
				break;

			case 'select':
				sEvent = "change";
				oControl = new DataTableFilterDropDown({
					options: aOptions
				}).addStyleClass(DataTable.FILTER_TYPES.SELECT);
				break;

			case 'none':
				oControl = '';
				break;

			default:
				// inputs
				var sFilterType = DataTable.FILTER_TYPES.NORMAL,
					sInputType = InputType.Text;

				if (sTypeValue === 'regex') {
					sFilterType = DataTable.FILTER_TYPES.REGEX;
				} else if (sTypeValue === 'cell-range') {
					sFilterType = DataTable.FILTER_TYPES.CELL_RANGE;
					sInputType = InputType.Number;
				} else if (sTypeValue === 'number') {
					sFilterType = DataTable.FILTER_TYPES.NUMBER;
					sInputType = InputType.Number;
				}

				oControl = new Input({
					type: sInputType,
					placeholder: "Filter"
				}).addStyleClass(sFilterType);
		}

		return { control: oControl, event: sEvent };
	};

	return DataTable;
});<|endoftext|>


<commit_before>function size_images(context) {
  $("img", context).not(".MathJax_strut").each(function (i, obj) {
    obj = $(obj);
    if (obj.width() > 625) {
      var scale = 625 / obj.width();
      obj.width(obj.width() * scale);
    }
  });
}

$(window).load(function () {
  size_images($("#output")[0]);
});

$.fn.quickdiff("filter", "mathSpanInline",
  function (node) { return (node.nodeName === "SPAN"
                            && $(node).hasClass("mathInline")); },
  function (a, b) {
    var aHTML = $.trim($("script", a).html()), bHTML = $.trim($(b).html());
    return ("%%" + aHTML + "%%") !== bHTML;
  });

$.fn.quickdiff("filter", "mathSpan",
  function (node) { return (node.nodeName === "SPAN"
                            && $(node).hasClass("math")); },
  function (a, b) {
    var aHTML = $.trim($("script", a).html()), bHTML = $.trim($(b).html());
    return ("$$" + aHTML + "$$") !== bHTML;
  });

var Page = (function () {
  var previewing = false,
    editor_scrolltop = 0,
    editor_position = {start: 0, end: 0},
    preview_scrolltop = 0,
    markdown = new Showdown.converter(),
    narrowscreen = false,
    inputarea,
    preproc = $("

"),
    outputel,
    renderDelay = 50;

  var setRenderDelay = function (rendertime) {
    if (rendertime > 200) {
      renderDelay = 400;
    } else if (rendertime > 10) {
      renderDelay = 50;
    }
  };

  var redraw = function () {
    var startTime = (new Date()).getTime();
    preproc.html(markdown.makeHtml(inputarea.val()));
    var patch = outputel.quickdiff("patch", preproc, ["mathSpan", "mathSpanInline"]);

    if (patch.type !== "identical" && patch.replace.length > 0) {
      $.each(patch.replace, function (i, el) {
        if (el.innerHTML) {
          size_images(el);
          MathJax.Hub.Typeset(el, function () {
            setRenderDelay((new Date()).getTime() - startTime);
          });
        } else {
          setRenderDelay((new Date()).getTime() - startTime);
        }
      });
    } else {
      setRenderDelay((new Date()).getTime() - startTime);
    }
  };

  var savePagePosition = function () {
    preview_scrolltop = $("body").scrollTop();
  };
  var restorePagePosition = function () {
    $("body").scrollTop(preview_scrolltop);
  };

  var saveEditorState = function () {
    editor_scrolltop = inputarea.scrollTop();
    editor_position = inputarea.getSelection();
  };
  var restoreEditorState = function () {
    inputarea.setSelection(editor_position.start, editor_position.end);
    inputarea.scrollTop(editor_scrolltop);
  };

  var setPreviewing = function (toggle) {
    previewing = toggle;
    $("body").toggleClass("preview", previewing);
    if (previewing) {
      $("#preview-enable a").text("EDITOR");
    } else {
      $("#preview-enable a").text("PREVIEW");
    }
  };

  var reconstrain = function () {
    var height = $(window).height(), width = $(window).width();

    if (editing) {
      inputarea.height(height - 90);
    }

    var switched = false;
    if (width < 1260 && !narrowscreen) {
      if (editing) {
        savePagePosition();
      }
      narrowscreen = true;
      setPreviewing(false);
      switched = true;
    } else if (width >= 1260 && narrowscreen) {
      if (editing) {
        saveEditorState();
      }
      narrowscreen = false;
      setPreviewing(true);
      switched = true;
    }

    $("body").toggleClass("widescreen", !narrowscreen);
    $("body").toggleClass("narrowscreen", narrowscreen);

    if (editing && switched && !narrowscreen) {
      restorePagePosition();
      restoreEditorState();
    }
  };

  var setEditing = function (edit) {
    editing = edit;
    $("body").toggleClass("readonly", !editing);
    $("body").toggleClass("editing", editing);
    if (editing) {
      reconstrain();
      restoreEditorState();
      $("#edit-enable a").text("CANCEL");
    } else {
      $("#page").css({height: "auto"});
      restorePagePosition();
      $("#edit-enable a").text("EDIT");
    }
  };

  return {
    editing: function () {
      if (arguments.length === 0) {
        return editing;
      } else {
        setEditing(arguments[0]);
      }
    },
    preview: function () {
      if (arguments.length === 0) {
        return previewing;
      } else {
        setPreviewing(arguments[0]);
      }
    },
    savePagePosition: savePagePosition,
    restorePagePosition: restorePagePosition,
    saveEditorState: saveEditorState,
    restoreEditorState: restoreEditorState,
    init : function (name, input, output) {
      pagename = name;
      inputarea = input;
      outputel = output;
    },
    reconstrain: reconstrain,
    pagename: function () {
      return pagename;
    },
    narrowscreen: function () {
      return narrowscreen;
    },
    redraw: redraw
  };
}());

$(document).ready(function () {
  var loaded = editing,
    inputarea = $("textarea"),
    outputel = $("#output > div");

  Page.init(pagename, inputarea, outputel);
  Page.reconstrain();
  Page.editing(editing);

  $(window).resize(Page.reconstrain);

  $("textarea").keyup(function () {
    if (this.timer) {
      clearTimeout(this.timer);
    }
    this.timer = setTimeout(Page.redraw, Page.renderDelay);
  });

  $("#edit-enable a").click(function () {
    if (!loaded) {
      inputarea.val("Loading..");
      $.getJSON("/" + Page.pagename() + ".json", function (data) {
        inputarea.val(data.text);
        loaded = true;
        Page.redraw();
      });
    }

    if (Page.preview() || !Page.narrowscreen()) {
      Page.savePagePosition();
    }
    if (Page.editing()) {
      Page.saveEditorState();
    }

    Page.preview(false);
    Page.editing(!Page.editing());
    return false;
  });

  $("#preview-enable a").click(function () {
    if (Page.preview()) {
      Page.savePagePosition();
      Page.preview(false);
      Page.restoreEditorState();
    } else {
      Page.saveEditorState();
      Page.preview(true);
      Page.restorePagePosition();
    }
    return false;
  });

  $("#savebutton").click(function () {
    $.post("/" + Page.pagename() + ".json", {text: inputarea.val(), password: $("#password").val()}, function (ret) {
      if (ret && ret.status === "success") {
        Grumble.show({message: "Saved successfully.", title: "Saved", icon: "success"});
      } else {
        if (ret && ret.status === "failure") {
          Grumble.show({message: ret.message, title: "Error", icon: "error"});
        } else {
          Grumble.show({message: "Unknown response from the server.", title: "Error", icon: "error"});
        }
      }
    }, "json");
  });

});<commit_msg>Add renderDelay getter<commit_after>function size_images(context) {
  $("img", context).not(".MathJax_strut").each(function (i, obj) {
    obj = $(obj);
    if (obj.width() > 625) {
      var scale = 625 / obj.width();
      obj.width(obj.width() * scale);
    }
  });
}

$(window).load(function () {
  size_images($("#output")[0]);
});

$.fn.quickdiff("filter", "mathSpanInline",
  function (node) { return (node.nodeName === "SPAN"
                            && $(node).hasClass("mathInline")); },
  function (a, b) {
    var aHTML = $.trim($("script", a).html()), bHTML = $.trim($(b).html());
    return ("%%" + aHTML + "%%") !== bHTML;
  });

$.fn.quickdiff("filter", "mathSpan",
  function (node) { return (node.nodeName === "SPAN"
                            && $(node).hasClass("math")); },
  function (a, b) {
    var aHTML = $.trim($("script", a).html()), bHTML = $.trim($(b).html());
    return ("$$" + aHTML + "$$") !== bHTML;
  });

var Page = (function () {
  var previewing = false,
    editor_scrolltop = 0,
    editor_position = {start: 0, end: 0},
    preview_scrolltop = 0,
    markdown = new Showdown.converter(),
    narrowscreen = false,
    inputarea,
    preproc = $("

"),
    outputel,
    renderDelay = 50;

  var setRenderDelay = function (rendertime) {
    if (rendertime > 200) {
      renderDelay = 400;
    } else if (rendertime > 10) {
      renderDelay = 50;
    }
  };

  var redraw = function () {
    var startTime = (new Date()).getTime();
    preproc.html(markdown.makeHtml(inputarea.val()));
    var patch = outputel.quickdiff("patch", preproc, ["mathSpan", "mathSpanInline"]);

    if (patch.type !== "identical" && patch.replace.length > 0) {
      $.each(patch.replace, function (i, el) {
        if (el.innerHTML) {
          size_images(el);
          MathJax.Hub.Typeset(el, function () {
            setRenderDelay((new Date()).getTime() - startTime);
          });
        } else {
          setRenderDelay((new Date()).getTime() - startTime);
        }
      });
    } else {
      setRenderDelay((new Date()).getTime() - startTime);
    }
  };

  var savePagePosition = function () {
    preview_scrolltop = $("body").scrollTop();
  };
  var restorePagePosition = function () {
    $("body").scrollTop(preview_scrolltop);
  };

  var saveEditorState = function () {
    editor_scrolltop = inputarea.scrollTop();
    editor_position = inputarea.getSelection();
  };
  var restoreEditorState = function () {
    inputarea.setSelection(editor_position.start, editor_position.end);
    inputarea.scrollTop(editor_scrolltop);
  };

  var setPreviewing = function (toggle) {
    previewing = toggle;
    $("body").toggleClass("preview", previewing);
    if (previewing) {
      $("#preview-enable a").text("EDITOR");
    } else {
      $("#preview-enable a").text("PREVIEW");
    }
  };

  var reconstrain = function () {
    var height = $(window).height(), width = $(window).width();

    if (editing) {
      inputarea.height(height - 90);
    }

    var switched = false;
    if (width < 1260 && !narrowscreen) {
      if (editing) {
        savePagePosition();
      }
      narrowscreen = true;
      setPreviewing(false);
      switched = true;
    } else if (width >= 1260 && narrowscreen) {
      if (editing) {
        saveEditorState();
      }
      narrowscreen = false;
      setPreviewing(true);
      switched = true;
    }

    $("body").toggleClass("widescreen", !narrowscreen);
    $("body").toggleClass("narrowscreen", narrowscreen);

    if (editing && switched && !narrowscreen) {
      restorePagePosition();
      restoreEditorState();
    }
  };

  var setEditing = function (edit) {
    editing = edit;
    $("body").toggleClass("readonly", !editing);
    $("body").toggleClass("editing", editing);
    if (editing) {
      reconstrain();
      restoreEditorState();
      $("#edit-enable a").text("CANCEL");
    } else {
      $("#page").css({height: "auto"});
      restorePagePosition();
      $("#edit-enable a").text("EDIT");
    }
  };

  return {
    editing: function () {
      if (arguments.length === 0) {
        return editing;
      } else {
        setEditing(arguments[0]);
      }
    },
    preview: function () {
      if (arguments.length === 0) {
        return previewing;
      } else {
        setPreviewing(arguments[0]);
      }
    },
    savePagePosition: savePagePosition,
    restorePagePosition: restorePagePosition,
    saveEditorState: saveEditorState,
    restoreEditorState: restoreEditorState,
    init : function (name, input, output) {
      pagename = name;
      inputarea = input;
      outputel = output;
    },
    reconstrain: reconstrain,
    pagename: function () {
      return pagename;
    },
    narrowscreen: function () {
      return narrowscreen;
    },
    redraw: redraw,
    renderDelay: function () {
      return renderDelay;
    }
  };
}());

$(document).ready(function () {
  var loaded = editing,
    inputarea = $("textarea"),
    outputel = $("#output > div");

  Page.init(pagename, inputarea, outputel);
  Page.reconstrain();
  Page.editing(editing);

  $(window).resize(Page.reconstrain);

  $("textarea").keyup(function () {
    if (this.timer) {
      clearTimeout(this.timer);
    }
    this.timer = setTimeout(Page.redraw, Page.renderDelay());
  });

  $("#edit-enable a").click(function () {
    if (!loaded) {
      inputarea.val("Loading..");
      $.getJSON("/" + Page.pagename() + ".json", function (data) {
        inputarea.val(data.text);
        loaded = true;
        Page.redraw();
      });
    }

    if (Page.preview() || !Page.narrowscreen()) {
      Page.savePagePosition();
    }
    if (Page.editing()) {
      Page.saveEditorState();
    }

    Page.preview(false);
    Page.editing(!Page.editing());
    return false;
  });

  $("#preview-enable a").click(function () {
    if (Page.preview()) {
      Page.savePagePosition();
      Page.preview(false);
      Page.restoreEditorState();
    } else {
      Page.saveEditorState();
      Page.preview(true);
      Page.restorePagePosition();
    }
    return false;
  });

  $("#savebutton").click(function () {
    $.post("/" + Page.pagename() + ".json", {text: inputarea.val(), password: $("#password").val()}, function (ret) {
      if (ret && ret.status === "success") {
        Grumble.show({message: "Saved successfully.", title: "Saved", icon: "success"});
      } else {
        if (ret && ret.status === "failure") {
          Grumble.show({message: ret.message, title: "Error", icon: "error"});
        } else {
          Grumble.show({message: "Unknown response from the server.", title: "Error", icon: "error"});
        }
      }
    }, "json");
  });

});<|endoftext|>


<commit_before>const getCookie = name => {
    const cookie = document.cookie
        .split(';')
        .find(cookie => cookie.startsWith(name + '=')) || ''
    return decodeURIComponent(cookie.substring(name.length + 1))
}

export var csrftoken = getCookie('csrftoken')
<commit_msg>js: django: fixup cookie parsing which is somehow different on heroku<commit_after>const getCookie = name => {
    const cookie = document.cookie
        .split(';')
        .find(cookie => cookie.trim().startsWith(name + '=')) || ''
    return decodeURIComponent(cookie.trim().substring(name.length + 1))
}

export var csrftoken = getCookie('csrftoken')
<|endoftext|>