<commit_before>// @flow

import styles from './EventDetail.css';
import React, { Component, Fragment, type Node } from 'react';
import CommentView from 'app/components/Comments/CommentView';
import Icon from 'app/components/Icon';
import JoinEventForm from '../JoinEventForm';
import RegisteredSummary from '../RegisteredSummary';
import {
  AttendanceStatus,
  ModalParentComponent
} from 'app/components/UserAttendance';
import Tag from 'app/components/Tags/Tag';
import moment from 'moment-timezone';
import { FormatTime, FromToTime } from 'app/components/Time';
import InfoList from 'app/components/InfoList';
import { Flex } from 'app/components/Layout';
import Tooltip from 'app/components/Tooltip';
import { EVENT_TYPE_TO_STRING, colorForEvent } from '../../utils';
import Admin from '../Admin';
import RegistrationMeta from '../RegistrationMeta';
import DisplayContent from 'app/components/DisplayContent';
import {
  Content,
  ContentHeader,
  ContentSection,
  ContentMain,
  ContentSidebar
} from 'app/components/Content';
import { Link } from 'react-router';
import UserGrid from 'app/components/UserGrid';
import type {
  ID,
  EventPool,
  EventRegistration,
  Event,
  ActionGrant
} from 'app/models';
import type { CommentEntity } from 'app/reducers/comments';
import type { UserEntity } from 'app/reducers/users';

type InterestedButtonProps = {
  isInterested: boolean
};

const InterestedButton = ({ isInterested }: InterestedButtonProps) => {
  const icon = isInterested ? 'star' : 'star-outline';
  return (

      <Tooltip
        style={{ lineHeight: '1.3rem' }}
        content={

            Favoritt

        }
      >
        <Icon className={styles.star} name={icon} />
      </Tooltip>

  );
};

type Props = {
  eventId: ID,
  event: Event,
  loggedIn: boolean,
  currentUser: UserEntity,
  actionGrant: ActionGrant,
  comments: Array<CommentEntity>,
  error?: Object,
  pools: Array<EventPool>,
  registrations: Array<EventRegistration>,
  currentRegistration: EventRegistration,
  currentRegistrationIndex: number,
  hasSimpleWaitingList: boolean,
  waitingRegistrations: Array<EventRegistration>,
  register: ({
    eventId: ID,
    captchaResponse: string,
    feedback: string,
    userId: ID
  }) => Promise<*>,
  follow: (eventId: ID, userId: ID) => Promise<*>,
  unfollow: (eventId: ID, userId: ID) => Promise<*>,
  unregister: ({
    eventId: ID,
    registrationId: ID,
    userId: ID
  }) => Promise<*>,
  payment: (eventId: ID, token: string) => Promise<*>,
  updateFeedback: (
    eventId: ID,
    registrationId: ID,
    feedback: string
  ) => Promise<*>,
  deleteEvent: (eventId: ID) => Promise<*>,
  deleteComment: (id: ID, commentTarget: string) => Promise<*>
};

export default class EventDetail extends Component<Props> {
  handleRegistration = ({ captchaResponse, feedback, type }: Object) => {
    const {
      eventId,
      currentRegistration,
      register,
      unregister,
      updateFeedback,
      currentUser: { id: userId }
    } = this.props;
    switch (type) {
      case 'feedback':
        return updateFeedback(eventId, currentRegistration.id, feedback);
      case 'register':
        // Note that we do not return this promise due to custom submitting handling
        register({
          eventId,
          captchaResponse,
          feedback,
          userId
        });
        return;
      case 'unregister':
        unregister({
          eventId,
          registrationId: currentRegistration.id,
          userId
        });
        return;
      default:
        return undefined;
    }
  };

  handleToken = (token: Object) => {
    this.props.payment(this.props.event.id, token.id);
  };

  render() {
    const {
      event,
      loggedIn,
      currentUser,
      actionGrant,
      comments,
      error,
      pools,
      registrations,
      currentRegistration,
      currentRegistrationIndex,
      hasSimpleWaitingList,
      deleteEvent,
      follow,
      unfollow,
      deleteComment
    } = this.props;
    if (!event.id) {
      return null;
    }

    if (error) {
      return
{error.message}
;
    }

    const color = colorForEvent(event.eventType);
    const onRegisterClick = event.isUserFollowing
      ? () => unfollow(event.isUserFollowing.id, event.id)
      : () => follow(currentUser.id, event.id);

    const infoItems: Array<?{ key: string, value: Node }> = [
      event.company && {
        key: 'Arrangerende bedrift',
        value: (
          <Link to={`/companies/${event.company.id}`}>
            {event.company.name}
          </Link>
        )
      },
      event.createdBy && {
        key: 'Forfatter',
        value: (
          <Link to={`/users/${event.createdBy.username}`}>
            {event.createdBy.fullName}
          </Link>
        )
      },
      event.responsibleGroup && {
        key: 'Arrangør',
        value: (

            {event.responsibleGroup.name}{' '}
            {event.responsibleGroup.contactEmail && (
              <a href={`mailto:${event.responsibleGroup.contactEmail}`}>
                {event.responsibleGroup.contactEmail}

            )}

        )
      },
      {
        key: 'Hva',
        value: EVENT_TYPE_TO_STRING(event.eventType)
      },
      {
        key: 'Når',
        value: <FromToTime from={event.startTime} to={event.endTime} />
      },
      { key: 'Finner sted i', value: event.location },
      event.activationTime
        ? {
            key: 'Påmelding åpner',
            value: <FormatTime time={event.activationTime} />
          }
        : null,
      event.unregistrationDeadline
        ? {
            key: 'Avregistreringsfrist',
            value: <FormatTime time={event.unregistrationDeadline} />
          }
        : null
    ];

    const paidItems: Array<?{ key: string, value: Node }> = [
      { key: 'Pris', value: `${event.priceMember / 100},-` },
      event.paymentDueDate
        ? {
            key: 'Betalingsfrist',
            value: <FormatTime time={event.paymentDueDate} />
          }
        : null
    ];

    return (

        <Content
          banner={event.cover || (event.company && event.company.logo)}
          youtubeUrl={event.youtubeUrl}
        >
          <ContentHeader
            borderColor={color}
            onClick={onRegisterClick}
            className={styles.title}
          >
            {loggedIn && (
              <InterestedButton isInterested={!!event.isUserFollowing} />
            )}
            {event.title}
          </ContentHeader>

          <ContentSection>
            <ContentMain>
              <DisplayContent content={event.text} />
              <Flex className={styles.tagRow}>
                {event.tags.map((tag, i) => (
                  <Tag key={i} tag={tag} />
                ))}
              </Flex>
            </ContentMain>
            <ContentSidebar>
              <InfoList items={infoItems} />
              {event.isPriced && (

                  Dette er et betalt arrangement
                  <InfoList items={paidItems} />

              )}
              <Flex column>

Påmeldte

                {registrations ? (
                  <Fragment>
                    <UserGrid
                      minRows={2}
                      maxRows={2}
                      users={registrations.slice(0, 14).map(reg => reg.user)}
                    />
                    <ModalParentComponent
                      key="modal"
                      pools={pools}
                      registrations={registrations}
                      title="Påmeldte"
                    >
                      <RegisteredSummary
                        registrations={registrations}
                        currentRegistration={currentRegistration}
                      />
                      <AttendanceStatus />
                    </ModalParentComponent>
                  </Fragment>
                ) : (
                  <AttendanceStatus pools={pools} />
                )}

                {loggedIn && (
                  <RegistrationMeta
                    useConsent={event.useConsent}
                    hasEnded={moment(event.endTime).isBefore(moment())}
                    registration={currentRegistration}
                    isPriced={event.isPriced}
                    registrationIndex={currentRegistrationIndex}
                    hasSimpleWaitingList={hasSimpleWaitingList}
                  />
                )}

                {event.unansweredSurveys &&
                event.unansweredSurveys.length > 0 ? (

                      Du kan ikke melde deg på dette arrangementet fordi du har
                      ubesvarte spørreundersøkelser.

                      Man må svare på alle spørreundersøkelser for tidligere
                      arrangementer før man kan melde seg på nye arrangementer.
                      Du kan svare på undersøkelsene dine ved å trykke på
                      følgende linker:

                      {event.unansweredSurveys.map((surveyId, i) => (

                          <Link to={`/surveys/${surveyId}`}>
                            Undersøkelse {i + 1}
                          </Link>

                      ))}

                ) : (

                    <JoinEventForm
                      event={event}
                      registration={currentRegistration}
                      currentUser={currentUser}
                      onToken={this.handleToken}
                      onSubmit={this.handleRegistration}
                    />

                )}
                <Admin
                  actionGrant={actionGrant}
                  event={event}
                  deleteEvent={deleteEvent}
                />
              </Flex>
            </ContentSidebar>
          </ContentSection>
          <Link
            to="/pages/arrangementer/26-arrangementsregler"
            style={{ marginTop: 0 }}
          >
            <Flex alignItems="center">
              <Icon name="document" style={{ marginRight: '4px' }} />
              Regler for Abakus' arrangementer
            </Flex>
          </Link>
          {loggedIn && (

              Du kan oppdatere dine allergier og preferanser
              <Link to="/users/me"> her</Link>.

          )}

          {event.commentTarget && (
            <CommentView
              style={{ marginTop: 20 }}
              user={currentUser}
              commentTarget={event.commentTarget}
              loggedIn={loggedIn}
              comments={comments}
              deleteComment={deleteComment}
            />
          )}
        </Content>

    );
  }
}
<commit_msg>Hide registration part of the event details on OPEN events<commit_after>// @flow

