<commit_before>/*
Copyright 2015, 2016 OpenMarket Ltd

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

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
var React = require('react');
var ContentRepo = require("matrix-js-sdk").ContentRepo;
var MatrixClientPeg = require('../../../MatrixClientPeg');
var Avatar = require('../../../Avatar');
var sdk = require("../../../index");

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

    // Room may be left unset here, but if it is,
    // oobData.avatarUrl should be set (else there
    // would be nowhere to get the avatar from)
    propTypes: {
        room: React.PropTypes.object,
        oobData: React.PropTypes.object,
        width: React.PropTypes.number,
        height: React.PropTypes.number,
        resizeMethod: React.PropTypes.string
    },

    getDefaultProps: function() {
        return {
            width: 36,
            height: 36,
            resizeMethod: 'crop',
            oobData: {},
        }
    },

    getInitialState: function() {
        return {
            urls: this.getImageUrls(this.props)
        };
    },

    componentWillReceiveProps: function(newProps) {
        this.setState({
            urls: this.getImageUrls(newProps)
        })
    },

    getImageUrls: function(props) {
        return [
            ContentRepo.getHttpUriForMxc(
                MatrixClientPeg.get().getHomeserverUrl(),
                props.oobData.avatarUrl,
                props.width, props.height, props.resizeMethod
            ), // highest priority
            this.getRoomAvatarUrl(props),
            this.getOneToOneAvatar(props),
            this.getFallbackAvatar(props) // lowest priority
        ].filter(function(url) {
            return (url != null && url != "");
        });
    },

    getRoomAvatarUrl: function(props) {
        if (!this.props.room) return null;

        return props.room.getAvatarUrl(
            MatrixClientPeg.get().getHomeserverUrl(),
            props.width, props.height, props.resizeMethod,
            false
        );
    },

    getOneToOneAvatar: function(props) {
        if (!this.props.room) return null;

        var mlist = props.room.currentState.members;
        var userIds = [];
        // for .. in optimisation to return early if there are >2 keys
        for (var uid in mlist) {
            if (mlist.hasOwnProperty(uid)) {
                userIds.push(uid);
            }
            if (userIds.length > 2) {
                return null;
            }
        }

        if (userIds.length == 2) {
            var theOtherGuy = null;
            if (mlist[userIds[0]].userId == MatrixClientPeg.get().credentials.userId) {
                theOtherGuy = mlist[userIds[1]];
            } else {
                theOtherGuy = mlist[userIds[0]];
            }
            return theOtherGuy.getAvatarUrl(
                MatrixClientPeg.get().getHomeserverUrl(),
                props.width, props.height, props.resizeMethod,
                false
            );
        } else if (userIds.length == 1) {
            return mlist[userIds[0]].getAvatarUrl(
                MatrixClientPeg.get().getHomeserverUrl(),
                props.width, props.height, props.resizeMethod,
                    false
            );
        } else {
           return null;
        }
    },

    getFallbackAvatar: function(props) {
        if (!this.props.room) return null;

        return Avatar.defaultAvatarUrlForString(props.room.roomId);
    },

    render: function() {
        var BaseAvatar = sdk.getComponent("avatars.BaseAvatar");

        var {room, oobData, ...otherProps} = this.props;

        var roomName = room ? room.name : oobData.name;

        return (
            <BaseAvatar {...otherProps} name={roomName}
                idName={room ? room.roomId : null}
                urls={this.state.urls} />
        );
    }
});
<commit_msg>Use correct 1-1 room avatar after users leave<commit_after>/*
Copyright 2015, 2016 OpenMarket Ltd

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

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
var React = require('react');
var ContentRepo = require("matrix-js-sdk").ContentRepo;
var MatrixClientPeg = require('../../../MatrixClientPeg');
var Avatar = require('../../../Avatar');
var sdk = require("../../../index");

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

    // Room may be left unset here, but if it is,
    // oobData.avatarUrl should be set (else there
    // would be nowhere to get the avatar from)
    propTypes: {
        room: React.PropTypes.object,
        oobData: React.PropTypes.object,
        width: React.PropTypes.number,
        height: React.PropTypes.number,
        resizeMethod: React.PropTypes.string
    },

    getDefaultProps: function() {
        return {
            width: 36,
            height: 36,
            resizeMethod: 'crop',
            oobData: {},
        }
    },

    getInitialState: function() {
        return {
            urls: this.getImageUrls(this.props)
        };
    },

    componentWillReceiveProps: function(newProps) {
        this.setState({
            urls: this.getImageUrls(newProps)
        })
    },

    getImageUrls: function(props) {
        return [
            ContentRepo.getHttpUriForMxc(
                MatrixClientPeg.get().getHomeserverUrl(),
                props.oobData.avatarUrl,
                props.width, props.height, props.resizeMethod
            ), // highest priority
            this.getRoomAvatarUrl(props),
            this.getOneToOneAvatar(props),
            this.getFallbackAvatar(props) // lowest priority
        ].filter(function(url) {
            return (url != null && url != "");
        });
    },

    getRoomAvatarUrl: function(props) {
        if (!this.props.room) return null;

        return props.room.getAvatarUrl(
            MatrixClientPeg.get().getHomeserverUrl(),
            props.width, props.height, props.resizeMethod,
            false
        );
    },

    getOneToOneAvatar: function(props) {
        if (!this.props.room) return null;

        var mlist = props.room.currentState.members;
        var userIds = [];
        // for .. in optimisation to return early if there are >2 keys
        for (var uid in mlist) {
            if (mlist.hasOwnProperty(uid) && ["join", "invite"].includes(mlist[uid].membership)) {
                userIds.push(uid);
            }
            if (userIds.length > 2) {
                return null;
            }
        }

        if (userIds.length == 2) {
            var theOtherGuy = null;
            if (mlist[userIds[0]].userId == MatrixClientPeg.get().credentials.userId) {
                theOtherGuy = mlist[userIds[1]];
            } else {
                theOtherGuy = mlist[userIds[0]];
            }
            return theOtherGuy.getAvatarUrl(
                MatrixClientPeg.get().getHomeserverUrl(),
                props.width, props.height, props.resizeMethod,
                false
            );
        } else if (userIds.length == 1) {
            return mlist[userIds[0]].getAvatarUrl(
                MatrixClientPeg.get().getHomeserverUrl(),
                props.width, props.height, props.resizeMethod,
                    false
            );
        } else {
           return null;
        }
    },

    getFallbackAvatar: function(props) {
        if (!this.props.room) return null;

        return Avatar.defaultAvatarUrlForString(props.room.roomId);
    },

    render: function() {
        var BaseAvatar = sdk.getComponent("avatars.BaseAvatar");

        var {room, oobData, ...otherProps} = this.props;

        var roomName = room ? room.name : oobData.name;

        return (
            <BaseAvatar {...otherProps} name={roomName}
                idName={room ? room.roomId : null}
                urls={this.state.urls} />
        );
    }
});
<|endoftext|>


<commit_before>const values = require('lodash.values');

const coreApp = require('kolibri');
const coreActions = require('kolibri.coreVue.vuex.actions');
const router = require('kolibri.coreVue.router');

const Constants = require('../../constants');
const ReportConstants = require('../../reportConstants');

const RecentReportResourceConstructor = require('../../apiResources/recentReport');
const ContentReportResourceConstructor = require('../../apiResources/contentReport');
const UserReportResourceConstructor = require('../../apiResources/userReport');
const UserSummaryResourceConstructor = require('../../apiResources/userSummary');
const ContentSummaryResourceConstructor = require('../../apiResources/contentSummary');

const UserSummaryResource = new UserSummaryResourceConstructor(coreApp);
const UserReportResource = new UserReportResourceConstructor(coreApp);
const ContentSummaryResource = new ContentSummaryResourceConstructor(coreApp);
const RecentReportResource = new RecentReportResourceConstructor(coreApp);
const ContentReportResource = new ContentReportResourceConstructor(coreApp);

const ChannelResource = coreApp.resources.ChannelResource;

// helper function for showRecent, provides list of channels with recent activity
function _showRecentChannels(store, classId) {
  function __getChannelLastActive(channel) {
    // helper function for _showRecentChannels
    // @param channel to get recentActivity for
    // @returns promise that resolves channel with lastActive value in object:
    // {
    //   'channelId': dateOfLastActivity,
    // }
    const summaryPayload = {
      channel_id: channel.id,
      collection_kind: ReportConstants.UserScopes.FACILITY,
      collection_id: store.state.core.session.facility_id,
    };

    // workaround for conditionalPromise.then() misbehaving
    return new Promise(
      (resolve, reject) => {
        const getSumm = ContentSummaryResource.getModel(channel.root_id, summaryPayload).fetch();
        getSumm.then(
          channelSummary => {
            const channelLastActive = {};
            channelLastActive[channel.id] = channelSummary.last_active;
            resolve(channelLastActive);
          },
          error => reject(error)
        );
      }
    );
  }

  const channelLastActivePromises = [];

  store.state.core.channels.list.forEach(
    channel => {
      channelLastActivePromises.push(__getChannelLastActive(channel));
    }
  );

  Promise.all(channelLastActivePromises).then(
    allChannelLastActive => {
      const lastActive = {};

      allChannelLastActive.forEach(
        channelLastActive => {
          Object.assign(lastActive, channelLastActive);
        }
      );

      const pageState = {
        lastActive,
        classId,
      };

      store.dispatch('SET_PAGE_STATE', pageState);
      store.dispatch('CORE_SET_PAGE_LOADING', false);
      store.dispatch('CORE_SET_ERROR', null);
    }
  );
}

function _showRecentReports(store, classId, channelId) {
  // should be cached if navigated to this point
  const channelPromise = ChannelResource.getModel(channelId).fetch();

  channelPromise.then(
    channelData => {
      const sevenDaysAgo = new Date();
      // this is being set by default in the backend
      // backend date data might be unreliable, though
      sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);

      const reportPayload = {
        channel_id: channelId,
        content_node_id: channelData.root_pk,
        collection_kind: ReportConstants.UserScopes.CLASSROOM,
        collection_id: classId,
        last_active_time: sevenDaysAgo,
      };
      const recentReportsPromise = RecentReportResource.getCollection(reportPayload).fetch();

      recentReportsPromise.then(
        reports => {
          const pageState = {
            reports,
            classId,
            channelId,
          };
          store.dispatch('SET_PAGE_STATE', pageState);
          store.dispatch('CORE_SET_PAGE_LOADING', false);
          store.dispatch('CORE_SET_ERROR', null);
          store.dispatch('CORE_SET_TITLE', 'Recents');
        },
        error => { coreActions.handleApiError(store, error); }
      );
    },
    error => { coreActions.handleApiError(store, error); }
  );
}

function showRecent(store, classId, channelId) {
  store.dispatch('CORE_SET_PAGE_LOADING', true);
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.RECENT);
  // Handled by coach index
  // store.dispatch('CORE_SET_TITLE', 'Coach Recents');

  if (channelId) {
    _showRecentReports(store, classId, channelId);
  } else {
    _showRecentChannels(store, classId);
  }
}

function redirectToDefaultReport(store, viewBy, classId, channelId) {
  const channelPromise = ChannelResource.getModel(channelId).fetch();

  channelPromise.then(
    (channelData) => {
      router.getInstance().replace({
        name: Constants.PageNames.TOPICS,
        params: {
          class_id: classId,
          channel_id: channelId,
          content_scope: ReportConstants.ContentScopes.ROOT,
          content_scope_id: channelData.root_pk,
          user_scope: ReportConstants.UserScopes.CLASSROOM,
          user_scope_id: classId,
          all_or_recent: ReportConstants.AllOrRecent.ALL,
          view_by_content_or_learners: ReportConstants.ViewBy.CONTENT,
          sort_column: ReportConstants.TableColumns.NAME,
          sort_order: ReportConstants.SortOrders.NONE,
        },
      });
    },
    error => {
      coreActions.handleError(store, error);
    }
  );
}

function updateSorting(store, sortColumn, sortOrder) {
  store.dispatch('SET_SORT_COLUMN', sortColumn);
  store.dispatch('SET_SORT_ORDER', sortOrder);
}

function showReport(store, viewBy, params) {
  store.dispatch('CORE_SET_PAGE_LOADING', true);

  const channelId = params.channel_id;
  const contentScope = params.content_scope;
  const contentScopeId = params.content_scope_id;
  const userScope = params.user_scope;
  const userScopeId = params.user_scope_id;
  const sortColumn = params.sort_column;
  const sortOrder = params.sort_order;

  /* check if params are semi-valid. */
  function _validate(value, constants) {
    if (!values(constants).includes(value)) {
      throw Error(`Invalid report parameters: ${value} not in ${JSON.stringify(constants)}`);
    }
  }
  _validate(contentScope, ReportConstants.ContentScopes);
  _validate(userScope, ReportConstants.UserScopes);
  _validate(viewBy, ReportConstants.ViewBy);
  _validate(sortColumn, ReportConstants.TableColumns);
  _validate(sortOrder, ReportConstants.SortOrders);

  if (
    userScope === ReportConstants.UserScopes.USER &&
    contentScope === ReportConstants.ContentScopes.CONTENT
  ) {
    throw Error('One user, one content - show exercise?');
  }

  // REPORT
  const reportPayload = {
    channel_id: channelId,
    content_node_id: contentScopeId,
    collection_kind: userScope,
    collection_id: userScopeId,
  };
  let reportPromise;
  if (viewBy === ReportConstants.ViewBy.CONTENT) {
    reportPromise = ContentReportResource.getCollection(reportPayload).fetch();
  } else {
    reportPromise = UserReportResource.getCollection(reportPayload).fetch();
  }

  // CONTENT SUMMARY
  const contentPromise = ContentSummaryResource.getModel(contentScopeId, reportPayload).fetch();

  // USER SUMMARY
  let userPromise;
  if (userScope === ReportConstants.UserScopes.USER) {
    userPromise = UserSummaryResource.getModel(userScopeId, reportPayload).fetch();
  }

  const promises = [];
  promises.push(reportPromise);
  promises.push(contentPromise);
  promises.push(userPromise);

  // API response handlers
  Promise.all(promises).then(
    ([report, contentSummary, userSummary]) => {
      // save URL params to store
      store.dispatch('SET_CHANNEL_ID', channelId);
      store.dispatch('SET_CONTENT_SCOPE', contentScope);
      store.dispatch('SET_CONTENT_SCOPE_ID', contentScopeId);
      store.dispatch('SET_USER_SCOPE', userScope);
      store.dispatch('SET_USER_SCOPE_ID', userScopeId);
      store.dispatch('SET_ALL_OR_RECENT', ReportConstants.AllOrRecent.ALL);
      store.dispatch('SET_VIEW_BY_CONTENT_OR_LEARNERS', viewBy);
      store.dispatch('SET_SORT_COLUMN', sortColumn);
      store.dispatch('SET_SORT_ORDER', sortOrder);

      // save results of API request
      store.dispatch('SET_TABLE_DATA', report || {});
      store.dispatch('SET_CONTENT_SCOPE_SUMMARY', contentSummary);
      store.dispatch('SET_USER_SCOPE_SUMMARY', userSummary || {});

      // finih up
      store.dispatch('SET_PAGE_NAME', Constants.PageNames.TOPICS);
      store.dispatch('CORE_SET_PAGE_LOADING', false);
    },
    error => { coreActions.handleError(store, error); }
  );
}

function showLearners(store) {
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.LEARNERS);
  store.dispatch('CORE_SET_PAGE_LOADING', false);
}

module.exports = {
  showRecent,
  redirectToDefaultReport,
  showReport,
  showLearners,
  updateSorting,
};
<commit_msg>ensure class id is set<commit_after>const values = require('lodash.values');

const coreApp = require('kolibri');
const coreActions = require('kolibri.coreVue.vuex.actions');
const router = require('kolibri.coreVue.router');

const Constants = require('../../constants');
const ReportConstants = require('../../reportConstants');

const RecentReportResourceConstructor = require('../../apiResources/recentReport');
const ContentReportResourceConstructor = require('../../apiResources/contentReport');
const UserReportResourceConstructor = require('../../apiResources/userReport');
const UserSummaryResourceConstructor = require('../../apiResources/userSummary');
const ContentSummaryResourceConstructor = require('../../apiResources/contentSummary');

const UserSummaryResource = new UserSummaryResourceConstructor(coreApp);
const UserReportResource = new UserReportResourceConstructor(coreApp);
const ContentSummaryResource = new ContentSummaryResourceConstructor(coreApp);
const RecentReportResource = new RecentReportResourceConstructor(coreApp);
const ContentReportResource = new ContentReportResourceConstructor(coreApp);

const ChannelResource = coreApp.resources.ChannelResource;

// helper function for showRecent, provides list of channels with recent activity
function _showRecentChannels(store, classId) {
  function __getChannelLastActive(channel) {
    // helper function for _showRecentChannels
    // @param channel to get recentActivity for
    // @returns promise that resolves channel with lastActive value in object:
    // {
    //   'channelId': dateOfLastActivity,
    // }
    const summaryPayload = {
      channel_id: channel.id,
      collection_kind: ReportConstants.UserScopes.FACILITY,
      collection_id: store.state.core.session.facility_id,
    };

    // workaround for conditionalPromise.then() misbehaving
    return new Promise(
      (resolve, reject) => {
        const getSumm = ContentSummaryResource.getModel(channel.root_id, summaryPayload).fetch();
        getSumm.then(
          channelSummary => {
            const channelLastActive = {};
            channelLastActive[channel.id] = channelSummary.last_active;
            resolve(channelLastActive);
          },
          error => reject(error)
        );
      }
    );
  }

  const channelLastActivePromises = [];

  store.state.core.channels.list.forEach(
    channel => {
      channelLastActivePromises.push(__getChannelLastActive(channel));
    }
  );

  Promise.all(channelLastActivePromises).then(
    allChannelLastActive => {
      const lastActive = {};

      allChannelLastActive.forEach(
        channelLastActive => {
          Object.assign(lastActive, channelLastActive);
        }
      );

      const pageState = {
        lastActive,
        classId,
      };

      store.dispatch('SET_PAGE_STATE', pageState);
      store.dispatch('CORE_SET_PAGE_LOADING', false);
      store.dispatch('CORE_SET_ERROR', null);
    }
  );
}

function _showRecentReports(store, classId, channelId) {
  // should be cached if navigated to this point
  const channelPromise = ChannelResource.getModel(channelId).fetch();

  channelPromise.then(
    channelData => {
      const sevenDaysAgo = new Date();
      // this is being set by default in the backend
      // backend date data might be unreliable, though
      sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);

      const reportPayload = {
        channel_id: channelId,
        content_node_id: channelData.root_pk,
        collection_kind: ReportConstants.UserScopes.CLASSROOM,
        collection_id: classId,
        last_active_time: sevenDaysAgo,
      };
      const recentReportsPromise = RecentReportResource.getCollection(reportPayload).fetch();

      recentReportsPromise.then(
        reports => {
          const pageState = {
            reports,
            classId,
            channelId,
          };
          store.dispatch('SET_PAGE_STATE', pageState);
          store.dispatch('CORE_SET_PAGE_LOADING', false);
          store.dispatch('CORE_SET_ERROR', null);
          store.dispatch('CORE_SET_TITLE', 'Recents');
        },
        error => { coreActions.handleApiError(store, error); }
      );
    },
    error => { coreActions.handleApiError(store, error); }
  );
}

function showRecent(store, classId, channelId) {
  store.dispatch('CORE_SET_PAGE_LOADING', true);
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.RECENT);
  // Handled by coach index
  // store.dispatch('CORE_SET_TITLE', 'Coach Recents');

  if (channelId) {
    _showRecentReports(store, classId, channelId);
  } else {
    _showRecentChannels(store, classId);
  }
}

function redirectToDefaultReport(store, viewBy, classId, channelId) {
  const channelPromise = ChannelResource.getModel(channelId).fetch();

  channelPromise.then(
    (channelData) => {
      router.getInstance().replace({
        name: Constants.PageNames.TOPICS,
        params: {
          class_id: classId,
          channel_id: channelId,
          content_scope: ReportConstants.ContentScopes.ROOT,
          content_scope_id: channelData.root_pk,
          user_scope: ReportConstants.UserScopes.CLASSROOM,
          user_scope_id: classId,
          all_or_recent: ReportConstants.AllOrRecent.ALL,
          view_by_content_or_learners: ReportConstants.ViewBy.CONTENT,
          sort_column: ReportConstants.TableColumns.NAME,
          sort_order: ReportConstants.SortOrders.NONE,
        },
      });
    },
    error => {
      coreActions.handleError(store, error);
    }
  );
}

function updateSorting(store, sortColumn, sortOrder) {
  store.dispatch('SET_SORT_COLUMN', sortColumn);
  store.dispatch('SET_SORT_ORDER', sortOrder);
}

function showReport(store, viewBy, params) {
  store.dispatch('CORE_SET_PAGE_LOADING', true);

  const classId = params.class_id;
  const channelId = params.channel_id;
  const contentScope = params.content_scope;
  const contentScopeId = params.content_scope_id;
  const userScope = params.user_scope;
  const userScopeId = params.user_scope_id;
  const sortColumn = params.sort_column;
  const sortOrder = params.sort_order;

  /* check if params are semi-valid. */
  function _validate(value, constants) {
    if (!values(constants).includes(value)) {
      throw Error(`Invalid report parameters: ${value} not in ${JSON.stringify(constants)}`);
    }
  }
  _validate(contentScope, ReportConstants.ContentScopes);
  _validate(userScope, ReportConstants.UserScopes);
  _validate(viewBy, ReportConstants.ViewBy);
  _validate(sortColumn, ReportConstants.TableColumns);
  _validate(sortOrder, ReportConstants.SortOrders);

  if (
    userScope === ReportConstants.UserScopes.USER &&
    contentScope === ReportConstants.ContentScopes.CONTENT
  ) {
    throw Error('One user, one content - show exercise?');
  }

  // REPORT
  const reportPayload = {
    channel_id: channelId,
    content_node_id: contentScopeId,
    collection_kind: userScope,
    collection_id: userScopeId,
  };
  let reportPromise;
  if (viewBy === ReportConstants.ViewBy.CONTENT) {
    reportPromise = ContentReportResource.getCollection(reportPayload).fetch();
  } else {
    reportPromise = UserReportResource.getCollection(reportPayload).fetch();
  }

  // CONTENT SUMMARY
  const contentPromise = ContentSummaryResource.getModel(contentScopeId, reportPayload).fetch();

  // USER SUMMARY
  let userPromise;
  if (userScope === ReportConstants.UserScopes.USER) {
    userPromise = UserSummaryResource.getModel(userScopeId, reportPayload).fetch();
  }

  const promises = [];
  promises.push(reportPromise);
  promises.push(contentPromise);
  promises.push(userPromise);

  // API response handlers
  Promise.all(promises).then(
    ([report, contentSummary, userSummary]) => {
      // save URL params to store
      store.dispatch('SET_CLASS_ID', classId);
      store.dispatch('SET_CHANNEL_ID', channelId);
      store.dispatch('SET_CONTENT_SCOPE', contentScope);
      store.dispatch('SET_CONTENT_SCOPE_ID', contentScopeId);
      store.dispatch('SET_USER_SCOPE', userScope);
      store.dispatch('SET_USER_SCOPE_ID', userScopeId);
      store.dispatch('SET_ALL_OR_RECENT', ReportConstants.AllOrRecent.ALL);
      store.dispatch('SET_VIEW_BY_CONTENT_OR_LEARNERS', viewBy);
      store.dispatch('SET_SORT_COLUMN', sortColumn);
      store.dispatch('SET_SORT_ORDER', sortOrder);

      // save results of API request
      store.dispatch('SET_TABLE_DATA', report || {});
      store.dispatch('SET_CONTENT_SCOPE_SUMMARY', contentSummary);
      store.dispatch('SET_USER_SCOPE_SUMMARY', userSummary || {});

      // finih up
      store.dispatch('SET_PAGE_NAME', Constants.PageNames.TOPICS);
      store.dispatch('CORE_SET_PAGE_LOADING', false);
    },
    error => { coreActions.handleError(store, error); }
  );
}