import styles from './EventDetail.css';
import React, { Component, Fragment, type Node } from 'react';
import CommentView from 'app/components/Comments/CommentView';
import Icon from 'app/components/Icon';
import JoinEventForm from '../JoinEventForm';
import RegisteredSummary from '../RegisteredSummary';
import {
  AttendanceStatus,
  ModalParentComponent
} from 'app/components/UserAttendance';
import Tag from 'app/components/Tags/Tag';
import moment from 'moment-timezone';
import { FormatTime, FromToTime } from 'app/components/Time';
import InfoList from 'app/components/InfoList';
import { Flex } from 'app/components/Layout';
import Tooltip from 'app/components/Tooltip';
import { EVENT_TYPE_TO_STRING, colorForEvent } from '../../utils';
import Admin from '../Admin';
import RegistrationMeta from '../RegistrationMeta';
import DisplayContent from 'app/components/DisplayContent';
import {
  Content,
  ContentHeader,
  ContentSection,
  ContentMain,
  ContentSidebar
} from 'app/components/Content';
import { Link } from 'react-router';
import UserGrid from 'app/components/UserGrid';
import type {
  ID,
  EventPool,
  EventRegistration,
  Event,
  ActionGrant
} from 'app/models';
import type { CommentEntity } from 'app/reducers/comments';
import type { UserEntity } from 'app/reducers/users';

type InterestedButtonProps = {
  isInterested: boolean
};

const InterestedButton = ({ isInterested }: InterestedButtonProps) => {
  const icon = isInterested ? 'star' : 'star-outline';
  return (

      <Tooltip
        style={{ lineHeight: '1.3rem' }}
        content={

            Favoritt

        }
      >
        <Icon className={styles.star} name={icon} />
      </Tooltip>

  );
};

type Props = {
  eventId: ID,
  event: Event,
  loggedIn: boolean,
  currentUser: UserEntity,
  actionGrant: ActionGrant,
  comments: Array<CommentEntity>,
  error?: Object,
  pools: Array<EventPool>,
  registrations: Array<EventRegistration>,
  currentRegistration: EventRegistration,
  currentRegistrationIndex: number,
  hasSimpleWaitingList: boolean,
  waitingRegistrations: Array<EventRegistration>,
  register: ({
    eventId: ID,
    captchaResponse: string,
    feedback: string,
    userId: ID
  }) => Promise<*>,
  follow: (eventId: ID, userId: ID) => Promise<*>,
  unfollow: (eventId: ID, userId: ID) => Promise<*>,
  unregister: ({
    eventId: ID,
    registrationId: ID,
    userId: ID
  }) => Promise<*>,
  payment: (eventId: ID, token: string) => Promise<*>,
  updateFeedback: (
    eventId: ID,
    registrationId: ID,
    feedback: string
  ) => Promise<*>,
  deleteEvent: (eventId: ID) => Promise<*>,
  deleteComment: (id: ID, commentTarget: string) => Promise<*>
};

export default class EventDetail extends Component<Props> {
  handleRegistration = ({ captchaResponse, feedback, type }: Object) => {
    const {
      eventId,
      currentRegistration,
      register,
      unregister,
      updateFeedback,
      currentUser: { id: userId }
    } = this.props;
    switch (type) {
      case 'feedback':
        return updateFeedback(eventId, currentRegistration.id, feedback);
      case 'register':
        // Note that we do not return this promise due to custom submitting handling
        register({
          eventId,
          captchaResponse,
          feedback,
          userId
        });
        return;
      case 'unregister':
        unregister({
          eventId,
          registrationId: currentRegistration.id,
          userId
        });
        return;
      default:
        return undefined;
    }
  };

  handleToken = (token: Object) => {
    this.props.payment(this.props.event.id, token.id);
  };

  render() {
    const {
      event,
      loggedIn,
      currentUser,
      actionGrant,
      comments,
      error,
      pools,
      registrations,
      currentRegistration,
      currentRegistrationIndex,
      hasSimpleWaitingList,
      deleteEvent,
      follow,
      unfollow,
      deleteComment
    } = this.props;
    if (!event.id) {
      return null;
    }

    if (error) {
      return
{error.message}
;
    }

    const color = colorForEvent(event.eventType);
    const onRegisterClick = event.isUserFollowing
      ? () => unfollow(event.isUserFollowing.id, event.id)
      : () => follow(currentUser.id, event.id);

    const infoItems: Array<?{ key: string, value: Node }> = [
      event.company && {
        key: 'Arrangerende bedrift',
        value: (
          <Link to={`/companies/${event.company.id}`}>
            {event.company.name}
          </Link>
        )
      },
      event.createdBy && {
        key: 'Forfatter',
        value: (
          <Link to={`/users/${event.createdBy.username}`}>
            {event.createdBy.fullName}
          </Link>
        )
      },
      event.responsibleGroup && {
        key: 'Arrangør',
        value: (

            {event.responsibleGroup.name}{' '}
            {event.responsibleGroup.contactEmail && (
              <a href={`mailto:${event.responsibleGroup.contactEmail}`}>
                {event.responsibleGroup.contactEmail}

            )}

        )
      },
      {
        key: 'Hva',
        value: EVENT_TYPE_TO_STRING(event.eventType)
      },
      {
        key: 'Når',
        value: <FromToTime from={event.startTime} to={event.endTime} />
      },
      { key: 'Finner sted i', value: event.location },
      event.activationTime
        ? {
            key: 'Påmelding åpner',
            value: <FormatTime time={event.activationTime} />
          }
        : null,
      event.unregistrationDeadline && event.eventStatusType !== 'OPEN'
        ? {
            key: 'Avregistreringsfrist',
            value: <FormatTime time={event.unregistrationDeadline} />
          }
        : null
    ];

    const paidItems: Array<?{ key: string, value: Node }> = [
      { key: 'Pris', value: `${event.priceMember / 100},-` },
      event.paymentDueDate
        ? {
            key: 'Betalingsfrist',
            value: <FormatTime time={event.paymentDueDate} />
          }
        : null
    ];

    return (

        <Content
          banner={event.cover || (event.company && event.company.logo)}
          youtubeUrl={event.youtubeUrl}
        >
          <ContentHeader
            borderColor={color}
            onClick={onRegisterClick}
            className={styles.title}
          >
            {loggedIn && (
              <InterestedButton isInterested={!!event.isUserFollowing} />
            )}
            {event.title}
          </ContentHeader>

          <ContentSection>
            <ContentMain>
              <DisplayContent content={event.text} />
              <Flex className={styles.tagRow}>
                {event.tags.map((tag, i) => (
                  <Tag key={i} tag={tag} />
                ))}
              </Flex>
            </ContentMain>
            <ContentSidebar>
              <InfoList items={infoItems} />
              {event.isPriced && (

                  Dette er et betalt arrangement
                  <InfoList items={paidItems} />

              )}
              {event.eventStatusType === 'OPEN' ? (
                <Flex column>

Påmelding

Dette arrangementet krever ingen påmelding

                </Flex>
              ) : (
                <Flex column>

Påmeldte

                  {registrations ? (
                    <Fragment>
                      <UserGrid
                        minRows={2}
                        maxRows={2}
                        users={registrations.slice(0, 14).map(reg => reg.user)}
                      />
                      <ModalParentComponent
                        key="modal"
                        pools={pools}
                        registrations={registrations}
                        title="Påmeldte"
                      >
                        <RegisteredSummary
                          registrations={registrations}
                          currentRegistration={currentRegistration}
                        />
                        <AttendanceStatus />
                      </ModalParentComponent>
                    </Fragment>
                  ) : (
                    <AttendanceStatus pools={pools} />
                  )}

                  {loggedIn && (
                    <RegistrationMeta
                      useConsent={event.useConsent}
                      hasEnded={moment(event.endTime).isBefore(moment())}
                      registration={currentRegistration}
                      isPriced={event.isPriced}
                      registrationIndex={currentRegistrationIndex}
                      hasSimpleWaitingList={hasSimpleWaitingList}
                    />
                  )}

                  {event.unansweredSurveys &&
                  event.unansweredSurveys.length > 0 ? (

                        Du kan ikke melde deg på dette arrangementet fordi du
                        har ubesvarte spørreundersøkelser.

                        Man må svare på alle spørreundersøkelser for tidligere
                        arrangementer før man kan melde seg på nye
                        arrangementer. Du kan svare på undersøkelsene dine ved å
                        trykke på følgende linker:

                        {event.unansweredSurveys.map((surveyId, i) => (

                            <Link to={`/surveys/${surveyId}`}>
                              Undersøkelse {i + 1}
                            </Link>

                        ))}

                  ) : (

                      <JoinEventForm
                        event={event}
                        registration={currentRegistration}
                        currentUser={currentUser}
                        onToken={this.handleToken}
                        onSubmit={this.handleRegistration}
                      />

                  )}
                </Flex>
              )}
              <Flex column>
                <Admin
                  actionGrant={actionGrant}
                  event={event}
                  deleteEvent={deleteEvent}
                />
              </Flex>
            </ContentSidebar>
          </ContentSection>
          <Link
            to="/pages/arrangementer/26-arrangementsregler"
            style={{ marginTop: 0 }}
          >
            <Flex alignItems="center">
              <Icon name="document" style={{ marginRight: '4px' }} />
              Regler for Abakus' arrangementer
            </Flex>
          </Link>
          {loggedIn && (

              Du kan oppdatere dine allergier og preferanser
              <Link to="/users/me"> her</Link>.

          )}

          {event.commentTarget && (
            <CommentView
              style={{ marginTop: 20 }}
              user={currentUser}
              commentTarget={event.commentTarget}
              loggedIn={loggedIn}
              comments={comments}
              deleteComment={deleteComment}
            />
          )}
        </Content>

    );
  }
}
<|endoftext|>


<commit_before>var fs = require('fs');
var expect = require('chai').expect;
var rimraf = require('rimraf');
var FixtureDir = require('../');

function cleanupFixtureDir() {
  after(function (done) {
    this.dir.destroy(done);
    delete this.dir;
  });
}