function showLearners(store) {
  store.dispatch('SET_PAGE_NAME', Constants.PageNames.LEARNERS);
  store.dispatch('CORE_SET_PAGE_LOADING', false);
}

module.exports = {
  showRecent,
  redirectToDefaultReport,
  showReport,
  showLearners,
  updateSorting,
};
<|endoftext|>


<commit_before>import { jestMockResource } from 'testUtils'; // eslint-disable-line
import { ClassroomResource, ContentNodeResource, ExamResource } from 'kolibri.resources';
import { showExamsPage } from '../src/modules/examsRoot/handlers';
import examReportStore from '../src/modules/examReport';
import makeStore from './makeStore';

jestMockResource(ClassroomResource);
jestMockResource(ContentNodeResource);
jestMockResource(ExamResource);

// fakes for data, since they have similar shape
const fakeItems = [
  {
    id: 'item_1',
    name: 'item one',
    root: 'pk1',
    misc: 'ha ha ha',
    learner_count: 5,
  },
  {
    id: 'item_2',
    name: 'item two',
    root: 'pk2',
    misc: 'ha ha ha',
    learner_count: 6,
  },
];

const fakeExams = [
  {
    id: '1',
    title: 'UNIT 1 Exam',
    channel_id: 'item_1',
    collection: 'collection_id',
    active: true,
    archive: false,
    question_count: 8,
    question_sources: [
      {
        exercise_id: '12345',
        number_of_questions: 6,
        title: 'exercise title 1',
      },
      {
        exercise_id: '54321',
        number_of_questions: 2,
        title: 'exercise title 2',
      },
    ],
    seed: 1234,
    learners_see_fixed_order: false,
    data_model_version: 0,
    assignments: [
      {
        id: 'assignmentA',
        exam: '1',
        collection: {
          id: 'class_1',
          kind: 'classroom',
          name: 'class_1',
        },
      },
    ],
  },
  {
    id: '2',
    title: 'UNIT 1 Quiz',
    channel_id: 'item_1',
    collection: 'collection_id',
    active: false,
    archive: false,
    question_count: 10,
    question_sources: [
      {
        exercise_id: 'xyz',
        number_of_questions: 3,
        title: 'exercise title 3',
      },
      {
        exercise_id: 'abc',
        number_of_questions: 3,
        title: 'exercise title 4',
      },
      {
        exercise_id: '123',
        number_of_questions: 4,
        title: 'exercise title 5',
      },
    ],
    seed: 4321,
    learners_see_fixed_order: false,
    data_model_version: 0,
    assignments: [
      {
        id: 'assignmentB',
        exam: '2',
        collection: {
          id: 'group_1',
          kind: 'learnergroup',
          name: 'group_1',
        },
      },
      {
        id: 'assignmentC',
        exam: '2',
        collection: {
          id: 'group_2',
          kind: 'learnergroup',
          name: 'group_2',
        },
      },
    ],
  },
  {
    id: '3',
    title: 'Newer quiz style',
    channel_id: 'item_1',
    collection: 'collection_id',
    active: false,
    archive: false,
    question_count: 3,
    question_sources: [
      {
        exercise_id: 'exercise_3',
        question_id: '00001',
        title: 'exercise title 3',
      },
      {
        exercise_id: 'exercise_4',
        question_id: '00002',
        title: 'exercise title 4',
      },
      {
        exercise_id: 'exercise_5',
        question_id: '00003',
        title: 'exercise title 5',
      },
      {
        exercise_id: 'exercise_5',
        question_id: '00001',
        title: 'exercise title 5',
      },
    ],
    seed: 4321,
    learners_see_fixed_order: true,
    data_model_version: 1,
    assignments: [
      {
        id: 'assignmentB',
        exam: '2',
        collection: {
          id: 'group_1',
          kind: 'learnergroup',
          name: 'group_1',
        },
      },
      {
        id: 'assignmentC',
        exam: '2',
        collection: {
          id: 'group_2',
          kind: 'learnergroup',
          name: 'group_2',
        },
      },
    ],
  },
];

const fakeExamState = [
  {
    id: '1',
    title: 'UNIT 1 Exam',
    channelId: 'item_1',
    collection: 'collection_id',
    active: true,
    archive: false,
    questionCount: 8,
    questionSources: [
      {
        exercise_id: '12345',
        number_of_questions: 6,
        title: 'exercise title 1',
      },
      {
        exercise_id: '54321',
        number_of_questions: 2,
        title: 'exercise title 2',
      },
    ],
    seed: 1234,
    dataModelVersion: 0,
    learnersSeeFixedOrder: false,
    assignments: [
      {
        id: 'assignmentA',
        exam: '1',
        collection: {
          id: 'class_1',
          kind: 'classroom',
          name: 'class_1',
        },
      },
    ],
  },
  {
    id: '2',
    title: 'UNIT 1 Quiz',
    channelId: 'item_1',
    collection: 'collection_id',
    active: false,
    archive: false,
    questionCount: 10,
    questionSources: [
      {
        exercise_id: 'xyz',
        number_of_questions: 3,
        title: 'exercise title 3',
      },
      {
        exercise_id: 'abc',
        number_of_questions: 3,
        title: 'exercise title 4',
      },
      {
        exercise_id: '123',
        number_of_questions: 4,
        title: 'exercise title 5',
      },
    ],
    seed: 4321,
    dataModelVersion: 0,
    learnersSeeFixedOrder: false,
    assignments: [
      {
        id: 'assignmentB',
        exam: '2',
        collection: {
          id: 'group_1',
          kind: 'learnergroup',
          name: 'group_1',
        },
      },
      {
        id: 'assignmentC',
        exam: '2',
        collection: {
          id: 'group_2',
          kind: 'learnergroup',
          name: 'group_2',
        },
      },
    ],
  },
  {
    id: '3',
    title: 'Newer quiz style',
    channelId: 'item_1',
    collection: 'collection_id',
    active: false,
    archive: false,
    questionCount: 3,
    questionSources: [
      {
        exercise_id: 'exercise_3',
        question_id: '00001',
        title: 'exercise title 3',
      },
      {
        exercise_id: 'exercise_4',
        question_id: '00002',
        title: 'exercise title 4',
      },
      {
        exercise_id: 'exercise_5',
        question_id: '00003',
        title: 'exercise title 5',
      },
      {
        exercise_id: 'exercise_5',
        question_id: '00001',
        title: 'exercise title 5',
      },
    ],
    seed: 4321,
    dataModelVersion: 1,
    learnersSeeFixedOrder: true,
    assignments: [
      {
        id: 'assignmentB',
        exam: '2',
        collection: {
          id: 'group_1',
          kind: 'learnergroup',
          name: 'group_1',
        },
      },
      {
        id: 'assignmentC',
        exam: '2',
        collection: {
          id: 'group_2',
          kind: 'learnergroup',
          name: 'group_2',
        },
      },
    ],
  },
];

// generate some more sample data - metainfo about the exercises used in the exams
const exerciseContentNodes = [];
fakeExamState.forEach(fakeExam => {
  let questionIds = [];
  if (fakeExam.dataModelVersion === 0) {
    // create an arbitrary array, because v0 didn't know about question IDs
    questionIds = Array.from(Array(20).keys());
  } else if (fakeExam.dataModelVersion === 1) {
    // Generate a list of IDs based on what we know the exam is referencing.
    // This isn't quite accurate because it takes all question IDs from all exercises.
    // ¯\_(ツ)_/¯
    questionIds = fakeExam.questionSources.map(question => question.question_id);
  }
  fakeExam.questionSources.forEach(question => {
    // mirrors what comes back from the ContentNode endpoints
    exerciseContentNodes.push({
      id: question.exercise_id,
      title: question.title,
      assessmentmetadata: [
        { assessment_item_ids: questionIds, mastery_model: { doStuff: 'doStuff' } },
      ],
    });
  });
});

describe('exam report state', () => {
  it('examQuestions getter handles a v0 exam', () => {
    const state = {
      exams: fakeExamState,
      exam: fakeExams[0],
      examsModalSet: false,
      busy: false,
      exerciseContentNodes,
    };
    const questions = [
      { exercise_id: '12345', question_id: 14, title: 'exercise title 1' },
      { exercise_id: '12345', question_id: 16, title: 'exercise title 1' },
      { exercise_id: '12345', question_id: 13, title: 'exercise title 1' },
      { exercise_id: '54321', question_id: 18, title: 'exercise title 2' },
      { exercise_id: '12345', question_id: 0, title: 'exercise title 1' },
      { exercise_id: '54321', question_id: 0, title: 'exercise title 2' },
      { exercise_id: '12345', question_id: 18, title: 'exercise title 1' },
      { exercise_id: '12345', question_id: 12, title: 'exercise title 1' },
    ];
    expect(examReportStore.getters.examQuestions(state)).toEqual(questions);
  });
  it('examQuestions getter handles another v0 exam', () => {
    const state = {
      exams: fakeExamState,
      exam: fakeExams[1],
      examsModalSet: false,
      busy: false,
      exerciseContentNodes,
    };
    const questions = [
      { exercise_id: '123', question_id: 10, title: 'exercise title 5' },
      { exercise_id: 'xyz', question_id: 8, title: 'exercise title 3' },
      { exercise_id: 'xyz', question_id: 10, title: 'exercise title 3' },
      { exercise_id: '123', question_id: 13, title: 'exercise title 5' },
      { exercise_id: 'abc', question_id: 8, title: 'exercise title 4' },
      { exercise_id: 'abc', question_id: 17, title: 'exercise title 4' },
      { exercise_id: '123', question_id: 8, title: 'exercise title 5' },
      { exercise_id: 'xyz', question_id: 17, title: 'exercise title 3' },
      { exercise_id: '123', question_id: 17, title: 'exercise title 5' },
      { exercise_id: 'abc', question_id: 10, title: 'exercise title 4' },
    ];
    expect(examReportStore.getters.examQuestions(state)).toEqual(questions);
  });
  it('examQuestions getter handles a v1 exam', () => {
    const state = {
      exams: fakeExamState,
      exam: fakeExams[2],
      examsModalSet: false,
      busy: false,
      exerciseContentNodes,
    };
    const questions = [
      { exercise_id: 'exercise_3', question_id: '00001', title: 'exercise title 3' },
      { exercise_id: 'exercise_4', question_id: '00002', title: 'exercise title 4' },
      { exercise_id: 'exercise_5', question_id: '00003', title: 'exercise title 5' },
      { exercise_id: 'exercise_5', question_id: '00001', title: 'exercise title 5' },
    ];
    expect(examReportStore.getters.examQuestions(state)).toEqual(questions);
  });
});

describe('showPage actions for coach exams section', () => {
  let store;
  beforeEach(() => {
    store = makeStore();
    ClassroomResource.__resetMocks();
    ContentNodeResource.__resetMocks();
    ExamResource.__resetMocks();
  });

  describe('showExamsPage', () => {
    it('store is properly set up when there are no problems', async () => {
      ClassroomResource.__getCollectionFetchReturns(fakeItems);
      ExamResource.__getCollectionFetchReturns(fakeExams);

      // Using the weird naming from fakeItems
      const classId = 'item_1';
      await showExamsPage(store, classId)._promise;
      expect(ClassroomResource.getCollection).toHaveBeenCalled();
      expect(ExamResource.getCollection).toHaveBeenCalledWith({ collection: classId });
      expect(store.state.examsRoot).toMatchObject({
        exams: fakeExamState,
        examsModalSet: false,
        busy: false,
      });
    });

    it('store is properly set up when there are errors', async () => {
      ClassroomResource.__getCollectionFetchReturns(fakeItems);
      ExamResource.__getCollectionFetchReturns('channel error', true);
      try {
        await showExamsPage(store, 'class_1')._promise;
      } catch (error) {
        expect(store.state.core.error).toEqual('channel error');
      }
    });
  });
});
<commit_msg>fix test<commit_after>import { jestMockResource } from 'testUtils'; // eslint-disable-line
import { ClassroomResource, ContentNodeResource, ExamResource } from 'kolibri.resources';
import { showExamsPage } from '../src/modules/examsRoot/handlers';
import examReportStore from '../src/modules/examReport';
import makeStore from './makeStore';

jestMockResource(ClassroomResource);
jestMockResource(ContentNodeResource);
jestMockResource(ExamResource);

// fakes for data, since they have similar shape
const fakeItems = [
  {
    id: 'item_1',
    name: 'item one',
    root: 'pk1',
    misc: 'ha ha ha',
    learner_count: 5,
  },
  {
    id: 'item_2',
    name: 'item two',
    root: 'pk2',
    misc: 'ha ha ha',
    learner_count: 6,
  },
];

const fakeExams = [
  {
    id: '1',
    title: 'UNIT 1 Exam',
    collection: 'collection_id',
    active: true,
    archive: false,
    question_count: 8,
    question_sources: [
      {
        exercise_id: '12345',
        number_of_questions: 6,
        title: 'exercise title 1',
      },
      {
        exercise_id: '54321',
        number_of_questions: 2,
        title: 'exercise title 2',
      },
    ],
    seed: 1234,
    learners_see_fixed_order: false,
    data_model_version: 0,
    assignments: [
      {
        id: 'assignmentA',
        exam: '1',
        collection: {
          id: 'class_1',
          kind: 'classroom',
          name: 'class_1',
        },
      },
    ],
  },
  {
    id: '2',
    title: 'UNIT 1 Quiz',
    collection: 'collection_id',
    active: false,
    archive: false,
    question_count: 10,
    question_sources: [
      {
        exercise_id: 'xyz',
        number_of_questions: 3,
        title: 'exercise title 3',
      },
      {
        exercise_id: 'abc',
        number_of_questions: 3,
        title: 'exercise title 4',
      },
      {
        exercise_id: '123',
        number_of_questions: 4,
        title: 'exercise title 5',
      },
    ],
    seed: 4321,
    learners_see_fixed_order: false,
    data_model_version: 0,
    assignments: [
      {
        id: 'assignmentB',
        exam: '2',
        collection: {
          id: 'group_1',
          kind: 'learnergroup',
          name: 'group_1',
        },
      },
      {
        id: 'assignmentC',
        exam: '2',
        collection: {
          id: 'group_2',
          kind: 'learnergroup',
          name: 'group_2',
        },
      },
    ],
  },
  {
    id: '3',
    title: 'Newer quiz style',
    collection: 'collection_id',
    active: false,
    archive: false,
    question_count: 3,
    question_sources: [
      {
        exercise_id: 'exercise_3',
        question_id: '00001',
        title: 'exercise title 3',
      },
      {
        exercise_id: 'exercise_4',
        question_id: '00002',
        title: 'exercise title 4',
      },
      {
        exercise_id: 'exercise_5',
        question_id: '00003',
        title: 'exercise title 5',
      },
      {
        exercise_id: 'exercise_5',
        question_id: '00001',
        title: 'exercise title 5',
      },
    ],
    seed: 4321,
    learners_see_fixed_order: true,
    data_model_version: 1,
    assignments: [
      {
        id: 'assignmentB',
        exam: '2',
        collection: {
          id: 'group_1',
          kind: 'learnergroup',
          name: 'group_1',
        },
      },
      {
        id: 'assignmentC',
        exam: '2',
        collection: {
          id: 'group_2',
          kind: 'learnergroup',
          name: 'group_2',
        },
      },
    ],
  },
];

const fakeExamState = [
  {
    id: '1',
    title: 'UNIT 1 Exam',
    collection: 'collection_id',
    active: true,
    archive: false,
    questionCount: 8,
    questionSources: [
      {
        exercise_id: '12345',
        number_of_questions: 6,
        title: 'exercise title 1',
      },
      {
        exercise_id: '54321',
        number_of_questions: 2,
        title: 'exercise title 2',
      },
    ],
    seed: 1234,
    dataModelVersion: 0,
    learnersSeeFixedOrder: false,
    assignments: [
      {
        id: 'assignmentA',
        exam: '1',
        collection: {
          id: 'class_1',
          kind: 'classroom',
          name: 'class_1',
        },
      },
    ],
  },
  {
    id: '2',
    title: 'UNIT 1 Quiz',
    collection: 'collection_id',
    active: false,
    archive: false,
    questionCount: 10,
    questionSources: [
      {
        exercise_id: 'xyz',
        number_of_questions: 3,
        title: 'exercise title 3',
      },
      {
        exercise_id: 'abc',
        number_of_questions: 3,
        title: 'exercise title 4',
      },
      {
        exercise_id: '123',
        number_of_questions: 4,
        title: 'exercise title 5',
      },
    ],
    seed: 4321,
    dataModelVersion: 0,
    learnersSeeFixedOrder: false,
    assignments: [
      {
        id: 'assignmentB',
        exam: '2',
        collection: {
          id: 'group_1',
          kind: 'learnergroup',
          name: 'group_1',
        },
      },
      {
        id: 'assignmentC',
        exam: '2',
        collection: {
          id: 'group_2',
          kind: 'learnergroup',
          name: 'group_2',
        },
      },
    ],
  },
  {
    id: '3',
    title: 'Newer quiz style',
    collection: 'collection_id',
    active: false,
    archive: false,
    questionCount: 3,
    questionSources: [
      {
        exercise_id: 'exercise_3',
        question_id: '00001',
        title: 'exercise title 3',
      },
      {
        exercise_id: 'exercise_4',
        question_id: '00002',
        title: 'exercise title 4',
      },
      {
        exercise_id: 'exercise_5',
        question_id: '00003',
        title: 'exercise title 5',
      },
      {
        exercise_id: 'exercise_5',
        question_id: '00001',
        title: 'exercise title 5',
      },
    ],
    seed: 4321,
    dataModelVersion: 1,
    learnersSeeFixedOrder: true,
    assignments: [
      {
        id: 'assignmentB',
        exam: '2',
        collection: {
          id: 'group_1',
          kind: 'learnergroup',
          name: 'group_1',
        },
      },
      {
        id: 'assignmentC',
        exam: '2',
        collection: {
          id: 'group_2',
          kind: 'learnergroup',
          name: 'group_2',
        },
      },
    ],
  },
];

// generate some more sample data - metainfo about the exercises used in the exams
const exerciseContentNodes = [];
fakeExamState.forEach(fakeExam => {
  let questionIds = [];
  if (fakeExam.dataModelVersion === 0) {
    // create an arbitrary array, because v0 didn't know about question IDs
    questionIds = Array.from(Array(20).keys());
  } else if (fakeExam.dataModelVersion === 1) {
    // Generate a list of IDs based on what we know the exam is referencing.
    // This isn't quite accurate because it takes all question IDs from all exercises.
    // ¯\_(ツ)_/¯
    questionIds = fakeExam.questionSources.map(question => question.question_id);
  }
  fakeExam.questionSources.forEach(question => {
    // mirrors what comes back from the ContentNode endpoints
    exerciseContentNodes.push({
      id: question.exercise_id,
      title: question.title,
      assessmentmetadata: [
        { assessment_item_ids: questionIds, mastery_model: { doStuff: 'doStuff' } },
      ],
    });
  });
});

describe('exam report state', () => {
  it('examQuestions getter handles a v0 exam', () => {
    const state = {
      exams: fakeExamState,
      exam: fakeExams[0],
      examsModalSet: false,
      busy: false,
      exerciseContentNodes,
    };
    const questions = [
      { exercise_id: '12345', question_id: 14, title: 'exercise title 1' },
      { exercise_id: '12345', question_id: 16, title: 'exercise title 1' },
      { exercise_id: '12345', question_id: 13, title: 'exercise title 1' },
      { exercise_id: '54321', question_id: 18, title: 'exercise title 2' },
      { exercise_id: '12345', question_id: 0, title: 'exercise title 1' },
      { exercise_id: '54321', question_id: 0, title: 'exercise title 2' },
      { exercise_id: '12345', question_id: 18, title: 'exercise title 1' },
      { exercise_id: '12345', question_id: 12, title: 'exercise title 1' },
    ];
    expect(examReportStore.getters.examQuestions(state)).toEqual(questions);
  });
  it('examQuestions getter handles another v0 exam', () => {
    const state = {
      exams: fakeExamState,
      exam: fakeExams[1],
      examsModalSet: false,
      busy: false,
      exerciseContentNodes,
    };
    const questions = [
      { exercise_id: '123', question_id: 10, title: 'exercise title 5' },
      { exercise_id: 'xyz', question_id: 8, title: 'exercise title 3' },
      { exercise_id: 'xyz', question_id: 10, title: 'exercise title 3' },
      { exercise_id: '123', question_id: 13, title: 'exercise title 5' },
      { exercise_id: 'abc', question_id: 8, title: 'exercise title 4' },
      { exercise_id: 'abc', question_id: 17, title: 'exercise title 4' },
      { exercise_id: '123', question_id: 8, title: 'exercise title 5' },
      { exercise_id: 'xyz', question_id: 17, title: 'exercise title 3' },
      { exercise_id: '123', question_id: 17, title: 'exercise title 5' },
      { exercise_id: 'abc', question_id: 10, title: 'exercise title 4' },
    ];
    expect(examReportStore.getters.examQuestions(state)).toEqual(questions);
  });
  it('examQuestions getter handles a v1 exam', () => {
    const state = {
      exams: fakeExamState,
      exam: fakeExams[2],
      examsModalSet: false,
      busy: false,
      exerciseContentNodes,
    };
    const questions = [
      { exercise_id: 'exercise_3', question_id: '00001', title: 'exercise title 3' },
      { exercise_id: 'exercise_4', question_id: '00002', title: 'exercise title 4' },
      { exercise_id: 'exercise_5', question_id: '00003', title: 'exercise title 5' },
      { exercise_id: 'exercise_5', question_id: '00001', title: 'exercise title 5' },
    ];
    expect(examReportStore.getters.examQuestions(state)).toEqual(questions);
  });
});