var fsUtils = {
  mkdir: function (dirpath) {
    before(function (done) {
      fs.mkdir(dirpath, done);
    });
  },
  readdir: function (dirpath) {
    before(function (done) {
      var that = this;
      fs.readdir(dirpath, function (err, files) {
        that.files = files;
        done(err);
      });
    });
    after(function () {
      delete this.files;
    });
  },
  writeFile: function (filepath, content) {
    before(function (done) {
      fs.writeFile(filepath, content, done);
    });
  }
};

// Clean up tmp directory
before(function (done) {
  rimraf('/tmp/fixture-dir-tests', done);
});

describe('A FixtureDir', function () {
  var fixtureDir = new FixtureDir('fixture-dir-tests');

  describe('of a nameless folder', function () {
    before(function (done) {
      var that = this;
      fixtureDir.mkdir(function (err, dir) {
        that.dir = dir;
        done(err);
      });
    });
    fsUtils.readdir('/tmp/fixture-dir-tests');

    it('creates a temporary directory in our namespace', function () {
      expect(this.files).to.have.length(1);
    });

    describe('when destroyed', function () {
      before(function (done) {
        this.dir.destroy(done);
        delete this.dir;
      });
      fsUtils.readdir('/tmp/fixture-dir-tests');

      it('no longer exists', function () {
        expect(this.files).to.have.length(0);
      });
    });
  });

  describe('of a named folder', function () {
    before(function (done) {
      var that = this;
      fixtureDir.mkdir({folderName: 'named'}, function (err, dir) {
        that.dir = dir;
        done(err);
      });
    });
    fsUtils.readdir('/tmp/fixture-dir-tests');
    cleanupFixtureDir();

    it('creates a directory under that name', function () {
      expect(this.files).to.deep.equal(['named']);
    });
  });

  describe('copying another folder', function () {
    before(function (done) {
      var that = this;
      fixtureDir.mkdir({
        copyFrom: __dirname + '/test-files/copy',
        folderName: 'copied'
      }, function (err, dir) {
        that.dir = dir;
        done(err);
      });
    });
    fsUtils.readdir('/tmp/fixture-dir-tests/copied');

    it('creates a directory with the same contents', function () {
      expect(this.files).to.deep.equal(['hai.txt']);
    });

    describe('when destroyed', function () {
      before(function (done) {
        this.dir.destroy(done);
        delete this.dir;
      });
      fsUtils.readdir('/tmp/fixture-dir-tests');

      it('no longer exists', function () {
        expect(this.files).to.not.contain('copied');
      });
    });
  });

  describe('of a named folder that already exists and has contents (e.g. bad test/no cleanup)', function () {
    // Generate our named folder and content
    fsUtils.mkdir('/tmp/fixture-dir-tests/existing');
    fsUtils.writeFile('/tmp/fixture-dir-tests/existing/hello.txt', 'world');

    // Assert the file was created for sanity
    fsUtils.readdir('/tmp/fixture-dir-tests/existing');
    before(function () {
      expect(this.files).to.deep.equal(['hello.txt']);
    });

    // Generate our fixture dir
    before(function (done) {
      var that = this;
      fixtureDir.mkdir({
        folderName: 'existing'
      }, function (err, dir) {
        that.dir = dir;
        done(err);
      });
    });
    fsUtils.readdir('/tmp/fixture-dir-tests/existing');
    cleanupFixtureDir();

    it('cleans out the directory', function () {
      expect(this.files).to.have.length(0);
    });

    it('creates a directory under that name', function () {
      // Proved by reading the directory
    });
  });
});
<commit_msg>Added test for this.dir<commit_after>var fs = require('fs');
var expect = require('chai').expect;
var rimraf = require('rimraf');
var FixtureDir = require('../');

function cleanupFixtureDir() {
  after(function (done) {
    this.dir.destroy(done);
    delete this.dir;
  });
}

var fsUtils = {
  mkdir: function (dirpath) {
    before(function (done) {
      fs.mkdir(dirpath, done);
    });
  },
  readdir: function (dirpath) {
    before(function (done) {
      var that = this;
      fs.readdir(dirpath, function (err, files) {
        that.files = files;
        done(err);
      });
    });
    after(function () {
      delete this.files;
    });
  },
  writeFile: function (filepath, content) {
    before(function (done) {
      fs.writeFile(filepath, content, done);
    });
  }
};

// Clean up tmp directory
before(function (done) {
  rimraf('/tmp/fixture-dir-tests', done);
});

describe('A FixtureDir', function () {
  var fixtureDir = new FixtureDir('fixture-dir-tests');

  describe('of a nameless folder', function () {
    before(function (done) {
      var that = this;
      fixtureDir.mkdir(function (err, dir) {
        that.dir = dir;
        done(err);
      });
    });
    fsUtils.readdir('/tmp/fixture-dir-tests');

    it('creates a temporary directory in our namespace', function () {
      expect(this.files).to.have.length(1);
    });

    describe('when destroyed', function () {
      before(function (done) {
        this.dir.destroy(done);
        delete this.dir;
      });
      fsUtils.readdir('/tmp/fixture-dir-tests');

      it('no longer exists', function () {
        expect(this.files).to.have.length(0);
      });
    });
  });

  describe('of a named folder', function () {
    before(function (done) {
      var that = this;
      fixtureDir.mkdir({folderName: 'named'}, function (err, dir) {
        that.dir = dir;
        done(err);
      });
    });
    fsUtils.readdir('/tmp/fixture-dir-tests');
    cleanupFixtureDir();

    it('creates a directory under that name', function () {
      expect(this.files).to.deep.equal(['named']);
    });

    it('provides the folder path', function () {
      expect(this.dir.path).to.deep.equal('/tmp/fixture-dir-tests/named');
    });
  });

  describe('copying another folder', function () {
    before(function (done) {
      var that = this;
      fixtureDir.mkdir({
        copyFrom: __dirname + '/test-files/copy',
        folderName: 'copied'
      }, function (err, dir) {
        that.dir = dir;
        done(err);
      });
    });
    fsUtils.readdir('/tmp/fixture-dir-tests/copied');

    it('creates a directory with the same contents', function () {
      expect(this.files).to.deep.equal(['hai.txt']);
    });

    describe('when destroyed', function () {
      before(function (done) {
        this.dir.destroy(done);
        delete this.dir;
      });
      fsUtils.readdir('/tmp/fixture-dir-tests');

      it('no longer exists', function () {
        expect(this.files).to.not.contain('copied');
      });
    });
  });

  describe('of a named folder that already exists and has contents (e.g. bad test/no cleanup)', function () {
    // Generate our named folder and content
    fsUtils.mkdir('/tmp/fixture-dir-tests/existing');
    fsUtils.writeFile('/tmp/fixture-dir-tests/existing/hello.txt', 'world');

    // Assert the file was created for sanity
    fsUtils.readdir('/tmp/fixture-dir-tests/existing');
    before(function () {
      expect(this.files).to.deep.equal(['hello.txt']);
    });

    // Generate our fixture dir
    before(function (done) {
      var that = this;
      fixtureDir.mkdir({
        folderName: 'existing'
      }, function (err, dir) {
        that.dir = dir;
        done(err);
      });
    });
    fsUtils.readdir('/tmp/fixture-dir-tests/existing');
    cleanupFixtureDir();

    it('cleans out the directory', function () {
      expect(this.files).to.have.length(0);
    });

    it('creates a directory under that name', function () {
      // Proved by reading the directory
    });
  });
});
<|endoftext|>


<commit_before>import fs from 'fs'
import path from 'path'

import Koa from 'koa'
import compress from 'koa-compress'
import onerror from 'koa-onerror'
import logger from 'koa-logger'
import lruCache from 'lru-cache'
import mkdirp from 'mkdirp'
import pug from 'pug'
import re from 'path-to-regexp'
import _debug from 'debug'

import router from './router'
import intercept from './intercept'

import config, {globals, paths} from '../build/config'

const {__DEV__} = globals

const debug = _debug('hi:server')

const template = pug.renderFile(paths.server('template.pug'), {
  pretty: !config.minimize,
  polyfill: !__DEV__
})

const app = new Koa()

onerror(app)

app.use(compress()).use(logger())

router(app)

let renderer
let readyPromise
let mfs

const koaVersion = require('koa/package.json').version
const vueVersion = require('vue-server-renderer/package.json').version

const INDEX_PAGE = 'index.html'

const DEFAULT_HEADERS = {
  'Content-Type': 'text/html',
  Server: `koa/${koaVersion}; vue-server-renderer/${vueVersion}`
}

const NON_SSR_PATTERN = ['/test']
const STATIC_PATTERN = ['/', '/articles', '/article/:id(\\d+)']