describe('showPage actions for coach exams section', () => {
  let store;
  beforeEach(() => {
    store = makeStore();
    ClassroomResource.__resetMocks();
    ContentNodeResource.__resetMocks();
    ExamResource.__resetMocks();
  });

  describe('showExamsPage', () => {
    it('store is properly set up when there are no problems', async () => {
      ClassroomResource.__getCollectionFetchReturns(fakeItems);
      ExamResource.__getCollectionFetchReturns(fakeExams);

      // Using the weird naming from fakeItems
      const classId = 'item_1';
      await showExamsPage(store, classId)._promise;
      expect(ClassroomResource.getCollection).toHaveBeenCalled();
      expect(ExamResource.getCollection).toHaveBeenCalledWith({ collection: classId });
      expect(store.state.examsRoot).toMatchObject({
        exams: fakeExamState,
        examsModalSet: false,
        busy: false,
      });
    });

    it('store is properly set up when there are errors', async () => {
      ClassroomResource.__getCollectionFetchReturns(fakeItems);
      ExamResource.__getCollectionFetchReturns('channel error', true);
      try {
        await showExamsPage(store, 'class_1')._promise;
      } catch (error) {
        expect(store.state.core.error).toEqual('channel error');
      }
    });
  });
});
<|endoftext|>


<commit_before>	'use strict';

$("#Macération").click(function(e){
	$(".ScientifiqueJ3-1").fadeIn("slow");
	$(".ScientifiqueJ3-2").fadeOut("slow");
	$(".ScientifiqueJ3-3").fadeOut("slow");
	$(".ScientifiqueJ3-4").fadeOut("slow");

	$(".DataJ3-1").fadeIn("slow");
	$(".DataJ3-2").fadeOut("slow");
	$(".DataJ3-3").fadeOut("slow");
	$(".DataJ3-4").fadeOut("slow");
});

$("#Ultrasons").click(function(e){
	$(".ScientifiqueJ3-1").fadeOut("slow");
	$(".ScientifiqueJ3-2").fadeIn("slow");
	$(".ScientifiqueJ3-3").fadeOut("slow");
	$(".ScientifiqueJ3-4").fadeOut("slow");

	$(".DataJ3-1").fadeOut("slow");
	$(".DataJ3-2").fadeIn("slow");
	$(".DataJ3-3").fadeOut("slow");
	$(".DataJ3-4").fadeOut("slow");
});

$("#Enzymes").click(function(e){
	$(".ScientifiqueJ3-1").fadeOut("slow");
	$(".ScientifiqueJ3-2").fadeOut("slow");
	$(".ScientifiqueJ3-3").fadeIn("slow");
	$(".ScientifiqueJ3-4").fadeOut("slow");

	$(".DataJ3-1").fadeOut("slow");
	$(".DataJ3-2").fadeOut("slow");
	$(".DataJ3-3").fadeIn("slow");
	$(".DataJ3-4").fadeOut("slow");
});

$("#Ultrasons_Enzymes").click(function(e){
	$(".ScientifiqueJ3-1").fadeOut("slow");
	$(".ScientifiqueJ3-2").fadeOut("slow");
	$(".ScientifiqueJ3-3").fadeOut("slow");
	$(".ScientifiqueJ3-4").fadeIn("slow");

	$(".DataJ3-1").fadeOut("slow");
	$(".DataJ3-2").fadeOut("slow");
	$(".DataJ3-3").fadeOut("slow");
	$(".DataJ3-4").fadeIn("slow");
});<commit_msg>Coloration data3<commit_after>	'use strict';

$("#Macération").click(function(e){
	$(".ScientifiqueJ3-1").fadeIn("slow");
	$(".ScientifiqueJ3-2").fadeOut("slow");
	$(".ScientifiqueJ3-3").fadeOut("slow");
	$(".ScientifiqueJ3-4").fadeOut("slow");

	$(".DataJ3-1").fadeIn("slow");
	$(".DataJ3-2").fadeOut("slow");
	$(".DataJ3-3").fadeOut("slow");
	$(".DataJ3-4").fadeOut("slow");

	$("#Macération").css("background-color", "#faf7f5");
	$("#Ultrasons").css("background-color", "#6a9dae");
	$("#Enzymes").css("background-color", "#6a9dae");
	$("#Ultrasons_Enzymes").css("background-color", "#6a9dae");

});

$("#Ultrasons").click(function(e){
	$(".ScientifiqueJ3-1").fadeOut("slow");
	$(".ScientifiqueJ3-2").fadeIn("slow");
	$(".ScientifiqueJ3-3").fadeOut("slow");
	$(".ScientifiqueJ3-4").fadeOut("slow");

	$(".DataJ3-1").fadeOut("slow");
	$(".DataJ3-2").fadeIn("slow");
	$(".DataJ3-3").fadeOut("slow");
	$(".DataJ3-4").fadeOut("slow");

	$("#Macération").css("background-color", "#6a9dae");
	$("#Ultrasons").css("background-color", "#faf7f5");
	$("#Enzymes").css("background-color", "#6a9dae");
	$("#Ultrasons_Enzymes").css("background-color", "#6a9dae");
});

$("#Enzymes").click(function(e){
	$(".ScientifiqueJ3-1").fadeOut("slow");
	$(".ScientifiqueJ3-2").fadeOut("slow");
	$(".ScientifiqueJ3-3").fadeIn("slow");
	$(".ScientifiqueJ3-4").fadeOut("slow");

	$(".DataJ3-1").fadeOut("slow");
	$(".DataJ3-2").fadeOut("slow");
	$(".DataJ3-3").fadeIn("slow");
	$(".DataJ3-4").fadeOut("slow");

	$("#Macération").css("background-color", "#6a9dae");
	$("#Ultrasons").css("background-color", "#6a9dae");
	$("#Enzymes").css("background-color", "#faf7f5");
	$("#Ultrasons_Enzymes").css("background-color", "#6a9dae");
});

$("#Ultrasons_Enzymes").click(function(e){
	$(".ScientifiqueJ3-1").fadeOut("slow");
	$(".ScientifiqueJ3-2").fadeOut("slow");
	$(".ScientifiqueJ3-3").fadeOut("slow");
	$(".ScientifiqueJ3-4").fadeIn("slow");

	$(".DataJ3-1").fadeOut("slow");
	$(".DataJ3-2").fadeOut("slow");
	$(".DataJ3-3").fadeOut("slow");
	$(".DataJ3-4").fadeIn("slow");

	$("#Macération").css("background-color", "#6a9dae");
	$("#Ultrasons").css("background-color", "#6a9dae");
	$("#Enzymes").css("background-color", "#6a9dae");
	$("#Ultrasons_Enzymes").css("background-color", "#faf7f5");
});<|endoftext|>


<commit_before>import * as R from 'ramda'

import { BaseError } from 'utils/error'

const parseDate = (d) => d && new Date(d)

const PACKAGES_SUFFIX = '_packages'

/*
File: {
  key: str,
  type: 'object',
  score: num,
  bucket: str,
  path: str,
  versions: [
    {
      id: str,
      score: num,
      updated: ?Date,
      lastModified: ?Date,
      size: num,
      meta: str,
    },
  ],
}

Package: {
  key: str,
  type: 'package',
  score: num,
  bucket: str,
  handle: str,
  revision: str,
  hash: str,
  lastModified: ?Date,
  meta: str, // should it be parsed?
}
*/

const getTypeAndBucketFromIndex = (idx) => {
  const i = idx.lastIndexOf('-reindex-')
  const idxNormalized = i === -1 ? idx : idx.slice(0, i)
  const suffixIdx = idxNormalized.lastIndexOf(PACKAGES_SUFFIX)
  return suffixIdx === -1
    ? { type: 'object', bucket: idxNormalized }
    : { type: 'package', bucket: idxNormalized.slice(0, suffixIdx) }
}

const extractObjData = ({ bucket, score, src }) => {
  const key = `object:${bucket}/${src.key}`
  return {
    [key]: {
      key,
      type: 'object',
      score,
      bucket,
      path: src.key,
      versions: [
        {
          id: src.version_id,
          score,
          updated: parseDate(src.updated),
          lastModified: parseDate(src.last_modified),
          size: src.size,
          meta: src.user_meta,
        },
      ],
    },
  }
}

const parseJSON = (s) => {
  try {
    return JSON.parse(s)
  } catch (e) {
    return s
  }
}

const extractPkgData = ({ bucket, score, src }) => {
  const key = `package:${bucket}/${src.handle}:${src.hash}`
  return {
    [key]: {
      key,
      type: 'package',
      bucket,
      score,
      handle: src.handle,
      revision: src.pointer_file || 'latest',
      hash: src.hash,
      lastModified: parseDate(src.last_modified),
      meta: parseJSON(src.metadata),
      // tags: src.tags, // TODO: currently not provided
      comment: src.comment,
    },
  }
}

const extractData = ({ _score: score, _source: src, _index: idx }) => {
  const { type, bucket } = getTypeAndBucketFromIndex(idx)
  const extract = type === 'object' ? extractObjData : extractPkgData
  return extract({ bucket, score, src })
}

const takeR = (l, r) => r

const mkMerger = (cases) => (key, l, r) => (cases[key] || takeR)(l, r)

const mergeHits = R.mergeDeepWithKey(
  mkMerger({
    score: R.max,
    versions: R.pipe(
      R.concat,
      R.sortBy((v) => -v.score),
    ),
  }),
)

const mergeAllHits = R.pipe(
  R.reduce((acc, hit) => mergeHits(acc, extractData(hit)), {}),
  R.values,
  R.sortBy((h) => -h.score),
)

const unescape = (s) => s.replace(/\\n/g, '\n')

export default async function search({
  req,
  query,
  buckets = [],
  mode = 'all', // all | objects | packages
}) {
  // eslint-disable-next-line no-nested-ternary
  const index = buckets.length
    ? R.pipe(
        R.chain((b) => {
          const idxs = []
          if (mode === 'objects' || mode === 'all') {
            idxs.push(b)
          }
          if (mode === 'packages' || mode === 'all') {
            idxs.push(`${b}${PACKAGES_SUFFIX}`)
          }
          return idxs
        }),
        R.join(','),
      )(buckets)
    : mode === 'objects' // eslint-disable-line no-nested-ternary
    ? `*,-*${PACKAGES_SUFFIX}`
    : mode === 'packages'
    ? `*${PACKAGES_SUFFIX}`
    : '*'
  try {
    const result = await req('/search', { index, action: 'search', query })
    const hits = mergeAllHits(result.hits.hits)
    const total = Math.min(result.hits.total, result.hits.hits.length)
    return { total, hits }
  } catch (e) {
    const match = e.message.match(
      /^API Gateway Error: RequestError\(400, 'search_phase_execution_exception', '(.+)'\)$/,
    )
    if (match) {
      throw new BaseError('SearchSyntaxError', { details: unescape(match[1]) })
    }
    console.log('Search error:', e.message)
    console.error(e)
    throw e
  }
}
<commit_msg>search: use wildcard for specifying package indices to avoid error (#1800)<commit_after>import * as R from 'ramda'

import { BaseError } from 'utils/error'

const parseDate = (d) => d && new Date(d)

const PACKAGES_SUFFIX = '_packages'

/*
File: {
  key: str,
  type: 'object',
  score: num,
  bucket: str,
  path: str,
  versions: [
    {
      id: str,
      score: num,
      updated: ?Date,
      lastModified: ?Date,
      size: num,
      meta: str,
    },
  ],
}

Package: {
  key: str,
  type: 'package',
  score: num,
  bucket: str,
  handle: str,
  revision: str,
  hash: str,
  lastModified: ?Date,
  meta: str, // should it be parsed?
}
*/

const getTypeAndBucketFromIndex = (idx) => {
  const i = idx.lastIndexOf('-reindex-')
  const idxNormalized = i === -1 ? idx : idx.slice(0, i)
  const suffixIdx = idxNormalized.lastIndexOf(PACKAGES_SUFFIX)
  return suffixIdx === -1
    ? { type: 'object', bucket: idxNormalized }
    : { type: 'package', bucket: idxNormalized.slice(0, suffixIdx) }
}

const extractObjData = ({ bucket, score, src }) => {
  const key = `object:${bucket}/${src.key}`
  return {
    [key]: {
      key,
      type: 'object',
      score,
      bucket,
      path: src.key,
      versions: [
        {
          id: src.version_id,
          score,
          updated: parseDate(src.updated),
          lastModified: parseDate(src.last_modified),
          size: src.size,
          meta: src.user_meta,
        },
      ],
    },
  }
}

const parseJSON = (s) => {
  try {
    return JSON.parse(s)
  } catch (e) {
    return s
  }
}

const extractPkgData = ({ bucket, score, src }) => {
  const key = `package:${bucket}/${src.handle}:${src.hash}`
  return {
    [key]: {
      key,
      type: 'package',
      bucket,
      score,
      handle: src.handle,
      revision: src.pointer_file || 'latest',
      hash: src.hash,
      lastModified: parseDate(src.last_modified),
      meta: parseJSON(src.metadata),
      // tags: src.tags, // TODO: currently not provided
      comment: src.comment,
    },
  }
}

const extractData = ({ _score: score, _source: src, _index: idx }) => {
  const { type, bucket } = getTypeAndBucketFromIndex(idx)
  const extract = type === 'object' ? extractObjData : extractPkgData
  return extract({ bucket, score, src })
}

const takeR = (l, r) => r

const mkMerger = (cases) => (key, l, r) => (cases[key] || takeR)(l, r)

const mergeHits = R.mergeDeepWithKey(
  mkMerger({
    score: R.max,
    versions: R.pipe(
      R.concat,
      R.sortBy((v) => -v.score),
    ),
  }),
)

const mergeAllHits = R.pipe(
  R.reduce((acc, hit) => mergeHits(acc, extractData(hit)), {}),
  R.values,
  R.sortBy((h) => -h.score),
)

const unescape = (s) => s.replace(/\\n/g, '\n')

export default async function search({
  req,
  query,
  buckets = [],
  mode = 'all', // all | objects | packages
}) {
  // eslint-disable-next-line no-nested-ternary
  const index = buckets.length
    ? R.pipe(
        R.chain((b) => {
          const idxs = []
          if (mode === 'objects' || mode === 'all') {
            idxs.push(b)
          }
          if (mode === 'packages' || mode === 'all') {
            idxs.push(`${b}${PACKAGES_SUFFIX}*`)
          }
          return idxs
        }),
        R.join(','),
      )(buckets)
    : mode === 'objects' // eslint-disable-line no-nested-ternary
    ? `*,-*${PACKAGES_SUFFIX}`
    : mode === 'packages'
    ? `*${PACKAGES_SUFFIX}`
    : '*'
  try {
    const result = await req('/search', { index, action: 'search', query })
    const hits = mergeAllHits(result.hits.hits)
    const total = Math.min(result.hits.total, result.hits.hits.length)
    return { total, hits }
  } catch (e) {
    const match = e.message.match(
      /^API Gateway Error: RequestError\(400, 'search_phase_execution_exception', '(.+)'\)$/,
    )
    if (match) {
      throw new BaseError('SearchSyntaxError', { details: unescape(match[1]) })
    }
    console.log('Search error:', e.message)
    console.error(e)
    throw e
  }
}
<|endoftext|>


<commit_before>import {invokeLifecycle} from './lifecycle';

export class DialogController {
  constructor(renderer: DialogRenderer, settings: any, resolve: Function, reject: Function) {
    this._renderer = renderer;
    this.settings = settings;
    this._resolve = resolve;
    this._reject = reject;
  }

  ok(result: DialogResult) {
    this.close(true, result);
  }

  cancel(result: DialogResult) {
    this.close(false, result);
  }

  error(message: any) {
    return invokeLifecycle(this.viewModel, 'deactivate').then(() => {
      return this._renderer.hideDialog(this).then(() => {
        return this._renderer.destroyDialogHost(this).then(() => {
          this.controller.unbind();
          this._reject(message);
        });
      });
    });
  }

  close(ok: boolean, result: DialogResult) {
    let returnResult = new DialogResult(!ok, result);
    return invokeLifecycle(this.viewModel, 'canDeactivate').then(canDeactivate => {
      if (canDeactivate) {
        return invokeLifecycle(this.viewModel, 'deactivate').then(() => {
          return this._renderer.hideDialog(this).then(() => {
            return this._renderer.destroyDialogHost(this).then(() => {
              this.controller.unbind();
              this._resolve(returnResult);
            });
          });
        });
      }
    });
  }
}

class DialogResult {
  wasCancelled = false;
  output;
  constructor(cancelled, result) {
    this.wasCancelled = cancelled;
    this.output = result;
  }
}
<commit_msg>fix(dialog-controller): fix the class interface<commit_after>import {invokeLifecycle} from './lifecycle';

export class DialogController {
  settings: any;
  constructor(renderer: DialogRenderer, settings: any, resolve: Function, reject: Function) {
    this._renderer = renderer;
    this.settings = settings;
    this._resolve = resolve;
    this._reject = reject;
  }

  ok(result: any) {
    this.close(true, result);
  }

  cancel(result: any) {
    this.close(false, result);
  }

  error(message: any) {
    return invokeLifecycle(this.viewModel, 'deactivate').then(() => {
      return this._renderer.hideDialog(this).then(() => {
        return this._renderer.destroyDialogHost(this).then(() => {
          this.controller.unbind();
          this._reject(message);
        });
      });
    });
  }

  close(ok: boolean, result: any) {
    let returnResult = new DialogResult(!ok, result);
    return invokeLifecycle(this.viewModel, 'canDeactivate').then(canDeactivate => {
      if (canDeactivate) {
        return invokeLifecycle(this.viewModel, 'deactivate').then(() => {
          return this._renderer.hideDialog(this).then(() => {
            return this._renderer.destroyDialogHost(this).then(() => {
              this.controller.unbind();
              this._resolve(returnResult);
            });
          });
        });
      }
    });
  }
}

class DialogResult {
  wasCancelled: boolean = false;
  output: any;
  constructor(cancelled: boolean, result: any) {
    this.wasCancelled = cancelled;
    this.output = result;
  }
}
<|endoftext|>


<commit_before>

define([], function() {
    'use strict';
    return {
	getDataFromAttribute: function(attribute) {
	    var re = /ROSMOD::(\w+)::([\d]*)::((?:CALLBACK COMPLETED)|(?:CALLBACK FIFO ENQUEUE) ?)*::Alias=(\w+); (?:(?:[\w=;, ]*Enqueue Time)|(?:Completion Time)) sec=(\d*), nsec=(\d*)/gi;
	    var result = re.exec(attribute);
	    var log_data = {};
	    var first_time = 0.0;
	    var max_exec_time = 0.0;
	    if (result != null)
		var first_time = parseInt(result[5]) + result[6]/1000000000.0;
	    while(result != null) {
		var alias = result[4];
		if (!log_data[alias]) {
		    log_data[alias] = {
			data : [],
			enqueue_times: [],
			completion_times: []
		    };
		}
		if (result[3].indexOf('ENQUEUE') > -1) {
		    var enqueue_time = parseInt(result[5]) + result[6]/1000000000.0;
		    log_data[alias].enqueue_times.push(enqueue_time);
		    if (first_time == 0.0)
			first_time = enqueue_time;
		}
		else if (result[3].indexOf('COMPLETED') > -1) {
		    var completion_time = parseInt(result[5]) + result[6]/1000000000.0;
		    log_data[alias].completion_times.push(completion_time);
		}
		if ( log_data[alias].completion_times.length > 0 && log_data[alias].enqueue_times.length > 0 ) {
		    // at this point there can only be one completion_time, though there may be multiple enqueue times
		    var comp = log_data[alias].completion_times[0];
		    var enq = log_data[alias].enqueue_times[0];
		    var exec_time = comp - enq;
		    if (exec_time > max_exec_time)
			max_exec_time = exec_time;
		    log_data[alias].data.push([enq - first_time,  0]);
		    log_data[alias].data.push([enq - first_time,  exec_time]);
		    log_data[alias].data.push([comp - first_time, exec_time]);
		    log_data[alias].data.push([comp - first_time, 0]);
		    // remove the currently processed enqueue / completion time
		    log_data[alias].enqueue_times = log_data[alias].enqueue_times.slice(1);
		    log_data[alias].completion_times = log_data[alias].completion_times.slice(1);
		}
		result = re.exec(attribute);
	    }
	    return log_data;
	},
    }
});
<commit_msg>updated parser to handle new format for trace logs.<commit_after>

define([], function() {
    'use strict';
    return {
	getDataFromAttribute: function(attribute) {
	    var re = /((?:[^\r\n,+\-\(\)\\\/][\S])+),([0-9\.]+),([0-9\.]+),([0-9\.]+),([0-9\.]+),([0-9\.]+)/gi;
	    var result = re.exec(attribute);
	    var log_data = {};
	    var first_time = 0.0;
	    if (result != null)
		var first_time = parseFloat(result[2]);
	    while(result != null) {
		var alias = result[1];
		if (!log_data[alias]) {
		    log_data[alias] = {
			data : [],
		    };
		}
		var enq = parseFloat(result[2]);
		var comp = parseFloat(result[4]);
		var exec_time = parseFloat(result[5]);
		log_data[alias].data.push([enq - first_time,  0]);
		log_data[alias].data.push([enq - first_time,  exec_time]);
		log_data[alias].data.push([comp - first_time, exec_time]);
		log_data[alias].data.push([comp - first_time, 0]);
		result = re.exec(attribute);
	    }
	    return log_data;
	},
    }
});
<|endoftext|>


<commit_before>import { Pos } from "../line/pos"
import { visualLine } from "../line/spans"
import { getLine } from "../line/utils_line"
import { charCoords, cursorCoords, displayWidth, paddingH, wrappedLineExtentChar } from "../measurement/position_measurement"
import { getOrder, iterateBidiSections } from "../util/bidi"
import { elt } from "../util/dom"

export function updateSelection(cm) {
  cm.display.input.showSelection(cm.display.input.prepareSelection())
}

export function prepareSelection(cm, primary = true) {
  let doc = cm.doc, result = {}
  let curFragment = result.cursors = document.createDocumentFragment()
  let selFragment = result.selection = document.createDocumentFragment()

  for (let i = 0; i < doc.sel.ranges.length; i++) {
    if (!primary && i == doc.sel.primIndex) continue
    let range = doc.sel.ranges[i]
    if (range.from().line >= cm.display.viewTo || range.to().line < cm.display.viewFrom) continue
    let collapsed = range.empty()
    if (collapsed || cm.options.showCursorWhenSelecting)
      drawSelectionCursor(cm, range.head, curFragment)
    if (!collapsed)
      drawSelectionRange(cm, range, selFragment)
  }
  return result
}

// Draws a cursor for the given range
export function drawSelectionCursor(cm, head, output) {
  let pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine)

  let cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor"))
  cursor.style.left = pos.left + "px"
  cursor.style.top = pos.top + "px"
  cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px"

  if (pos.other) {
    // Secondary cursor, shown when on a 'jump' in bi-directional text
    let otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor"))
    otherCursor.style.display = ""
    otherCursor.style.left = pos.other.left + "px"
    otherCursor.style.top = pos.other.top + "px"
    otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px"
  }
}

function cmpCoords(a, b) { return a.top - b.top || a.left - b.left }