app.use(async (ctx, next) => {
  await readyPromise

  if (intercept(ctx, {logger: __DEV__ && debug})) {
    await next()
    return
  }

  ctx.set(DEFAULT_HEADERS)

  const {url} = ctx

  if (NON_SSR_PATTERN.find(pattern => re(pattern).exec(url))) {
    if (__DEV__) {
      ctx.body = mfs.createReadStream(paths.dist(INDEX_PAGE))
    } else {
      ctx.url = INDEX_PAGE
      await next()
    }
    return
  }

  let generateStatic, distPath

  if (STATIC_PATTERN.find(pattern => re(pattern).exec(url))) {
    const staticFile = url.split('?')[0].replace(/^\//, '') || 'home'
    const staticPath = `static/${staticFile}.html`
    distPath = paths.dist(staticPath)

    if (mfs.existsSync(distPath)) {
      if (__DEV__) {
        ctx.body = mfs.createReadStream(distPath)
      } else {
        ctx.url = staticPath
        await next()
      }
      return
    }

    generateStatic = true
  }

  const start = Date.now()

  const context = {url, title: 'vue-ssr'}

  try {
    let stream

    await new Promise((resolve, reject) => {
      let first = true
      let html = ''
      stream = renderer.renderToStream(context)
        .on('data', data => {
          if (first) {
            first = false
            stream.pause()
            stream.unshift(data)
            resolve()
          }

          generateStatic && (html += data.toString())
        })
        .on('error', reject)
        .on('end', () => {
          if (html) {
            try {
              mkdirp.sync(path.dirname(distPath), {fs: mfs})
              mfs.writeFileSync(distPath, html)
            } catch (e) {
              console.error(e)
            }

            debug(`static html file "${distPath}" is generated!`)
          }
          debug(`whole request: ${Date.now() - start}ms`)
        })
    })

    ctx.body = stream.resume()
  } catch (e) {
    if (e.status === 404) {
      ctx.body = '404 | Page Not Found'
    } else {
      ctx.status = 500
      ctx.body = '500 | Internal Server Error'
      console.error(`error during render : ${url}`)
      console.error(e.stack)
    }
  }
})

// https://github.com/vuejs/vue/blob/dev/packages/vue-server-renderer/README.md#why-use-bundlerenderer
const createRenderer = (bundle, options) => require('vue-server-renderer').createBundleRenderer(bundle, {
  ...options,
  template,
  inject: false,
  cache: lruCache({
    max: 1000,
    maxAge: 1000 * 60 * 15
  }),
  basedir: paths.dist(),
  runInNewContext: false
})

if (__DEV__) {
  readyPromise = require('./dev-tools').default(app, (bundle, {clientManifest, fs}) => {
    renderer = createRenderer(bundle, {clientManifest})
    mfs = fs
  })
} else {
  mfs = fs
  renderer = createRenderer(require(paths.dist('vue-ssr-server-bundle.json')), {
    clientManifest: require(paths.dist('vue-ssr-client-manifest.json'))
  })
  app.use(require('koa-static')('dist'))
}

const {serverHost, serverPort} = config

const args = [serverPort, serverHost]

app.listen(...args, err =>
  debug(...err ? [err] : ['Server is now running at %s:%s.', ...args.reverse()]))
<commit_msg>stream.once<commit_after>import fs from 'fs'
import path from 'path'

import Koa from 'koa'
import compress from 'koa-compress'
import onerror from 'koa-onerror'
import logger from 'koa-logger'
import lruCache from 'lru-cache'
import mkdirp from 'mkdirp'
import pug from 'pug'
import re from 'path-to-regexp'
import _debug from 'debug'

import router from './router'
import intercept from './intercept'

import config, {globals, paths} from '../build/config'

const {__DEV__} = globals

const debug = _debug('hi:server')

const template = pug.renderFile(paths.server('template.pug'), {
  pretty: !config.minimize,
  polyfill: !__DEV__
})

const app = new Koa()

onerror(app)

app.use(compress()).use(logger())

router(app)

let renderer
let readyPromise
let mfs

const koaVersion = require('koa/package.json').version
const vueVersion = require('vue-server-renderer/package.json').version

const INDEX_PAGE = 'index.html'

const DEFAULT_HEADERS = {
  'Content-Type': 'text/html',
  Server: `koa/${koaVersion}; vue-server-renderer/${vueVersion}`
}

const NON_SSR_PATTERN = ['/test']
const STATIC_PATTERN = ['/', '/articles', '/article/:id(\\d+)']

app.use(async (ctx, next) => {
  await readyPromise

  if (intercept(ctx, {logger: __DEV__ && debug})) {
    await next()
    return
  }

  ctx.set(DEFAULT_HEADERS)

  const {url} = ctx

  if (NON_SSR_PATTERN.find(pattern => re(pattern).exec(url))) {
    if (__DEV__) {
      ctx.body = mfs.createReadStream(paths.dist(INDEX_PAGE))
    } else {
      ctx.url = INDEX_PAGE
      await next()
    }
    return
  }

  let generateStatic, distPath

  if (STATIC_PATTERN.find(pattern => re(pattern).exec(url))) {
    const staticFile = url.split('?')[0].replace(/^\//, '') || 'home'
    const staticPath = `static/${staticFile}.html`
    distPath = paths.dist(staticPath)

    if (mfs.existsSync(distPath)) {
      if (__DEV__) {
        ctx.body = mfs.createReadStream(distPath)
      } else {
        ctx.url = staticPath
        await next()
      }
      return
    }

    generateStatic = true
  }

  const start = Date.now()

  const context = {url, title: 'vue-ssr'}

  try {
    let stream

    await new Promise((resolve, reject) => {
      let html = ''
      stream = renderer.renderToStream(context)
        .once('data', data => {
          stream.pause()
          stream.unshift(data)
          resolve()
        })
        .on('error', reject)
        .on('end', () => {
          if (html) {
            try {
              mkdirp.sync(path.dirname(distPath), {fs: mfs})
              mfs.writeFileSync(distPath, html)
            } catch (e) {
              console.error(e)
            }

            debug(`static html file "${distPath}" is generated!`)
          }
          debug(`whole request: ${Date.now() - start}ms`)
        })

      generateStatic && stream.on('data', data => (html += data))
    })

    ctx.body = stream.resume()
  } catch (e) {
    if (e.status === 404) {
      ctx.body = '404 | Page Not Found'
    } else {
      ctx.status = 500
      ctx.body = '500 | Internal Server Error'
      console.error(`error during render : ${url}`)
      console.error(e.stack)
    }
  }
})

// https://github.com/vuejs/vue/blob/dev/packages/vue-server-renderer/README.md#why-use-bundlerenderer
const createRenderer = (bundle, options) => require('vue-server-renderer').createBundleRenderer(bundle, {
  ...options,
  template,
  inject: false,
  cache: lruCache({
    max: 1000,
    maxAge: 1000 * 60 * 15
  }),
  basedir: paths.dist(),
  runInNewContext: false
})

if (__DEV__) {
  readyPromise = require('./dev-tools').default(app, (bundle, {clientManifest, fs}) => {
    renderer = createRenderer(bundle, {clientManifest})
    mfs = fs
  })
} else {
  mfs = fs
  renderer = createRenderer(require(paths.dist('vue-ssr-server-bundle.json')), {
    clientManifest: require(paths.dist('vue-ssr-client-manifest.json'))
  })
  app.use(require('koa-static')('dist'))
}

const {serverHost, serverPort} = config

const args = [serverPort, serverHost]

app.listen(...args, err =>
  debug(...err ? [err] : ['Server is now running at %s:%s.', ...args.reverse()]))
<|endoftext|>


<commit_before>
/**
 * Module dependencies
 */

var
	mongoose = require('mongoose'),
	Schema = mongoose.Schema,
	util = require("util"),
	async = require('async');

/**
 * Layer schema
 */

var LayerSchema = new Schema({
	title: { type: String, required: true },
	description: String,
	creator: {type: Schema.ObjectId, ref: 'User'},
	maps: [{type: Schema.ObjectId, ref: 'Map'}],
	createdAt: {type: Date, default: Date.now},
	updateAt: {type: Date, default: Date.now},
	visibility: { type: String, enum: ['Public', 'Visible', 'Private'], default: 'Private'},
	type: { type: String, enum: ['FeatureLayer', 'TileLayer'], default: 'FeatureLayer'},

	// Content Layer Attributes
	contributors: [{type: Schema.ObjectId, ref: 'User'}],
	features: [{type: Schema.ObjectId, ref: 'Feature'}],
	contents: [{type: Schema.ObjectId, ref: 'Content'}],
	isDraft: {type: Boolean, default: true},
	oldId: Number,

	// Tile Layer Attributes
	url: String,
	properties: {}

});

/**
 * Hooks
 */

LayerSchema.pre('remove', function(next) {
	var self = this;

	async.each( self.maps,
		function(mapId, done){
			mongoose.model('Map').findById(mapId, function(err, map){
				map.removeLayerAndSave(self, done);
			})
		}, next);
});

/**
 * Methods
 */

LayerSchema.methods = {
	removeMapAndSave: function(map, done){
		var self = this;

		self.maps.pull({ _id: map._id });

		self.save(done);
	}
}

/**
 * Statics
 */

LayerSchema.statics = {

	load: function (id, doneLoading) {
		this.findOne({ _id : id })
			.populate('creator', 'name username email')
			.populate('contributors', 'name username email')
			.populate('features')
			.populate('features.creator')
			.populate('contents')
			.exec(function(err, layer){
				var features = []
				async.each(layer.features, function(feature, cb){
					console.log(feature);
					feature.populate('creator', function(err, feature){
						features.push(feature);
						cb();
					})
				}, function(err){
					layer.features = features;
					doneLoading(err, layer);
				});
			})
	},

	list: function (options, cb) {
		var criteria = options.criteria || {}

		this
			.find(criteria)
			.populate('creator', 'name username email')
			.sort({'createdAt': -1}) // sort by date
			.limit(options.perPage)
			.skip(options.perPage * options.page)
		.exec(cb)
	}

}

mongoose.model('Layer', LayerSchema)
<commit_msg>remove console.log<commit_after>
/**
 * Module dependencies
 */

var
	mongoose = require('mongoose'),
	Schema = mongoose.Schema,
	util = require("util"),
	async = require('async');

/**
 * Layer schema
 */

var LayerSchema = new Schema({
	title: { type: String, required: true },
	description: String,
	creator: {type: Schema.ObjectId, ref: 'User'},
	maps: [{type: Schema.ObjectId, ref: 'Map'}],
	createdAt: {type: Date, default: Date.now},
	updateAt: {type: Date, default: Date.now},
	visibility: { type: String, enum: ['Public', 'Visible', 'Private'], default: 'Private'},
	type: { type: String, enum: ['FeatureLayer', 'TileLayer'], default: 'FeatureLayer'},

	// Content Layer Attributes
	contributors: [{type: Schema.ObjectId, ref: 'User'}],
	features: [{type: Schema.ObjectId, ref: 'Feature'}],
	contents: [{type: Schema.ObjectId, ref: 'Content'}],
	isDraft: {type: Boolean, default: true},
	oldId: Number,

	// Tile Layer Attributes
	url: String,
	properties: {}

});

/**
 * Hooks
 */

LayerSchema.pre('remove', function(next) {
	var self = this;

	async.each( self.maps,
		function(mapId, done){
			mongoose.model('Map').findById(mapId, function(err, map){
				map.removeLayerAndSave(self, done);
			})
		}, next);
});

/**
 * Methods
 */

LayerSchema.methods = {
	removeMapAndSave: function(map, done){
		var self = this;

		self.maps.pull({ _id: map._id });

		self.save(done);
	}
}

/**
 * Statics
 */

LayerSchema.statics = {

	load: function (id, doneLoading) {
		this.findOne({ _id : id })
			.populate('creator', 'name username email')
			.populate('contributors', 'name username email')
			.populate('features')
			.populate('features.creator')
			.populate('contents')
			.exec(function(err, layer){
				var features = []
				async.each(layer.features, function(feature, cb){
					feature.populate('creator', function(err, feature){
						features.push(feature);
						cb();
					})
				}, function(err){
					layer.features = features;
					doneLoading(err, layer);
				});
			})
	},

	list: function (options, cb) {
		var criteria = options.criteria || {}

		this
			.find(criteria)
			.populate('creator', 'name username email')
			.sort({'createdAt': -1}) // sort by date
			.limit(options.perPage)
			.skip(options.perPage * options.page)
		.exec(cb)
	}

}

mongoose.model('Layer', LayerSchema)
<|endoftext|>


<commit_before>var test = require('tape');
var markdown = require('../js/markdown');
test("verify inline component blocks make it into lexer",
  function(t) {
    t.plan(2);
    var md = '!![foobar]';
    var tokens = markdown.lexer(md);
    t.equal(
      tokens[0]['type'], 'component_block',
      'adds a component type to the lexer'
    );
    t.equal(
      tokens[0]['slug'], 'foobar',
      'the correct slug gets into the lexer'
    );
  }
);
test("verify parser handles component type in lexer",
  function(t) {
    t.plan(1);
    var md = '!![barfoo]';
    var html = markdown.toHTML(md);
    t.equal(
      html, 'barfoo',
      'the proper component is rendered'
    );
  }
);

<commit_msg>added t.end<commit_after>var test = require('tape');
var markdown = require('../js/markdown');
test("verify inline component blocks make it into lexer",
  function(t) {
    t.plan(2);
    var md = '!![foobar]';
    var tokens = markdown.lexer(md);
    t.equal(
      tokens[0]['type'], 'component_block',
      'adds a component type to the lexer'
    );
    t.equal(
      tokens[0]['slug'], 'foobar',
      'the correct slug gets into the lexer'
    );
    t.end();
  }
);
test("verify parser handles component type in lexer",
  function(t) {
    t.plan(1);
    var md = '!![barfoo]';
    var html = markdown.toHTML(md);
    t.equal(
      html, 'barfoo',
      'the proper component is rendered'
    );
    t.end();
  }
);

<|endoftext|>


<commit_before>/*jshint node:true, indent:2, curly:false, eqeqeq:true, immed:true, latedef:true, newcap:true, noarg:true,
regexp:true, undef:true, strict:true, trailing:true, white:true */
/*global X:true, XM:true, XT:true, _:true */

(function () {
  "use strict";

  /**
    Returns a list of extensions associated with an organization.

    @extends X.Route
    @class
   */
  X.Functor.create({
    handle: function (xtr, session, callback) {
      var organizationName = session.get("details").organization,
        organization = new XM.Organization(),
        fetchError = function (err) {
          xtr.error({isError: true, reason: "Error fetching organization"});
        },
        fetchSuccess = function (model, result) {
          var extensions = _.map(model.get("extensions").models, function (ext) {
            return {
              name: ext.getValue("extension.name"),
              location: ext.getValue("extension.location"),
              privilegeName: ext.getValue("extension.privilegeName")
            };
          });

          xtr.write({data: extensions}).close();
        };

      // Fetch the organization to get their extensions
      organization.fetch({
        id: organizationName,
        success: fetchSuccess,
        error: fetchError,
        username: X.options.globalDatabase.nodeUsername
      });

    },
    handles: "function/extensions",
    needsSession: true
  });
}());
<commit_msg>issue #18575: passing load order through for extensions<commit_after>/*jshint node:true, indent:2, curly:false, eqeqeq:true, immed:true, latedef:true, newcap:true, noarg:true,
regexp:true, undef:true, strict:true, trailing:true, white:true */
/*global X:true, XM:true, XT:true, _:true */

(function () {
  "use strict";

  /**
    Returns a list of extensions associated with an organization.

    @extends X.Route
    @class
   */
  X.Functor.create({
    handle: function (xtr, session, callback) {
      var organizationName = session.get("details").organization,
        organization = new XM.Organization(),
        fetchError = function (err) {
          xtr.error({isError: true, reason: "Error fetching organization"});
        },
        fetchSuccess = function (model, result) {
          var extensions = _.map(model.get("extensions").models, function (orgext) {
            var ext = orgext.get("extension");
            return {
              name: ext.get("name"),
              location: ext.get("location"),
              loadOrder: ext.get("loadOrder"),
              privilegeName: ext.get("privilegeName")
            };
          });

          xtr.write({data: extensions}).close();
        };

      // Fetch the organization to get their extensions
      organization.fetch({
        id: organizationName,
        success: fetchSuccess,
        error: fetchError,
        username: X.options.globalDatabase.nodeUsername
      });

    },
    handles: "function/extensions",
    needsSession: true
  });
}());
<|endoftext|>


<commit_before>
// The schedule object saves the times at which each source bundle should be updated
// Documentation on how to write crontab: http://crontab.org/

const schedules = [
  // {
  //   source: 'elmundo',
  //   hourFreq: '*',
  //   timeZone: 'America/Los_Angeles'
  // },
  // {
  //   source: 'hackernews',
  //   hourFreq: '*/2',
  //   timeZone: 'America/Los_Angeles'
  // },
  // {
  //   source: 'newyorktimes',
  //   hourFreq: '*/6',
  //   timeZone: 'America/Los_Angeles'
  // },
  {
    source: 'indiehackers',
    hourFreq: '*/3',
    timeZone: 'America/Los_Angeles'
  },
  {
    source: 'askhackernews',
    hourFreq: '*',
    timeZone: 'America/Los_Angeles'
  },
  {
    source: 'hackernews',
    hourFreq: '*',
    timeZone: 'America/Los_Angeles'
  }
]

export default schedules;
<commit_msg>Cut indiehackers parser | Add hackernews parser<commit_after>
// The schedule object saves the times at which each source bundle should be updated
// Documentation on how to write crontab: http://crontab.org/

const schedules = [
  // {
  //   source: 'elmundo',
  //   hourFreq: '*',
  //   timeZone: 'America/Los_Angeles'
  // },
  // {
  //   source: 'hackernews',
  //   hourFreq: '*/2',
  //   timeZone: 'America/Los_Angeles'
  // },
  // {
  //   source: 'newyorktimes',
  //   hourFreq: '*/6',
  //   timeZone: 'America/Los_Angeles'
  // },
  // {
  //   source: 'indiehackers',
  //   hourFreq: '*/3',
  //   timeZone: 'America/Los_Angeles'
  // },
  {
    source: 'askhackernews',
    hourFreq: '*',
    timeZone: 'America/Los_Angeles'
  },
  {
    source: 'hackernews',
    hourFreq: '*',
    timeZone: 'America/Los_Angeles'
  }
]

export default schedules;
<|endoftext|>


<commit_before>module.exports = {
  "env": {
    "browser": true,
    "es6": true,
    "jquery": true,
    "node": true
  },
  "globals": {
    "assert": false,
    "Electron": false,
    "Mithril": false,
    "Vue": false,
    "Bse": false,
    "Shell": false,
    "_": false,
    "MAXINT": false,
    "MAXUINT": false,
    "module": true /* allow mods */
  },
  "rules": {
    "no-unused-vars": [ "warn", { "args": "none", "argsIgnorePattern": "^__.*", "varsIgnorePattern": "^__.*" } ],
    "no-unreachable": [ "warn" ],
    "semi": [ "error", "always" ],
    "no-extra-semi": [ "warn" ],
    "no-console": [ "off" ],
    "no-constant-condition": [ "warn" ],
    "indent": [ "off", 2 ],
    "linebreak-style": [ "error", "unix" ],
    "no-mixed-spaces-and-tabs": [ "off" ],
    "quotes": [ "off", "single" ]
  },
  "plugins": [ "html" ],
  "extends": "eslint:recommended"
};
<commit_msg>EBEAST: .eslintrc.js: disable overzealous linting rules<commit_after>module.exports = {
  "env": {
    "browser": true,
    "es6": true,
    "jquery": true,
    "node": true
  },
  "globals": {
    "assert": false,
    "Electron": false,
    "Mithril": false,
    "Vue": false,
    "Bse": false,
    "Shell": false,
    "_": false,
    "MAXINT": false,
    "MAXUINT": false,
    "module": true /* allow mods */
  },
  "rules": {
    "no-unused-vars": [ "warn", { "args": "none", "argsIgnorePattern": "^__.*", "varsIgnorePattern": "^__.*" } ],
    "no-unreachable": [ "warn" ],
    "semi": [ "error", "always" ],
    "no-extra-semi": [ "warn" ],
    "no-console": [ "off" ],
    "no-constant-condition": [ "warn" ],
    "indent": [ "off", 2 ],
    "linebreak-style": [ "error", "unix" ],
    "no-mixed-spaces-and-tabs": [ "off" ],
    'no-useless-escape': 'warn',
    'vue/multiline-html-element-content-newline': 'off',
    'vue/html-closing-bracket-spacing': 'off',
    'vue/html-self-closing': 'off',
    'vue/max-attributes-per-line': 'off',
    'vue/html-indent': 'off',
    'vue/html-closing-bracket-newline': 'off',
    'vue/no-multi-spaces': 'off',
    'vue/singleline-html-element-content-newline': 'off',
    'vue/html-quotes': 'off',
    'no-irregular-whitespace': 'off', /* ["error", { 'skipStrings': true, 'skipComments': true, 'skipTemplates': true, 'skipRegExps':true } ], */
    "quotes": [ "off", "single" ]
  },
  "plugins": [ "html" ],
  "extends": [ "eslint:recommended", "plugin:vue/recommended" ]
};
<|endoftext|>


<commit_before>import GenericResolver from 'api/resolver/generic/genericResolver'
import {ObjectId} from 'mongodb'
import Hook from 'util/hook'
import Util from 'api/util'
import {getHostFromHeaders} from 'util/host'
import Cache from 'util/cache'
import {
    CAPABILITY_MANAGE_KEYVALUES
} from 'util/capabilities'
import phantom from 'phantom'

const UtilCms = {
    getCmsPage: async ({db, context, slug, editmode, _version, headers}) => {
        const host = getHostFromHeaders(headers)

        const cacheKey = 'cmsPage-' + _version + '-' + slug + (host ? '-' + host : '')

        let cmsPages
        if (!editmode) {
            cmsPages = Cache.get(cacheKey)
        }
        if (!cmsPages) {

            let match, hostRule

            const ors = []

            if (host) {
                hostRule = {$regex: `(^|;)${host.replace(/\./g, '\\.')}=${slug}($|;)`, $options: 'i'}
                ors.push({hostRule})
            }

            let tmpSlug = slug
            ors.push({slug})

            if (!Util.isUserLoggedIn(context)) {
                // if no user only match public entries
                match = {$and: [{$or: ors}, {public: true}]}
            } else {
                match = {$or: ors}
            }
            cmsPages = await GenericResolver.entities(db, context, 'CmsPage', ['slug', 'name', 'template', 'script', 'dataResolver', 'resources', 'ssr', 'public', 'urlSensitiv'], {
                match,
                limit: 1,
                _version
            })

            // minify template if no user is logged in
            if (cmsPages.results && cmsPages.results.length) {

                if (!editmode) {
                    const template = JSON.parse(cmsPages.results[0].template)

                    // TODO: Include sub CMS component to reduce number of requests
                    //console.log(template)

                    try {
                        cmsPages.results[0].template = JSON.stringify(template, null, 0)
                    } catch (e) {
                    }
                }
            }
            Cache.set(cacheKey, cmsPages, 600000) // cache expires in 10 min
        }
        return cmsPages
    },
    resolveData: async (db, context, dataResolver, scope, nosession) => {
        const resolvedData = {_meta: {}}, subscriptions = []

        if (dataResolver) {
            let debugInfo = null
            try {
                let segments = JSON.parse(dataResolver)
                if (segments.constructor === Object) segments = [segments]

                for (let i = 0; i < segments.length; i++) {

                    debugInfo = ''

                    let tempPhantom
                    if (segments[i].phantom) {
                        // exclude pipline from replacements
                        tempPhantom = segments[i].phantom.pipeline
                        segments[i].phantom.pipeline = null
                    }
                    const tpl = new Function(`const {${Object.keys(scope).join(',')}} = this.scope
                                              const {data} = this
                                              return \`${JSON.stringify(segments[i])}\``)

                    const replacedSegmentStr = tpl.call({scope, data: resolvedData})
                    const segment = JSON.parse(replacedSegmentStr)

                    if (tempPhantom) {
                        segment.phantom.pipeline = tempPhantom
                    }

                    if (segment._data) {
                        resolvedData._data = segment._data
                    } else if (segment.data) {
                        Object.keys(segment.data).forEach(k => {
                            resolvedData[k] = segment.data[k]
                        })
                    } else if (segment.t) {
                        const {t, f, l, o, p, d, s, cache, includeCount} = segment
                        /*
                         f = filter for the query
                         t = type
                         s = sort
                         d = the data / fields you want to access
                         l = limit of results
                         o = offset
                         p = page (if no offset is defined, offset is limit * (page -1) )

                         cache = defines cache policy
                         includeCount = whether to return the total number of results
                         */
                        let fields
                        if (d && d.constructor === String) {
                            try {
                                fields = Function(`const {${Object.keys(scope).join(',')}} = this.scope;const {data} = this;return ${d}`).bind({
                                    scope,
                                    data: resolvedData
                                })()
                            } catch (e) {
                                if (!segment.ignoreError)
                                    throw e
                            }
                        } else {
                            fields = d
                        }

                        let type, match
                        if (t.indexOf('$') === 0) {
                            type = t.substring(1)
                            subscriptions.push(type)
                        } else {
                            type = t
                        }

                        // restriction = if it is set to 'user' only entries that belongs to the user are returned
                        if (segment.restriction && segment.restriction === 'user') {
                            match = {createdBy: ObjectId(context.id)}
                        } else {
                            match = {}
                        }
                        debugInfo += ' type=' + type
                        const result = await GenericResolver.entities(db, context, type, fields, {
                            filter: f,
                            limit: l,
                            page: p,
                            sort: s,
                            offset: o,
                            match,
                            cache,
                            includeCount,
                            projectResult: true
                        })

                        debugInfo += ' result=true'

                        resolvedData[segment.key || type] = result
                    } else if (segment.tr) {
                        resolvedData.tr = segment.tr[context.lang]
                    } else if (segment.eval) {
                        debugInfo += ' in eval'
                        try {
                            const tpl = new Function('const {' + Object.keys(scope).join(',') + '} = this.scope; const {data} = this;' + segment.eval)
                            tpl.call({data: resolvedData, scope, context})
                        } catch (e) {
                            if (!segment.ignoreError)
                                throw e
                        }
                    } else if (segment.subscription) {
                        if (segment.subscription.constructor === String) {
                            subscriptions.push(segment.subscription)
                        } else {
                            subscriptions.push(JSON.stringify(segment.subscription))
                        }
                    } else if (segment.system) {
                        const system = Util.systemProperties()
                        resolvedData._meta.system = segment.key || 'system'
                        resolvedData[resolvedData._meta.system] = system
                    } else if (segment.keyValueGlobals) {
                        const match = {key: {$in: segment.keyValueGlobals}}

                        // if user don't have capability to manage keys he can only see the public ones
                        if (!await Util.userHasCapability(db, context, CAPABILITY_MANAGE_KEYVALUES)) {
                            match.ispublic = true
                        }

                        const result = await GenericResolver.entities(db, context, 'KeyValueGlobal', ['key', 'value'], {
                            match
                        })
                        const map = {}
                        if (result.results) {
                            result.results.map(entry => {
                                console.log(entry)
                                try {
                                    map[entry.key] = JSON.parse(entry.value)
                                } catch (e) {
                                    map[entry.key] = entry.value
                                }
                            })
                        }
                        resolvedData._meta.keyValueGlobalKey = segment.key || 'keyValueGlobals'
                        resolvedData[resolvedData._meta.keyValueGlobalKey] = map
                    } else if (segment.keyValues) {

                        const map = {}

                        if (Util.isUserLoggedIn(context)) {
                            const match = {createdBy: ObjectId(context.id), key: {$in: segment.keyValues}}
                            const result = await GenericResolver.entities(db, context, 'KeyValue', ['key', 'value'], {
                                match
                            })

                            if (result.results) {
                                result.results.map(entry => {
                                    try {
                                        map[entry.key] = JSON.parse(entry.value)
                                    } catch (e) {
                                        map[entry.key] = entry.value
                                    }
                                })
                            }
                        } else if (nosession) {
                            let nosessionJson
                            try {
                                nosessionJson = JSON.parse(nosession)
                            } catch (e) {
                                nosessionJson = {}
                            }
                            segment.keyValues.forEach(key => {
                                if (nosessionJson[key]) {
                                    try {
                                        map[key] = JSON.parse(nosessionJson[key])
                                    } catch (e) {
                                        map[key] = nosessionJson[key]
                                    }
                                }
                            })
                        }

                        resolvedData._meta.keyValueKey = segment.key || 'keyValues'
                        resolvedData[resolvedData._meta.keyValueKey] = map

                    } else if (segment.phantom) {

                        if (segment.phantom.if && segment.phantom.if !== 'true') {
                            continue
                        }

                        const {url, pipeline} = segment.phantom

                        const instance = await phantom.create(['--ignore-ssl-errors=yes', '--load-images=no'], {
                            logLevel: 'error', viewportSize: {width: 1600, height: 900},
                            settings: {
                                userAgent: 'Mozilla/5.0 (X11; Linux x86_64; rv:49.0) Gecko/20100101 Firefox/49.0',
                                javascriptEnabled: 'true',
                                loadImages: 'false'
                            }
                        })
                        const page = await instance.createPage();

                        await page.on('onResourceRequested', function (requestData) {
                            //console.info('Requesting', requestData.url)
                        })
                        await page.on('onLoadStarted', function () {
                            //console.info('started')
                        })
                        await page.on('onLoadFinished', function () {
                            //console.info('finshed')
                        })
                        await page.on('onNavigationRequested', function (targetUrl) {
                            console.info('onNavigationRequested', targetUrl)
                        })

                        await page.on('onError', function (msg, trace) {
                            console.error(msg, trace)
                        })

                        await page.on('onConsoleMessage', function (msg, lineNum, sourceId) {
                            console.log('CONSOLE: ' + msg + ' (from line #' + lineNum + ' in "' + sourceId + '")');
                        })

                        /*await page.on('onResourceRequested', function(requestData) { console.info('Requesting', requestData.url); });*/
                        const status = await page.open(url)
                        let data = {}
                        if (pipeline) {

                            const evalFunc = (evalData) => {
                                let evalStr
                                if (evalData.constructor === Array) {
                                    evalStr = evalData.join('\n')
                                } else {
                                    evalStr = evalData
                                }
                                return page.evaluate(function (evalStr) {
                                    const tpl = new Function(evalStr)
                                    return tpl.call({})
                                }, evalStr)

                            }

                            for (const pipeObj of pipeline) {

                                const tpl = new Function('const {' + Object.keys(scope).join(',') + '} = this.scope;const {data} = this; return `' + JSON.stringify(pipeObj) + '`;')
                                const pipeReplaceStr = tpl.call({scope, data: resolvedData})
                                const pipe = JSON.parse(pipeReplaceStr)

                                if (pipe.waitFor) {
                                    const startTime = new Date()
                                    const timeout = pipe.waitFor.timeout || 10000
                                    let isValid = false
                                    while (timeout > (new Date() - startTime)) {
                                        const tmpData = await evalFunc(pipe.waitFor.eval)
                                        if (tmpData) {
                                            isValid = true
                                            break
                                        }
                                        await Util.sleep(50)
                                    }
                                    if (!isValid) {
                                        break
                                    }

                                } else if (pipe.eval) {
                                    const tmpData = await evalFunc(pipe.eval)
                                    if (tmpData) {
                                        data = {...data, ...tmpData}
                                    }
                                } else if (pipe.open) {
                                    await page.open(pipe.open)
                                } else if (pipe.fetch) {

                                    let headers = ''

                                    if (pipe.fetch.headers) {

                                        Object.entries(pipe.fetch.headers).forEach(header => {
                                            headers += 'req.setRequestHeader(\'' + header[0] + '\', \'' + header[1] + '\')\n'
                                        })
                                    }
                                    const tmpData = await evalFunc(`const req = new XMLHttpRequest()
                                    req.open('${pipe.fetch.methode || 'post'}', '${pipe.fetch.url}', false)
                                    req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded')
                                    ${headers}

                                    req.send('${pipe.fetch.data}')
                                    return req`)

                                    if (tmpData) {
                                        data = {...data, [pipe.fetch.key || 'fetchResult']: tmpData}
                                    }

                                }
                                resolvedData[segment.key || 'phantom'] = {eval: data, debug: 'debug infos'}
                            }
                        }

                        await instance.exit()

                    } else {
                        console.log('call cmsCustomResolver', segment)
                        Hook.call('cmsCustomResolver', {resolvedData, resolver: segment})
                    }

                }
                delete resolvedData._data
            } catch (e) {
                resolvedData.error = e.message + ' -> scope=' + JSON.stringify(scope) + debugInfo
            }
        }
        return {resolvedData, subscriptions}
    }
}

export default UtilCms<commit_msg>Small improvements<commit_after>import GenericResolver from 'api/resolver/generic/genericResolver'
import {ObjectId} from 'mongodb'
import Hook from 'util/hook'
import Util from 'api/util'
import {getHostFromHeaders} from 'util/host'
import Cache from 'util/cache'
import {
    CAPABILITY_MANAGE_KEYVALUES
} from 'util/capabilities'
import phantom from 'phantom'

const UtilCms = {
    getCmsPage: async ({db, context, slug, editmode, _version, headers}) => {
        const host = getHostFromHeaders(headers)

        const cacheKey = 'cmsPage-' + _version + '-' + slug + (host ? '-' + host : '')

        let cmsPages
        if (!editmode) {
            cmsPages = Cache.get(cacheKey)
        }
        if (!cmsPages) {

            let match, hostRule

            const ors = []

            if (host) {
                hostRule = {$regex: `(^|;)${host.replace(/\./g, '\\.')}=${slug}($|;)`, $options: 'i'}
                ors.push({hostRule})
            }

            let tmpSlug = slug
            ors.push({slug})

            if (!Util.isUserLoggedIn(context)) {
                // if no user only match public entries
                match = {$and: [{$or: ors}, {public: true}]}
            } else {
                match = {$or: ors}
            }
            console.log(match)
            cmsPages = await GenericResolver.entities(db, context, 'CmsPage', ['slug', 'name', 'template', 'script', 'dataResolver', 'resources', 'ssr', 'public', 'urlSensitiv'], {
                match,
                limit: 1,
                _version
            })

            // minify template if no user is logged in
            if (cmsPages.results && cmsPages.results.length) {

                if (!editmode) {

                    // TODO: Include sub CMS component to reduce number of requests
                    //console.log(template)

                    try {
                        const template = JSON.parse(cmsPages.results[0].template)
                        cmsPages.results[0].template = JSON.stringify(template, null, 0)
                    } catch (e) {
                    }
                }
            }
            Cache.set(cacheKey, cmsPages, 600000) // cache expires in 10 min
        }
        return cmsPages
    },
    resolveData: async (db, context, dataResolver, scope, nosession) => {
        const resolvedData = {_meta: {}}, subscriptions = []

        if (dataResolver) {
            let debugInfo = null
            try {
                let segments = JSON.parse(dataResolver)
                if (segments.constructor === Object) segments = [segments]

                for (let i = 0; i < segments.length; i++) {

                    debugInfo = ''

                    let tempPhantom
                    if (segments[i].phantom) {
                        // exclude pipline from replacements
                        tempPhantom = segments[i].phantom.pipeline
                        segments[i].phantom.pipeline = null
                    }
                    const tpl = new Function(`const {${Object.keys(scope).join(',')}} = this.scope
                                              const {data} = this
                                              return \`${JSON.stringify(segments[i])}\``)

                    const replacedSegmentStr = tpl.call({scope, data: resolvedData})
                    const segment = JSON.parse(replacedSegmentStr)

                    if (tempPhantom) {
                        segment.phantom.pipeline = tempPhantom
                    }

                    if (segment._data) {
                        resolvedData._data = segment._data
                    } else if (segment.data) {
                        Object.keys(segment.data).forEach(k => {
                            resolvedData[k] = segment.data[k]
                        })
                    } else if (segment.t) {
                        const {t, f, l, o, p, d, s, cache, includeCount} = segment
                        /*
                         f = filter for the query
                         t = type
                         s = sort
                         d = the data / fields you want to access
                         l = limit of results
                         o = offset
                         p = page (if no offset is defined, offset is limit * (page -1) )

                         cache = defines cache policy
                         includeCount = whether to return the total number of results
                         */
                        let fields
                        if (d && d.constructor === String) {
                            try {
                                fields = Function(`const {${Object.keys(scope).join(',')}} = this.scope;const {data} = this;return ${d}`).bind({
                                    scope,
                                    data: resolvedData
                                })()
                            } catch (e) {
                                if (!segment.ignoreError)
                                    throw e
                            }
                        } else {
                            fields = d
                        }

                        let type, match
                        if (t.indexOf('$') === 0) {
                            type = t.substring(1)
                            subscriptions.push(type)
                        } else {
                            type = t
                        }

                        // restriction = if it is set to 'user' only entries that belongs to the user are returned
                        if (segment.restriction && segment.restriction === 'user') {
                            match = {createdBy: ObjectId(context.id)}
                        } else {
                            match = {}
                        }
                        debugInfo += ' type=' + type
                        const result = await GenericResolver.entities(db, context, type, fields, {
                            filter: f,
                            limit: l,
                            page: p,
                            sort: s,
                            offset: o,
                            match,
                            cache,
                            includeCount,
                            projectResult: true
                        })

                        debugInfo += ' result=true'

                        resolvedData[segment.key || type] = result
                    } else if (segment.tr) {
                        resolvedData.tr = segment.tr[context.lang]
                    } else if (segment.eval) {
                        debugInfo += ' in eval'
                        try {
                            const tpl = new Function('const {' + Object.keys(scope).join(',') + '} = this.scope; const {data} = this;' + segment.eval)
                            tpl.call({data: resolvedData, scope, context})
                        } catch (e) {
                            if (!segment.ignoreError)
                                throw e
                        }
                    } else if (segment.subscription) {
                        if (segment.subscription.constructor === String) {
                            subscriptions.push(segment.subscription)
                        } else {
                            subscriptions.push(JSON.stringify(segment.subscription))
                        }
                    } else if (segment.system) {
                        const system = Util.systemProperties()
                        resolvedData._meta.system = segment.key || 'system'
                        resolvedData[resolvedData._meta.system] = system
                    } else if (segment.keyValueGlobals) {
                        const match = {key: {$in: segment.keyValueGlobals}}

                        // if user don't have capability to manage keys he can only see the public ones
                        if (!await Util.userHasCapability(db, context, CAPABILITY_MANAGE_KEYVALUES)) {
                            match.ispublic = true
                        }

                        const result = await GenericResolver.entities(db, context, 'KeyValueGlobal', ['key', 'value'], {
                            match
                        })
                        const map = {}
                        if (result.results) {
                            result.results.map(entry => {
                                console.log(entry)
                                try {
                                    map[entry.key] = JSON.parse(entry.value)
                                } catch (e) {
                                    map[entry.key] = entry.value
                                }
                            })
                        }
                        resolvedData._meta.keyValueGlobalKey = segment.key || 'keyValueGlobals'
                        resolvedData[resolvedData._meta.keyValueGlobalKey] = map
                    } else if (segment.keyValues) {

                        const map = {}

                        if (Util.isUserLoggedIn(context)) {
                            const match = {createdBy: ObjectId(context.id), key: {$in: segment.keyValues}}
                            const result = await GenericResolver.entities(db, context, 'KeyValue', ['key', 'value'], {
                                match
                            })

                            if (result.results) {
                                result.results.map(entry => {
                                    try {
                                        map[entry.key] = JSON.parse(entry.value)
                                    } catch (e) {
                                        map[entry.key] = entry.value
                                    }
                                })
                            }
                        } else if (nosession) {
                            let nosessionJson
                            try {
                                nosessionJson = JSON.parse(nosession)
                            } catch (e) {
                                nosessionJson = {}
                            }
                            segment.keyValues.forEach(key => {
                                if (nosessionJson[key]) {
                                    try {
                                        map[key] = JSON.parse(nosessionJson[key])
                                    } catch (e) {
                                        map[key] = nosessionJson[key]
                                    }
                                }
                            })
                        }

                        resolvedData._meta.keyValueKey = segment.key || 'keyValues'
                        resolvedData[resolvedData._meta.keyValueKey] = map

                    } else if (segment.phantom) {

                        if (segment.phantom.if && segment.phantom.if !== 'true') {
                            continue
                        }

                        const {url, pipeline} = segment.phantom

                        const instance = await phantom.create(['--ignore-ssl-errors=yes', '--load-images=no'], {
                            logLevel: 'error', viewportSize: {width: 1600, height: 900},
                            settings: {
                                userAgent: 'Mozilla/5.0 (X11; Linux x86_64; rv:49.0) Gecko/20100101 Firefox/49.0',
                                javascriptEnabled: 'true',
                                loadImages: 'false'
                            }
                        })
                        const page = await instance.createPage();

                        await page.on('onResourceRequested', function (requestData) {
                            //console.info('Requesting', requestData.url)
                        })
                        await page.on('onLoadStarted', function () {
                            //console.info('started')
                        })
                        await page.on('onLoadFinished', function () {
                            //console.info('finshed')
                        })
                        await page.on('onNavigationRequested', function (targetUrl) {
                            console.info('onNavigationRequested', targetUrl)
                        })

                        await page.on('onError', function (msg, trace) {
                            console.error(msg, trace)
                        })

                        await page.on('onConsoleMessage', function (msg, lineNum, sourceId) {
                            console.log('CONSOLE: ' + msg + ' (from line #' + lineNum + ' in "' + sourceId + '")');
                        })

                        /*await page.on('onResourceRequested', function(requestData) { console.info('Requesting', requestData.url); });*/
                        const status = await page.open(url)
                        let data = {}
                        if (pipeline) {

                            const evalFunc = (evalData) => {
                                let evalStr
                                if (evalData.constructor === Array) {
                                    evalStr = evalData.join('\n')
                                } else {
                                    evalStr = evalData
                                }
                                return page.evaluate(function (evalStr) {
                                    const tpl = new Function(evalStr)
                                    return tpl.call({})
                                }, evalStr)

                            }

                            for (const pipeObj of pipeline) {

                                const tpl = new Function('const {' + Object.keys(scope).join(',') + '} = this.scope;const {data} = this; return `' + JSON.stringify(pipeObj) + '`;')
                                const pipeReplaceStr = tpl.call({scope, data: resolvedData})
                                const pipe = JSON.parse(pipeReplaceStr)

                                if (pipe.waitFor) {
                                    const startTime = new Date()
                                    const timeout = pipe.waitFor.timeout || 10000
                                    let isValid = false
                                    while (timeout > (new Date() - startTime)) {
                                        const tmpData = await evalFunc(pipe.waitFor.eval)
                                        if (tmpData) {
                                            isValid = true
                                            break
                                        }
                                        await Util.sleep(50)
                                    }
                                    if (!isValid) {
                                        break
                                    }

                                } else if (pipe.eval) {
                                    const tmpData = await evalFunc(pipe.eval)
                                    if (tmpData) {
                                        data = {...data, ...tmpData}
                                    }
                                } else if (pipe.open) {
                                    await page.open(pipe.open)
                                } else if (pipe.fetch) {

                                    let headers = ''

                                    if (pipe.fetch.headers) {

                                        Object.entries(pipe.fetch.headers).forEach(header => {
                                            headers += 'req.setRequestHeader(\'' + header[0] + '\', \'' + header[1] + '\')\n'
                                        })
                                    }
                                    const tmpData = await evalFunc(`const req = new XMLHttpRequest()
                                    req.open('${pipe.fetch.methode || 'post'}', '${pipe.fetch.url}', false)
                                    req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded')
                                    ${headers}

                                    req.send('${pipe.fetch.data}')
                                    return req`)

                                    if (tmpData) {
                                        data = {...data, [pipe.fetch.key || 'fetchResult']: tmpData}
                                    }

                                }
                                resolvedData[segment.key || 'phantom'] = {eval: data, debug: 'debug infos'}
                            }
                        }

                        await instance.exit()

                    } else {
                        console.log('call cmsCustomResolver', segment)
                        Hook.call('cmsCustomResolver', {resolvedData, resolver: segment})
                    }

                }
                delete resolvedData._data
            } catch (e) {
                resolvedData.error = e.message + ' -> scope=' + JSON.stringify(scope) + debugInfo
            }
        }
        return {resolvedData, subscriptions}
    }
}

export default UtilCms<|endoftext|>


<commit_before>describe('mwTextCollapsable', function () {
  var $compile;
  var $rootScope;
  var scope;

  beforeEach(module('karmaDirectiveTemplates'));

  beforeEach(module('mwUI.UiComponents'));

  //mock i18n filter
  beforeEach(function(){
    module(function($provide){
      $provide.value('i18nFilter', function(){
        return function(input){
          return input;
        };
      });
    });
  });

  beforeEach(inject(function (_$compile_, _$rootScope_) {
    $compile = _$compile_;
    $rootScope = _$rootScope_;
    scope = _$rootScope_.$new();
  }));

  var longText = 'long text long text long text long text long text ' +
    'long text long text long text long text long text long text long text ' +
    'long text long text long text long text long text long text long text ' +
    'long text long text long text long text long text long text long text ' +
    'long text long text long text long text long text long text long text ' +
    'long text long text long text long text long text long text long text ' +
    'long text long text long text long text long text long text long text ' +
    'long text long text long text long text long text long text long text';

  it('should not cut off text when text is shorter than 200 characters', function () {
    var textCollapse = '';
    var el = $compile(textCollapse)(scope);

    scope.$digest();

    expect(el.has('.toggle-btn').length).toBe(0);
    expect(el.find('.content').text()).toEqual('short text');
  });

  it('text should have a default max length of 203 chars', function () {
    var textCollapse = '';
    var el = $compile(textCollapse)(scope);
    scope.$digest();

    expect(el.has('.toggle-btn').length).toBe(1);

    expect(el.find('span').text().length).toEqual(203);
  });

  it('text should have a custom max length', function () {
    var textCollapse = '';
    var el = $compile(textCollapse)(scope);
    scope.$digest();

    expect(el.has('.toggle-btn').length).toBe(1);

    expect(el.find('.content').text().length).toEqual(53);
  });

  it('text should have a "show more" button when cut off', function () {
    var textCollapse = '';
    var el = $compile(textCollapse)(scope);
    scope.$digest();

    var isolateScope = el.isolateScope();
    expect(isolateScope.showLessOrMore()).toEqual('UiComponents.mwTextCollapsible.showMore');

    isolateScope.defaultLength = 999;
    expect(isolateScope.showLessOrMore()).toEqual('UiComponents.mwTextCollapsible.showLess');
  });

  it('text should be expanded when button "show more" is clicked', function () {
    var textCollapse = '';
    var el = $compile(textCollapse)(scope);
    scope.$digest();

    expect(el.find('span').text().length).toEqual(203);
    el.find('a').trigger('click');
    expect(el.find('span').text().length).toEqual(539);
  });

});
<commit_msg>fixes typo<commit_after>describe('mwTextCollapsible', function () {
  var $compile;
  var $rootScope;
  var scope;

  beforeEach(module('karmaDirectiveTemplates'));

  beforeEach(module('mwUI.UiComponents'));

  //mock i18n filter
  beforeEach(function(){
    module(function($provide){
      $provide.value('i18nFilter', function(){
        return function(input){
          return input;
        };
      });
    });
  });

  beforeEach(inject(function (_$compile_, _$rootScope_) {
    $compile = _$compile_;
    $rootScope = _$rootScope_;
    scope = _$rootScope_.$new();
  }));

  var longText = 'long text long text long text long text long text ' +
    'long text long text long text long text long text long text long text ' +
    'long text long text long text long text long text long text long text ' +
    'long text long text long text long text long text long text long text ' +
    'long text long text long text long text long text long text long text ' +
    'long text long text long text long text long text long text long text ' +
    'long text long text long text long text long text long text long text ' +
    'long text long text long text long text long text long text long text';

  it('should not cut off text when text is shorter than 200 characters', function () {
    var textCollapse = '';
    var el = $compile(textCollapse)(scope);

    scope.$digest();

    expect(el.has('.toggle-btn').length).toBe(0);
    expect(el.find('.content').text()).toEqual('short text');
  });

  it('text should have a default max length of 203 chars', function () {
    var textCollapse = '';
    var el = $compile(textCollapse)(scope);
    scope.$digest();

    expect(el.has('.toggle-btn').length).toBe(1);

    expect(el.find('span').text().length).toEqual(203);
  });

  it('text should have a custom max length', function () {
    var textCollapse = '';
    var el = $compile(textCollapse)(scope);
    scope.$digest();

    expect(el.has('.toggle-btn').length).toBe(1);

    expect(el.find('.content').text().length).toEqual(53);
  });

  it('text should have a "show more" button when cut off', function () {
    var textCollapse = '';
    var el = $compile(textCollapse)(scope);
    scope.$digest();

    var isolateScope = el.isolateScope();
    expect(isolateScope.showLessOrMore()).toEqual('UiComponents.mwTextCollapsible.showMore');

    isolateScope.defaultLength = 999;
    expect(isolateScope.showLessOrMore()).toEqual('UiComponents.mwTextCollapsible.showLess');
  });

  it('text should be expanded when button "show more" is clicked', function () {
    var textCollapse = '';
    var el = $compile(textCollapse)(scope);
    scope.$digest();

    expect(el.find('span').text().length).toEqual(203);
    el.find('a').trigger('click');
    expect(el.find('span').text().length).toEqual(539);
  });

});
<|endoftext|>