// Draws the given range as a highlighted selection
function drawSelectionRange(cm, range, output) {
  let display = cm.display, doc = cm.doc
  let fragment = document.createDocumentFragment()
  let padding = paddingH(cm.display), leftSide = padding.left
  let rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right

  function add(left, top, width, bottom) {
    if (top < 0) top = 0
    top = Math.round(top)
    bottom = Math.round(bottom)
    fragment.appendChild(elt("div", null, "CodeMirror-selected", `position: absolute; left: ${left}px;
                             top: ${top}px; width: ${width == null ? rightSide - left : width}px;
                             height: ${bottom - top}px`))
  }

  function drawForLine(line, fromArg, toArg) {
    let lineObj = getLine(doc, line)
    let lineLen = lineObj.text.length
    let start, end
    function coords(ch, bias) {
      return charCoords(cm, Pos(line, ch), "div", lineObj, bias)
    }

    let order = getOrder(lineObj, doc.direction)
    iterateBidiSections(order, fromArg || 0, toArg == null ? lineLen : toArg, (from, to, dir, i) => {
      let fromPos = coords(from, dir == "ltr" ? "left" : "right")
      let toPos = coords(to - 1, dir == "ltr" ? "right" : "left")
      if (dir == "ltr") {
        let fromLeft = fromArg == null && from == 0 ? leftSide : fromPos.left
        let toRight = toArg == null && to == lineLen ? rightSide : toPos.right
        if (toPos.top - fromPos.top <= 3) { // Single line
          add(fromLeft, toPos.top, toRight - fromLeft, toPos.bottom)
        } else { // Multiple lines
          add(fromLeft, fromPos.top, null, fromPos.bottom)
          if (fromPos.bottom < toPos.top) add(leftSide, fromPos.bottom, null, toPos.top)
          add(leftSide, toPos.top, toPos.right, toPos.bottom)
        }
      } else if (from < to) { // RTL
        let fromRight = fromArg == null && from == 0 ? rightSide : fromPos.right
        let toLeft = toArg == null && to == lineLen ? leftSide : toPos.left
        if (toPos.top - fromPos.top <= 3) { // Single line
          add(toLeft, toPos.top, fromRight - toLeft, toPos.bottom)
        } else { // Multiple lines
          let topLeft = leftSide
          if (i) {
            let topEnd = wrappedLineExtentChar(cm, lineObj, null, from).end
            // The coordinates returned for an RTL wrapped space tend to
            // be complete bogus, so try to skip that here.
            topLeft = coords(topEnd - (/\s/.test(lineObj.text.charAt(topEnd - 1)) ? 2 : 1), "left").left
          }
          add(topLeft, fromPos.top, fromRight - topLeft, fromPos.bottom)
          if (fromPos.bottom < toPos.top) add(leftSide, fromPos.bottom, null, toPos.top)
          let botWidth = null
          if (i < order.length  - 1 || true) {
            let botStart = wrappedLineExtentChar(cm, lineObj, null, to).begin
            botWidth = coords(botStart, "right").right - toLeft
          }
          add(toLeft, toPos.top, botWidth, toPos.bottom)
        }
      }

      if (!start || cmpCoords(fromPos, start) < 0) start = fromPos
      if (cmpCoords(toPos, start) < 0) start = toPos
      if (!end || cmpCoords(fromPos, end) < 0) end = fromPos
      if (cmpCoords(toPos, end) < 0) end = toPos
    })
    return {start: start, end: end}
  }

  let sFrom = range.from(), sTo = range.to()
  if (sFrom.line == sTo.line) {
    drawForLine(sFrom.line, sFrom.ch, sTo.ch)
  } else {
    let fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line)
    let singleVLine = visualLine(fromLine) == visualLine(toLine)
    let leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end
    let rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start
    if (singleVLine) {
      if (leftEnd.top < rightStart.top - 2) {
        add(leftEnd.right, leftEnd.top, null, leftEnd.bottom)
        add(leftSide, rightStart.top, rightStart.left, rightStart.bottom)
      } else {
        add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom)
      }
    }
    if (leftEnd.bottom < rightStart.top)
      add(leftSide, leftEnd.bottom, null, rightStart.top)
  }

  output.appendChild(fragment)
}

// Cursor-blinking
export function restartBlink(cm) {
  if (!cm.state.focused) return
  let display = cm.display
  clearInterval(display.blinker)
  let on = true
  display.cursorDiv.style.visibility = ""
  if (cm.options.cursorBlinkRate > 0)
    display.blinker = setInterval(() => display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden",
      cm.options.cursorBlinkRate)
  else if (cm.options.cursorBlinkRate < 0)
    display.cursorDiv.style.visibility = "hidden"
}
<commit_msg>Rewrite selection drawing again<commit_after>import { Pos } from "../line/pos"
import { visualLine } from "../line/spans"
import { getLine } from "../line/utils_line"
import { charCoords, cursorCoords, displayWidth, paddingH, wrappedLineExtentChar } from "../measurement/position_measurement"
import { getOrder, iterateBidiSections } from "../util/bidi"
import { elt } from "../util/dom"

export function updateSelection(cm) {
  cm.display.input.showSelection(cm.display.input.prepareSelection())
}

export function prepareSelection(cm, primary = true) {
  let doc = cm.doc, result = {}
  let curFragment = result.cursors = document.createDocumentFragment()
  let selFragment = result.selection = document.createDocumentFragment()

  for (let i = 0; i < doc.sel.ranges.length; i++) {
    if (!primary && i == doc.sel.primIndex) continue
    let range = doc.sel.ranges[i]
    if (range.from().line >= cm.display.viewTo || range.to().line < cm.display.viewFrom) continue
    let collapsed = range.empty()
    if (collapsed || cm.options.showCursorWhenSelecting)
      drawSelectionCursor(cm, range.head, curFragment)
    if (!collapsed)
      drawSelectionRange(cm, range, selFragment)
  }
  return result
}

// Draws a cursor for the given range
export function drawSelectionCursor(cm, head, output) {
  let pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine)

  let cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor"))
  cursor.style.left = pos.left + "px"
  cursor.style.top = pos.top + "px"
  cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px"

  if (pos.other) {
    // Secondary cursor, shown when on a 'jump' in bi-directional text
    let otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor"))
    otherCursor.style.display = ""
    otherCursor.style.left = pos.other.left + "px"
    otherCursor.style.top = pos.other.top + "px"
    otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px"
  }
}

function cmpCoords(a, b) { return a.top - b.top || a.left - b.left }

// Draws the given range as a highlighted selection
function drawSelectionRange(cm, range, output) {
  let display = cm.display, doc = cm.doc
  let fragment = document.createDocumentFragment()
  let padding = paddingH(cm.display), leftSide = padding.left
  let rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right
  let docLTR = doc.direction == "ltr"

  function add(left, top, width, bottom) {
    if (top < 0) top = 0
    top = Math.round(top)
    bottom = Math.round(bottom)
    fragment.appendChild(elt("div", null, "CodeMirror-selected", `position: absolute; left: ${left}px;
                             top: ${top}px; width: ${width == null ? rightSide - left : width}px;
                             height: ${bottom - top}px`))
  }

  function drawForLine(line, fromArg, toArg) {
    let lineObj = getLine(doc, line)
    let lineLen = lineObj.text.length
    let start, end
    function coords(ch, bias) {
      return charCoords(cm, Pos(line, ch), "div", lineObj, bias)
    }

    function wrapX(pos, dir, side) {
      let extent = wrappedLineExtentChar(cm, lineObj, null, pos)
      let prop = (dir == "ltr") == (side == "after") ? "left" : "right"
      let ch = side == "after" ? extent.begin : extent.end - (/\s/.test(lineObj.text.charAt(extent.end - 1)) ? 2 : 1)
      return coords(ch, prop)[prop]
    }

    let order = getOrder(lineObj, doc.direction)
    iterateBidiSections(order, fromArg || 0, toArg == null ? lineLen : toArg, (from, to, dir, i) => {
      let ltr = dir == "ltr"
      let fromPos = coords(from, ltr ? "left" : "right")
      let toPos = coords(to - 1, ltr ? "right" : "left")

      let openStart = fromArg == null && from == 0, openEnd = toArg == null && to == lineLen
      let first = i == 0, last = !order || i == order.length - 1
      if (toPos.top - fromPos.top <= 3) { // Single line
        let openLeft = (docLTR ? openStart : openEnd) && first
        let openRight = (docLTR ? openEnd : openStart) && last
        let left = openLeft ? leftSide : (ltr ? fromPos : toPos).left
        let right = openRight ? rightSide : (ltr ? toPos : fromPos).right
        add(left, fromPos.top, right - left, fromPos.bottom)
      } else { // Multiple lines
        let topLeft, topRight, botLeft, botRight
        if (ltr) {
          topLeft = docLTR && openStart && first ? leftSide : fromPos.left
          topRight = docLTR ? rightSide : wrapX(from, dir, "before")
          botLeft = docLTR ? leftSide : wrapX(to, dir, "after")
          botRight = docLTR && openEnd && last ? rightSide : toPos.right
        } else {
          topLeft = !docLTR ? leftSide : wrapX(from, dir, "before")
          topRight = !docLTR && openStart && first ? rightSide : fromPos.right
          botLeft = !docLTR && openEnd && last ? leftSide : toPos.left
          botRight = !docLTR ? rightSide : wrapX(to, dir, "after")
        }
        add(topLeft, fromPos.top, topRight - topLeft, fromPos.bottom)
        if (fromPos.bottom < toPos.top) add(leftSide, fromPos.bottom, null, toPos.top)
        add(botLeft, toPos.top, botRight - botLeft, toPos.bottom)
      }

      if (!start || cmpCoords(fromPos, start) < 0) start = fromPos
      if (cmpCoords(toPos, start) < 0) start = toPos
      if (!end || cmpCoords(fromPos, end) < 0) end = fromPos
      if (cmpCoords(toPos, end) < 0) end = toPos
    })
    return {start: start, end: end}
  }

  let sFrom = range.from(), sTo = range.to()
  if (sFrom.line == sTo.line) {
    drawForLine(sFrom.line, sFrom.ch, sTo.ch)
  } else {
    let fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line)
    let singleVLine = visualLine(fromLine) == visualLine(toLine)
    let leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end
    let rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start
    if (singleVLine) {
      if (leftEnd.top < rightStart.top - 2) {
        add(leftEnd.right, leftEnd.top, null, leftEnd.bottom)
        add(leftSide, rightStart.top, rightStart.left, rightStart.bottom)
      } else {
        add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom)
      }
    }
    if (leftEnd.bottom < rightStart.top)
      add(leftSide, leftEnd.bottom, null, rightStart.top)
  }

  output.appendChild(fragment)
}

// Cursor-blinking
export function restartBlink(cm) {
  if (!cm.state.focused) return
  let display = cm.display
  clearInterval(display.blinker)
  let on = true
  display.cursorDiv.style.visibility = ""
  if (cm.options.cursorBlinkRate > 0)
    display.blinker = setInterval(() => display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden",
      cm.options.cursorBlinkRate)
  else if (cm.options.cursorBlinkRate < 0)
    display.cursorDiv.style.visibility = "hidden"
}
<|endoftext|>


<commit_before>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * All rights reserved.
 */

var Document = this.Document = Base.extend({
	beans: true,

	initialize: function(canvas) {
		// Store reference to the currently active global paper scope:
		this._scope = paper;
		if (canvas && canvas instanceof HTMLCanvasElement) {
			this.canvas = canvas;
			if (canvas.attributes.resize) {
				// If the canvas has a fullscreen attribute,
				// resize the canvas to fill the window and resize it again
				// whenever the user resizes the window.
				// TODO: set the following styles on the body tag:
				// body {
				//	background: black;
				//	margin: 0;
				//	overflow: hidden;
				// }
				this._size = DomElement.getWindowSize()
						.subtract(DomElement.getOffset(this.canvas));
				this.canvas.width = this._size.width;
				this.canvas.height = this._size.height;
				var that = this;
				var offset = DomElement.getOffset(this.canvas);
				DomEvent.add(window, {
					resize: function(event) {
						// Only get canvas offset if it's not invisible (size is
						// 0, 0), as otherwise the offset would be wrong.
						if (!DomElement.getSize(that.canvas).equals([0, 0]))
							offset = DomElement.getOffset(that.canvas);
						that.setSize(DomElement.getWindowSize().subtract(offset));
						that.redraw();
					}
				});
			} else {
				this._size = Size.create(canvas.offsetWidth,
						canvas.offsetHeight);
			}
		} else {
			this._size = Size.read(arguments) || new Size(1024, 768);
			this.canvas = CanvasProvider.getCanvas(this._size);
		}
		// TODO: Currently we don't do anything with Document#bounds.
		// What does it mean to change the bounds of the document? (JP)
		this.bounds = Rectangle.create(0, 0, this._size.width,
				this._size.height);
		this.context = this.canvas.getContext('2d');
		// Push it onto this._scope.documents and set index:
		this._index = this._scope.documents.push(this) - 1;
		this.activate();
		this.layers = [];
		this.activeLayer = new Layer();
		this.setCurrentStyle(null);
		this.symbols = [];
		this.activeView = new DocumentView(this);
		this.views = [this.activeView];
		this._selectedItems = {};
		this._selectedItemCount = 0;
		// TODO: Test this on IE:
		if (this.canvas.attributes.stats) {
			this.stats = new Stats();
			// Align top-left to the canvas
			var element = this.stats.domElement,
				style = element.style,
				offset = DomElement.getOffset(this.canvas);
			style.position = 'absolute';
			style.left = offset.x + 'px';
			style.top = offset.y + 'px';
			document.body.appendChild(element);
		}
	},

	getSize: function() {
		return this._size;
	},

	setSize: function(size) {
		size = Size.read(arguments);
		if (this.canvas) {
			this.canvas.width = size.width;
			this.canvas.height = size.height;
		}
		this._size = size;
		this.bounds.setSize(size);
	},

	getCurrentStyle: function() {
		return this._currentStyle;
	},

	setCurrentStyle: function(style) {
		this._currentStyle = PathStyle.create(null, style);
	},

	activate: function() {
		// TODO: Remove indexOf()
		var index = this._scope.documents.indexOf(this);
		if (index != -1) {
			this._scope.document = this;
			return true;
		}
		return false;
	},

	getSelectedItems: function() {
		// TODO: return groups if their children are all selected,
		// and filter out their children from the list.
		// TODO: the order of these items should be that of their
		// drawing order.
		var items = [];
		Base.each(this._selectedItems, function(item) {
			items.push(item);
		});
		return items;
	},

	// TODO: implement setSelectedItems?

	_selectItem: function(item, select) {
		if (select) {
			this._selectedItemCount++;
			this._selectedItems[item.getId()] = item;
		} else {
			this._selectedItemCount--;
			delete this._selectedItems[item.getId()];
		}
	},

	/**
	 * Selects all items in the document.
	 */
	selectAll: function() {
		// TODO: is using for var i in good practice?
		// or should we use Base.each? (JP)
		for (var i = 0, l = this.layers.length; i < l; i++)
			this.layers[i].setSelected(true);
	},

	/**
	 * Deselects all selected items in the document.
	 */
	deselectAll: function() {
		// TODO: is using for var i in good practice?
		// or should we use Base.each? (JP)
		for (var i in this._selectedItems)
			this._selectedItems[i].setSelected(false);
	},

	draw: function() {
		if (this.canvas) {
			if (this.stats)
				this.stats.update();
			var ctx = this.context;
			ctx.save();

			// TODO: Remove dirty rectangle test code once it's actually
			// implemented.
			var testDirtyRects = false;
			if (testDirtyRects) {
				var left = this.size.width / 8,
					top = this.size.height / 8;

				function clear(rect) {
					ctx.clearRect(rect.x, rect.y, rect.width, rect.height);

					if (true) {
						ctx.moveTo(rect.x, rect.y);
						ctx.lineTo(rect.x + rect.width, rect.y);
						ctx.lineTo(rect.x + rect.width, rect.y + rect.height);
						ctx.lineTo(rect.x, rect.y + rect.height);
					}
				}

				ctx.beginPath();

				clear(Rectangle.create(left, top, 2 * left, 2 * top));
				clear(Rectangle.create(3 * left, 3 * top, 2 * left, 2 * top));

//				clear(Rectangle.create(left, top, 4 * left, 4 * top));

				ctx.closePath();
				ctx.clip();
			} else {
				// Initial tests conclude that clearing the canvas using clearRect
				// is always faster than setting canvas.width = canvas.width
				// http://jsperf.com/clearrect-vs-setting-width/7
				ctx.clearRect(0, 0, this.size.width + 1, this.size.height + 1);
			}

			var param = { offset: new Point(0, 0) };
			for (var i = 0, l = this.layers.length; i < l; i++)
				Item.draw(this.layers[i], ctx, param);
			ctx.restore();

			// Draw the selection of the selected items in the document:
			if (this._selectedItemCount > 0) {
				ctx.save();
				ctx.strokeWidth = 1;
				// TODO: use Layer#color
				ctx.strokeStyle = ctx.fillStyle = '#009dec';
				param = { selection: true };
				Base.each(this._selectedItems, function(item) {
					item.draw(ctx, param);
				});
				ctx.restore();
			}
		}
	},

	redraw: function() {
		this.draw();
	}
});
<commit_msg>Add Document#getIndex().<commit_after>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * All rights reserved.
 */

var Document = this.Document = Base.extend({
	beans: true,

	initialize: function(canvas) {
		// Store reference to the currently active global paper scope:
		this._scope = paper;
		if (canvas && canvas instanceof HTMLCanvasElement) {
			this.canvas = canvas;
			if (canvas.attributes.resize) {
				// If the canvas has a fullscreen attribute,
				// resize the canvas to fill the window and resize it again
				// whenever the user resizes the window.
				// TODO: set the following styles on the body tag:
				// body {
				//	background: black;
				//	margin: 0;
				//	overflow: hidden;
				// }
				this._size = DomElement.getWindowSize()
						.subtract(DomElement.getOffset(this.canvas));
				this.canvas.width = this._size.width;
				this.canvas.height = this._size.height;
				var that = this;
				var offset = DomElement.getOffset(this.canvas);
				DomEvent.add(window, {
					resize: function(event) {
						// Only get canvas offset if it's not invisible (size is
						// 0, 0), as otherwise the offset would be wrong.
						if (!DomElement.getSize(that.canvas).equals([0, 0]))
							offset = DomElement.getOffset(that.canvas);
						that.setSize(DomElement.getWindowSize().subtract(offset));
						that.redraw();
					}
				});
			} else {
				this._size = Size.create(canvas.offsetWidth,
						canvas.offsetHeight);
			}
		} else {
			this._size = Size.read(arguments) || new Size(1024, 768);
			this.canvas = CanvasProvider.getCanvas(this._size);
		}
		// TODO: Currently we don't do anything with Document#bounds.
		// What does it mean to change the bounds of the document? (JP)
		this.bounds = Rectangle.create(0, 0, this._size.width,
				this._size.height);
		this.context = this.canvas.getContext('2d');
		// Push it onto this._scope.documents and set index:
		this._index = this._scope.documents.push(this) - 1;
		this.activate();
		this.layers = [];
		this.activeLayer = new Layer();
		this.setCurrentStyle(null);
		this.symbols = [];
		this.activeView = new DocumentView(this);
		this.views = [this.activeView];
		this._selectedItems = {};
		this._selectedItemCount = 0;
		// TODO: Test this on IE:
		if (this.canvas.attributes.stats) {
			this.stats = new Stats();
			// Align top-left to the canvas
			var element = this.stats.domElement,
				style = element.style,
				offset = DomElement.getOffset(this.canvas);
			style.position = 'absolute';
			style.left = offset.x + 'px';
			style.top = offset.y + 'px';
			document.body.appendChild(element);
		}
	},

	getSize: function() {
		return this._size;
	},

	setSize: function(size) {
		size = Size.read(arguments);
		if (this.canvas) {
			this.canvas.width = size.width;
			this.canvas.height = size.height;
		}
		this._size = size;
		this.bounds.setSize(size);
	},

	getCurrentStyle: function() {
		return this._currentStyle;
	},

	setCurrentStyle: function(style) {
		this._currentStyle = PathStyle.create(null, style);
	},

	getIndex: function() {
		return this._index;
	},

	activate: function() {
		// TODO: Remove indexOf()
		var index = this._scope.documents.indexOf(this);
		if (index != -1) {
			this._scope.document = this;
			return true;
		}
		return false;
	},

	getSelectedItems: function() {
		// TODO: return groups if their children are all selected,
		// and filter out their children from the list.
		// TODO: the order of these items should be that of their
		// drawing order.
		var items = [];
		Base.each(this._selectedItems, function(item) {
			items.push(item);
		});
		return items;
	},

	// TODO: implement setSelectedItems?

	_selectItem: function(item, select) {
		if (select) {
			this._selectedItemCount++;
			this._selectedItems[item.getId()] = item;
		} else {
			this._selectedItemCount--;
			delete this._selectedItems[item.getId()];
		}
	},

	/**
	 * Selects all items in the document.
	 */
	selectAll: function() {
		// TODO: is using for var i in good practice?
		// or should we use Base.each? (JP)
		for (var i = 0, l = this.layers.length; i < l; i++)
			this.layers[i].setSelected(true);
	},

	/**
	 * Deselects all selected items in the document.
	 */
	deselectAll: function() {
		// TODO: is using for var i in good practice?
		// or should we use Base.each? (JP)
		for (var i in this._selectedItems)
			this._selectedItems[i].setSelected(false);
	},

	draw: function() {
		if (this.canvas) {
			if (this.stats)
				this.stats.update();
			var ctx = this.context;
			ctx.save();

			// TODO: Remove dirty rectangle test code once it's actually
			// implemented.
			var testDirtyRects = false;
			if (testDirtyRects) {
				var left = this.size.width / 8,
					top = this.size.height / 8;

				function clear(rect) {
					ctx.clearRect(rect.x, rect.y, rect.width, rect.height);

					if (true) {
						ctx.moveTo(rect.x, rect.y);
						ctx.lineTo(rect.x + rect.width, rect.y);
						ctx.lineTo(rect.x + rect.width, rect.y + rect.height);
						ctx.lineTo(rect.x, rect.y + rect.height);
					}
				}

				ctx.beginPath();

				clear(Rectangle.create(left, top, 2 * left, 2 * top));
				clear(Rectangle.create(3 * left, 3 * top, 2 * left, 2 * top));

//				clear(Rectangle.create(left, top, 4 * left, 4 * top));

				ctx.closePath();
				ctx.clip();
			} else {
				// Initial tests conclude that clearing the canvas using clearRect
				// is always faster than setting canvas.width = canvas.width
				// http://jsperf.com/clearrect-vs-setting-width/7
				ctx.clearRect(0, 0, this.size.width + 1, this.size.height + 1);
			}

			var param = { offset: new Point(0, 0) };
			for (var i = 0, l = this.layers.length; i < l; i++)
				Item.draw(this.layers[i], ctx, param);
			ctx.restore();

			// Draw the selection of the selected items in the document:
			if (this._selectedItemCount > 0) {
				ctx.save();
				ctx.strokeWidth = 1;
				// TODO: use Layer#color
				ctx.strokeStyle = ctx.fillStyle = '#009dec';
				param = { selection: true };
				Base.each(this._selectedItems, function(item) {
					item.draw(ctx, param);
				});
				ctx.restore();
			}
		}
	},

	redraw: function() {
		this.draw();
	}
});
<|endoftext|>