Run prettier on app/jsx/ from files to login
This was achieved by turning the prettier rule on in .eslintrc.js then running: ./node_modules/eslint app/jsx/<folder_name>/**/*.js on each folder from the start directory to the end directory listed above. Test Plan: - Automated tests pass refs COREFE-347 flag = none Change-Id: I33fd9457836100499f9ef1c38fdf1d25f81d776b Reviewed-on: https://gerrit.instructure.com/212312 Tested-by: Jenkins Reviewed-by: Ryan Shaw <ryan@instructure.com> QA-Review: Ryan Shaw <ryan@instructure.com> Product-Review: Ryan Shaw <ryan@instructure.com>
This commit is contained in:
parent
c82d0c28a5
commit
3e38077e3f
|
@ -17,105 +17,111 @@
|
|||
*/
|
||||
|
||||
import React from 'react'
|
||||
import createReactClass from 'create-react-class';
|
||||
import createReactClass from 'create-react-class'
|
||||
import I18n from 'i18n!react_files'
|
||||
import Breadcrumbs from 'compiled/react_files/components/Breadcrumbs'
|
||||
import filesEnv from 'compiled/react_files/modules/filesEnv'
|
||||
import BreadcrumbCollapsedContainer from '../files/BreadcrumbCollapsedContainer'
|
||||
import BreadcrumbCollapsedContainer from './BreadcrumbCollapsedContainer'
|
||||
import splitAssetString from 'compiled/str/splitAssetString'
|
||||
|
||||
var MAX_CRUMB_WIDTH = 500
|
||||
var MIN_CRUMB_WIDTH = 80;
|
||||
const MAX_CRUMB_WIDTH = 500
|
||||
const MIN_CRUMB_WIDTH = 80
|
||||
|
||||
Breadcrumbs.renderSingleCrumb = function (folder, isLastCrumb, isRootCrumb) {
|
||||
const [contextType, contextId] = splitAssetString(this.props.contextAssetString, false);
|
||||
const isContextRoot = !folder ||
|
||||
!!(folder && (folder.get("context_type") || "").toLowerCase() === contextType &&
|
||||
(folder.get("context_id") || -1).toString() === contextId);
|
||||
const name = (isRootCrumb && isContextRoot) ? I18n.t('files', 'Files') : folder && (folder.get('custom_name') || folder.get('name'));
|
||||
Breadcrumbs.renderSingleCrumb = function(folder, isLastCrumb, isRootCrumb) {
|
||||
const [contextType, contextId] = splitAssetString(this.props.contextAssetString, false)
|
||||
const isContextRoot =
|
||||
!folder ||
|
||||
!!(
|
||||
folder &&
|
||||
(folder.get('context_type') || '').toLowerCase() === contextType &&
|
||||
(folder.get('context_id') || -1).toString() === contextId
|
||||
)
|
||||
const name =
|
||||
isRootCrumb && isContextRoot
|
||||
? I18n.t('files', 'Files')
|
||||
: folder && (folder.get('custom_name') || folder.get('name'))
|
||||
|
||||
return (
|
||||
<li key={name}>
|
||||
<a
|
||||
href={(isRootCrumb && isContextRoot) ? filesEnv.baseUrl : `${filesEnv.baseUrl}/folder/${(folder) ? folder.urlPath(): null}`}
|
||||
// only add title tooltips if there's a chance they could be ellipsized
|
||||
title={(this.state.maxCrumbWidth < 500) ? name : null}
|
||||
return (
|
||||
<li key={name}>
|
||||
<a
|
||||
href={
|
||||
isRootCrumb && isContextRoot
|
||||
? filesEnv.baseUrl
|
||||
: `${filesEnv.baseUrl}/folder/${folder ? folder.urlPath() : null}`
|
||||
}
|
||||
// only add title tooltips if there's a chance they could be ellipsized
|
||||
title={this.state.maxCrumbWidth < 500 ? name : null}
|
||||
>
|
||||
<span
|
||||
className="ellipsis"
|
||||
style={{maxWidth: isLastCrumb ? null : this.state.maxCrumbWidth}}
|
||||
>
|
||||
<span
|
||||
className='ellipsis'
|
||||
style={{maxWidth: (isLastCrumb) ? null : this.state.maxCrumbWidth}}
|
||||
>
|
||||
{name}
|
||||
{name}
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
||||
Breadcrumbs.renderDynamicCrumbs = function() {
|
||||
if (this.props.showingSearchResults) {
|
||||
return [
|
||||
this.renderSingleCrumb(null, !'isLastCrumb', !!'isRootCrumb'),
|
||||
<li key="searchLink">
|
||||
<a href="/search">
|
||||
<span className="ellipsis">
|
||||
{this.props.query.search_term &&
|
||||
I18n.t('search_results_for', 'search results for "%{search_term}"', {
|
||||
search_term: this.props.query.search_term
|
||||
})}
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
]
|
||||
} else {
|
||||
if (!this.props.rootTillCurrentFolder || !this.props.rootTillCurrentFolder.length) {
|
||||
return []
|
||||
}
|
||||
// Formerly, in CoffeeScript [...foldersInMiddle, lastFolder] = this.props.rootTillCurrentFolder
|
||||
const foldersInMiddle = this.props.rootTillCurrentFolder.slice(
|
||||
0,
|
||||
this.props.rootTillCurrentFolder.length - 1
|
||||
)
|
||||
const lastFolder = this.props.rootTillCurrentFolder[this.props.rootTillCurrentFolder.length - 1]
|
||||
|
||||
};
|
||||
|
||||
Breadcrumbs.renderDynamicCrumbs = function () {
|
||||
if (this.props.showingSearchResults) {
|
||||
if (this.state.maxCrumbWidth > MIN_CRUMB_WIDTH) {
|
||||
return this.props.rootTillCurrentFolder.map((folder, i) => {
|
||||
return this.renderSingleCrumb(folder, folder === lastFolder, i === 0)
|
||||
})
|
||||
} else {
|
||||
return [
|
||||
this.renderSingleCrumb(null, !'isLastCrumb', !!'isRootCrumb'),
|
||||
<li key='searchLink'>
|
||||
<a href="/search">
|
||||
<span className='ellipsis'>
|
||||
{this.props.query.search_term &&
|
||||
I18n.t('search_results_for', 'search results for "%{search_term}"', {search_term: this.props.query.search_term})
|
||||
}
|
||||
</span>
|
||||
<BreadcrumbCollapsedContainer foldersToContain={foldersInMiddle} />,
|
||||
this.renderSingleCrumb(lastFolder, true)
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Breadcrumbs.render = function() {
|
||||
return (
|
||||
<nav aria-label="breadcrumbs" role="navigation" id="breadcrumbs" ref="breadcrumbs">
|
||||
<ul>
|
||||
<li className="home">
|
||||
<a href="/">
|
||||
<i className="icon-home standalone-icon" title={this.state.homeName}>
|
||||
<span className="screenreader-only">{this.state.homeName}</span>
|
||||
</i>
|
||||
</a>
|
||||
</li>
|
||||
];
|
||||
} else {
|
||||
if (!this.props.rootTillCurrentFolder || !this.props.rootTillCurrentFolder.length) {
|
||||
return [];
|
||||
}
|
||||
// Formerly, in CoffeeScript [...foldersInMiddle, lastFolder] = this.props.rootTillCurrentFolder
|
||||
var foldersInMiddle = this.props.rootTillCurrentFolder.slice(0, this.props.rootTillCurrentFolder.length - 1)
|
||||
var lastFolder = this.props.rootTillCurrentFolder[this.props.rootTillCurrentFolder.length - 1]
|
||||
<li>
|
||||
<a href={this.state.contextUrl}>
|
||||
<span className="ellipsible">{this.state.contextName}</span>
|
||||
</a>
|
||||
</li>
|
||||
{this.renderDynamicCrumbs()}
|
||||
</ul>
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
|
||||
if (this.state.maxCrumbWidth > MIN_CRUMB_WIDTH) {
|
||||
return this.props.rootTillCurrentFolder.map((folder, i) => {
|
||||
return this.renderSingleCrumb(folder, folder === lastFolder, i === 0)
|
||||
});
|
||||
} else {
|
||||
return [
|
||||
<BreadcrumbCollapsedContainer foldersToContain={foldersInMiddle} />,
|
||||
this.renderSingleCrumb(lastFolder, true)
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Breadcrumbs.render = function () {
|
||||
return (
|
||||
<nav
|
||||
aria-label='breadcrumbs'
|
||||
role='navigation'
|
||||
id='breadcrumbs'
|
||||
ref='breadcrumbs'
|
||||
>
|
||||
<ul>
|
||||
<li className='home'>
|
||||
<a href='/'>
|
||||
<i className='icon-home standalone-icon' title={this.state.homeName}>
|
||||
<span className='screenreader-only'>{this.state.homeName}</span>
|
||||
</i>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href={this.state.contextUrl}>
|
||||
<span className='ellipsible'>
|
||||
{this.state.contextName}
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
{this.renderDynamicCrumbs()}
|
||||
</ul>
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
|
||||
export default createReactClass(Breadcrumbs);
|
||||
export default createReactClass(Breadcrumbs)
|
||||
|
|
|
@ -19,103 +19,103 @@
|
|||
import $ from 'jquery'
|
||||
import I18n from 'i18n!react_files'
|
||||
import React from 'react'
|
||||
import createReactClass from 'create-react-class';
|
||||
import createReactClass from 'create-react-class'
|
||||
import classnames from 'classnames'
|
||||
import ColumnHeaders from 'compiled/react_files/components/ColumnHeaders'
|
||||
|
||||
ColumnHeaders.renderColumns = function (sort, order) {
|
||||
return this.columns.map((column) => {
|
||||
if (column.property === 'usage_rights' && !this.props.usageRightsRequiredForContext) {
|
||||
return;
|
||||
}
|
||||
var isSortedCol = sort === column.property;
|
||||
if (this.props.query.sort && isSortedCol && order) {
|
||||
const direction = order === 'asc' ? 'ascending' : 'descending'
|
||||
$.screenReaderFlashMessage(I18n.t("Sorted %{direction} by %{columnName}",
|
||||
{direction, columnName: column.displayName}))
|
||||
}
|
||||
var columnClassNameObj = {
|
||||
"current-filter": isSortedCol
|
||||
};
|
||||
columnClassNameObj[column.className] = true;
|
||||
var columnClassName = classnames(columnClassNameObj);
|
||||
var linkClassName = classnames({
|
||||
'visible-desktop': column.displayNameShort,
|
||||
'ef-usage-rights-col-offset': (column.property === 'usage_rights')
|
||||
});
|
||||
ColumnHeaders.renderColumns = function(sort, order) {
|
||||
return this.columns.map(column => {
|
||||
if (column.property === 'usage_rights' && !this.props.usageRightsRequiredForContext) {
|
||||
return
|
||||
}
|
||||
const isSortedCol = sort === column.property
|
||||
if (this.props.query.sort && isSortedCol && order) {
|
||||
const direction = order === 'asc' ? 'ascending' : 'descending'
|
||||
$.screenReaderFlashMessage(
|
||||
I18n.t('Sorted %{direction} by %{columnName}', {direction, columnName: column.displayName})
|
||||
)
|
||||
}
|
||||
const columnClassNameObj = {
|
||||
'current-filter': isSortedCol
|
||||
}
|
||||
columnClassNameObj[column.className] = true
|
||||
const columnClassName = classnames(columnClassNameObj)
|
||||
const linkClassName = classnames({
|
||||
'visible-desktop': column.displayNameShort,
|
||||
'ef-usage-rights-col-offset': column.property === 'usage_rights'
|
||||
})
|
||||
|
||||
const encoded_path = this.props.pathname.split('/').map((part) => window.encodeURIComponent(part)).join('/');
|
||||
const href = `${encoded_path}?${$.param(this.queryParamsFor(this.props.query, column.property))}`;
|
||||
const linkProps = {
|
||||
className: 'ef-plain-link',
|
||||
href
|
||||
};
|
||||
var linkText;
|
||||
if (column.property === 'select') {
|
||||
linkText = <span className='screenreader-only'>{column.displayName}</span>;
|
||||
} else if (column.property == 'usage_rights') {
|
||||
linkText = (<i className='icon-files-copyright'>
|
||||
<span className='screenreader-only'>{column.displayName}</span>
|
||||
</i>
|
||||
);
|
||||
} else {
|
||||
linkText = column.displayName;
|
||||
}
|
||||
const encoded_path = this.props.pathname
|
||||
.split('/')
|
||||
.map(part => window.encodeURIComponent(part))
|
||||
.join('/')
|
||||
const href = `${encoded_path}?${$.param(
|
||||
this.queryParamsFor(this.props.query, column.property)
|
||||
)}`
|
||||
const linkProps = {
|
||||
className: 'ef-plain-link',
|
||||
href
|
||||
}
|
||||
let linkText
|
||||
if (column.property === 'select') {
|
||||
linkText = <span className="screenreader-only">{column.displayName}</span>
|
||||
} else if (column.property == 'usage_rights') {
|
||||
linkText = (
|
||||
<i className="icon-files-copyright">
|
||||
<span className="screenreader-only">{column.displayName}</span>
|
||||
</i>
|
||||
)
|
||||
} else {
|
||||
linkText = column.displayName
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
key={column.property}
|
||||
className={columnClassName}
|
||||
role='columnheader'
|
||||
aria-sort={{asc: 'ascending', desc: 'descending'}[isSortedCol && order] || 'none'}
|
||||
>
|
||||
<a {...linkProps}>
|
||||
<span className={linkClassName}>
|
||||
{linkText}
|
||||
return (
|
||||
<div
|
||||
key={column.property}
|
||||
className={columnClassName}
|
||||
role="columnheader"
|
||||
aria-sort={{asc: 'ascending', desc: 'descending'}[isSortedCol && order] || 'none'}
|
||||
>
|
||||
<a {...linkProps}>
|
||||
<span className={linkClassName}>{linkText}</span>
|
||||
{column.displayNameShort && (
|
||||
<span className="hidden-desktop">{column.displayNameShort}</span>
|
||||
)}
|
||||
{isSortedCol && order === 'asc' && (
|
||||
<i className="icon-mini-arrow-up">
|
||||
<span className="screenreader-only">
|
||||
{I18n.t('sorted_ascending', 'Sorted Ascending')}
|
||||
</span>
|
||||
{column.displayNameShort && (
|
||||
<span className='hidden-desktop'>{column.displayNameShort}</span>
|
||||
)}
|
||||
{isSortedCol && order === 'asc' && (
|
||||
<i className='icon-mini-arrow-up'>
|
||||
<span className='screenreader-only'>
|
||||
{I18n.t('sorted_ascending', "Sorted Ascending")}
|
||||
</span>
|
||||
</i>
|
||||
)}
|
||||
{isSortedCol && order === 'desc' && (
|
||||
<i className='icon-mini-arrow-down'>
|
||||
<span className='screenreader-only'>
|
||||
{I18n.t('sorted_desending', "Sorted Descending")}
|
||||
</span>
|
||||
</i>
|
||||
)}
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
})
|
||||
}
|
||||
</i>
|
||||
)}
|
||||
{isSortedCol && order === 'desc' && (
|
||||
<i className="icon-mini-arrow-down">
|
||||
<span className="screenreader-only">
|
||||
{I18n.t('sorted_desending', 'Sorted Descending')}
|
||||
</span>
|
||||
</i>
|
||||
)}
|
||||
</a>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
ColumnHeaders.render = function () {
|
||||
const sort = this.props.query.sort || 'name';
|
||||
const order = this.props.query.order || 'asc';
|
||||
ColumnHeaders.render = function() {
|
||||
const sort = this.props.query.sort || 'name'
|
||||
const order = this.props.query.order || 'asc'
|
||||
|
||||
return (
|
||||
<header className='ef-directory-header' role='row'>
|
||||
<div className='screenreader-only' role='columnheader'>
|
||||
{I18n.t('Select')}
|
||||
</div>
|
||||
{this.renderColumns(sort, order)}
|
||||
<div
|
||||
className='ef-links-col'
|
||||
role='columnheader'
|
||||
>
|
||||
<span className='screenreader-only'>
|
||||
{I18n.t('Actions')}
|
||||
</span>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<header className="ef-directory-header" role="row">
|
||||
<div className="screenreader-only" role="columnheader">
|
||||
{I18n.t('Select')}
|
||||
</div>
|
||||
{this.renderColumns(sort, order)}
|
||||
<div className="ef-links-col" role="columnheader">
|
||||
<span className="screenreader-only">{I18n.t('Actions')}</span>
|
||||
</div>
|
||||
</header>
|
||||
)
|
||||
}
|
||||
|
||||
export default createReactClass(ColumnHeaders);
|
||||
export default createReactClass(ColumnHeaders)
|
||||
|
|
|
@ -17,36 +17,28 @@
|
|||
*/
|
||||
|
||||
import React from 'react'
|
||||
import createReactClass from 'create-react-class';
|
||||
import createReactClass from 'create-react-class'
|
||||
import classnames from 'classnames'
|
||||
import CurrentUploads from 'compiled/react_files/components/CurrentUploads'
|
||||
import UploadProgress from '../files/UploadProgress'
|
||||
import UploadProgress from './UploadProgress'
|
||||
|
||||
CurrentUploads.renderUploadProgress = function () {
|
||||
if (this.state.currentUploads.length) {
|
||||
var progessComponents = this.state.currentUploads.map((uploader) => {
|
||||
return <UploadProgress uploader={uploader} key={uploader.getFileName()} />
|
||||
});
|
||||
return (
|
||||
<div className='current_uploads__uploaders'>
|
||||
{progessComponents}
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
CurrentUploads.renderUploadProgress = function() {
|
||||
if (this.state.currentUploads.length) {
|
||||
const progessComponents = this.state.currentUploads.map(uploader => {
|
||||
return <UploadProgress uploader={uploader} key={uploader.getFileName()} />
|
||||
})
|
||||
return <div className="current_uploads__uploaders">{progessComponents}</div>
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
CurrentUploads.render = function () {
|
||||
var classes = classnames({
|
||||
'current_uploads': this.state.currentUploads.length
|
||||
});
|
||||
CurrentUploads.render = function() {
|
||||
const classes = classnames({
|
||||
current_uploads: this.state.currentUploads.length
|
||||
})
|
||||
|
||||
return (
|
||||
<div className={classes}>
|
||||
{this.renderUploadProgress()}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
return <div className={classes}>{this.renderUploadProgress()}</div>
|
||||
}
|
||||
|
||||
export default createReactClass(CurrentUploads);
|
||||
export default createReactClass(CurrentUploads)
|
||||
|
|
|
@ -20,7 +20,7 @@ import React from 'react'
|
|||
import PropTypes from 'prop-types'
|
||||
import customPropTypes from 'compiled/react_files/modules/customPropTypes'
|
||||
import filesEnv from 'compiled/react_files/modules/filesEnv'
|
||||
import FilesystemObjectThumbnail from '../files/FilesystemObjectThumbnail'
|
||||
import FilesystemObjectThumbnail from './FilesystemObjectThumbnail'
|
||||
|
||||
const MAX_THUMBNAILS_TO_SHOW = 5
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import FilesystemObjectThumbnail from '../files/FilesystemObjectThumbnail'
|
||||
import FilesystemObjectThumbnail from './FilesystemObjectThumbnail'
|
||||
import customPropTypes from 'compiled/react_files/modules/customPropTypes'
|
||||
|
||||
const MAX_THUMBNAILS_TO_SHOW = 10
|
||||
|
|
|
@ -53,9 +53,7 @@ export default class FilePreview extends React.PureComponent {
|
|||
|
||||
componentWillMount() {
|
||||
if (this.props.isOpen) {
|
||||
this.getItemsToView(this.props, items =>
|
||||
this.setState(this.stateProperties(items))
|
||||
)
|
||||
this.getItemsToView(this.props, items => this.setState(this.stateProperties(items)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,7 +104,10 @@ export default class FilePreview extends React.PureComponent {
|
|||
}
|
||||
|
||||
getItemsToView = (props, cb) => {
|
||||
if (typeof cb !== 'function') throw new Error("getItemsToView(props: obj, callback: fn) requires `callback` to be a function")
|
||||
if (typeof cb !== 'function')
|
||||
throw new Error(
|
||||
'getItemsToView(props: obj, callback: fn) requires `callback` to be a function'
|
||||
)
|
||||
// Sets up our collection that we will be using.
|
||||
let initialItem = null
|
||||
const onlyIdsToPreview = props.query.only_preview && props.query.only_preview.split(',')
|
||||
|
@ -182,10 +183,10 @@ export default class FilePreview extends React.PureComponent {
|
|||
)
|
||||
}
|
||||
|
||||
stateProperties = (items) => ({
|
||||
stateProperties = items => ({
|
||||
initialItem: items.initialItem,
|
||||
displayedItem: items.initialItem,
|
||||
otherItems: items.otherItems,
|
||||
otherItems: items.otherItems
|
||||
})
|
||||
|
||||
renderArrowLink = direction => {
|
||||
|
@ -269,21 +270,20 @@ export default class FilePreview extends React.PureComponent {
|
|||
{this.state.initialItem ? this.state.initialItem.displayName() : ''}
|
||||
</h1>
|
||||
<div className="ef-file-preview-header-buttons">
|
||||
{this.state.displayedItem &&
|
||||
!this.state.displayedItem.get('locked_for_user') && (
|
||||
<a
|
||||
href={this.state.displayedItem.get('url')}
|
||||
download
|
||||
className="ef-file-preview-header-download ef-file-preview-button"
|
||||
>
|
||||
<i className="icon-download" />
|
||||
<span className="hidden-phone">{` ${I18n.t('Download')}`}</span>
|
||||
</a>
|
||||
)}
|
||||
{this.state.displayedItem && !this.state.displayedItem.get('locked_for_user') && (
|
||||
<a
|
||||
href={this.state.displayedItem.get('url')}
|
||||
download
|
||||
className="ef-file-preview-header-download ef-file-preview-button"
|
||||
>
|
||||
<i className="icon-download" />
|
||||
<span className="hidden-phone">{` ${I18n.t('Download')}`}</span>
|
||||
</a>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
className={showInfoPanelClasses}
|
||||
ref={e => this.infoButton = e}
|
||||
ref={e => (this.infoButton = e)}
|
||||
onClick={this.toggle('showInfoPanel')}
|
||||
>
|
||||
{/* Wrap content in a div because firefox doesn't support display: flex on buttons */}
|
||||
|
@ -295,7 +295,7 @@ export default class FilePreview extends React.PureComponent {
|
|||
<button
|
||||
type="button"
|
||||
onClick={preventDefault(this.closeModal)}
|
||||
ref={e => this.closeButton = e}
|
||||
ref={e => (this.closeButton = e)}
|
||||
className="ef-file-preview-header-close ef-file-preview-button"
|
||||
>
|
||||
<i className="icon-end" />
|
||||
|
|
|
@ -17,140 +17,126 @@
|
|||
*/
|
||||
|
||||
import React from 'react'
|
||||
import createReactClass from 'create-react-class';
|
||||
import createReactClass from 'create-react-class'
|
||||
import FileRenameForm from 'compiled/react_files/components/FileRenameForm'
|
||||
import Modal from '../shared/modal'
|
||||
import ModalContent from '../shared/modal-content'
|
||||
import ModalButtons from '../shared/modal-buttons'
|
||||
import I18n from 'i18n!file_rename_form'
|
||||
|
||||
FileRenameForm.buildContent = function () {
|
||||
var nameToUse = this.state.fileOptions.name || this.state.fileOptions.file.name;
|
||||
var buildContentToRender;
|
||||
if (!this.state.isEditing && !this.state.fileOptions.cannotOverwrite) {
|
||||
buildContentToRender = (
|
||||
<div ref='bodyContent'>
|
||||
<p id='renameFileMessage'>
|
||||
{I18n.t('An item named "%{name}" already exists in this location. Do you want to replace the existing file?', {name: nameToUse})}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
var renameMessage;
|
||||
if (this.state.fileOptions.cannotOverwrite) {
|
||||
renameMessage = I18n.t('A locked item named "%{name}" already exists in this location. Please enter a new name.', {name: nameToUse});
|
||||
} else {
|
||||
renameMessage = I18n.t('Change "%{name}" to', {name: nameToUse});
|
||||
}
|
||||
|
||||
buildContentToRender = (
|
||||
<div ref='bodyContent'>
|
||||
<p>
|
||||
{renameMessage}
|
||||
</p>
|
||||
<form onSubmit={this.handleFormSubmit}>
|
||||
<label className='file-rename-form__form-label'>
|
||||
{I18n.t('Name')}
|
||||
</label>
|
||||
<input
|
||||
className='input-block-level'
|
||||
type='text'
|
||||
defaultValue={nameToUse}
|
||||
ref='newName'
|
||||
>
|
||||
</input>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return buildContentToRender;
|
||||
};
|
||||
|
||||
FileRenameForm.buildButtons = function () {
|
||||
var buildButtonsToRender;
|
||||
if (this.state.fileOptions.cannotOverwrite) {
|
||||
buildButtonsToRender = (
|
||||
[
|
||||
<button
|
||||
key='commitChangeBtn'
|
||||
ref='commitChangeBtn'
|
||||
className='btn btn-primary'
|
||||
onClick={this.handleChangeClick}
|
||||
>
|
||||
{I18n.t('Change')}
|
||||
</button>
|
||||
]
|
||||
);
|
||||
} else if (!this.state.isEditing) {
|
||||
buildButtonsToRender = (
|
||||
[
|
||||
<button
|
||||
key='renameBtn'
|
||||
ref='renameBtn'
|
||||
className='btn btn-default'
|
||||
onClick={this.handleRenameClick}
|
||||
>
|
||||
{I18n.t('Change Name')}
|
||||
</button>
|
||||
,
|
||||
<button
|
||||
key='replaceBtn'
|
||||
ref='replaceBtn'
|
||||
className='btn btn-primary'
|
||||
onClick={this.handleReplaceClick}
|
||||
>
|
||||
{I18n.t('Replace')}
|
||||
</button>
|
||||
]
|
||||
);
|
||||
} else {
|
||||
buildButtonsToRender = (
|
||||
[
|
||||
<button
|
||||
key='backBtn'
|
||||
ref='backBtn'
|
||||
className='btn btn-default'
|
||||
onClick={this.handleBackClick}
|
||||
>
|
||||
{I18n.t('Back')}
|
||||
</button>
|
||||
,
|
||||
<button
|
||||
key='commitChangeBtn'
|
||||
ref='commitChangeBtn'
|
||||
className='btn btn-primary'
|
||||
onClick={this.handleChangeClick}
|
||||
>
|
||||
{I18n.t('Change')}
|
||||
</button>
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
return buildButtonsToRender;
|
||||
};
|
||||
|
||||
FileRenameForm.render = function () {
|
||||
return (
|
||||
<div>
|
||||
<Modal
|
||||
className='ReactModal__Content--canvas ReactModal__Content--mini-modal'
|
||||
ref='canvasModal'
|
||||
isOpen={this.props.fileOptions}
|
||||
title={I18n.t('Copy')}
|
||||
onRequestClose={this.props.onClose}
|
||||
closeWithX={this.props.closeWithX}
|
||||
>
|
||||
<ModalContent>
|
||||
{this.buildContent()}
|
||||
<ModalButtons>
|
||||
{this.buildButtons()}
|
||||
</ModalButtons>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
FileRenameForm.buildContent = function() {
|
||||
const nameToUse = this.state.fileOptions.name || this.state.fileOptions.file.name
|
||||
let buildContentToRender
|
||||
if (!this.state.isEditing && !this.state.fileOptions.cannotOverwrite) {
|
||||
buildContentToRender = (
|
||||
<div ref="bodyContent">
|
||||
<p id="renameFileMessage">
|
||||
{I18n.t(
|
||||
'An item named "%{name}" already exists in this location. Do you want to replace the existing file?',
|
||||
{name: nameToUse}
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
)
|
||||
} else {
|
||||
let renameMessage
|
||||
if (this.state.fileOptions.cannotOverwrite) {
|
||||
renameMessage = I18n.t(
|
||||
'A locked item named "%{name}" already exists in this location. Please enter a new name.',
|
||||
{name: nameToUse}
|
||||
)
|
||||
} else {
|
||||
renameMessage = I18n.t('Change "%{name}" to', {name: nameToUse})
|
||||
}
|
||||
|
||||
export default createReactClass(FileRenameForm);
|
||||
buildContentToRender = (
|
||||
<div ref="bodyContent">
|
||||
<p>{renameMessage}</p>
|
||||
<form onSubmit={this.handleFormSubmit}>
|
||||
<label className="file-rename-form__form-label">{I18n.t('Name')}</label>
|
||||
<input className="input-block-level" type="text" defaultValue={nameToUse} ref="newName" />
|
||||
</form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return buildContentToRender
|
||||
}
|
||||
|
||||
FileRenameForm.buildButtons = function() {
|
||||
let buildButtonsToRender
|
||||
if (this.state.fileOptions.cannotOverwrite) {
|
||||
buildButtonsToRender = [
|
||||
<button
|
||||
key="commitChangeBtn"
|
||||
ref="commitChangeBtn"
|
||||
className="btn btn-primary"
|
||||
onClick={this.handleChangeClick}
|
||||
>
|
||||
{I18n.t('Change')}
|
||||
</button>
|
||||
]
|
||||
} else if (!this.state.isEditing) {
|
||||
buildButtonsToRender = [
|
||||
<button
|
||||
key="renameBtn"
|
||||
ref="renameBtn"
|
||||
className="btn btn-default"
|
||||
onClick={this.handleRenameClick}
|
||||
>
|
||||
{I18n.t('Change Name')}
|
||||
</button>,
|
||||
<button
|
||||
key="replaceBtn"
|
||||
ref="replaceBtn"
|
||||
className="btn btn-primary"
|
||||
onClick={this.handleReplaceClick}
|
||||
>
|
||||
{I18n.t('Replace')}
|
||||
</button>
|
||||
]
|
||||
} else {
|
||||
buildButtonsToRender = [
|
||||
<button
|
||||
key="backBtn"
|
||||
ref="backBtn"
|
||||
className="btn btn-default"
|
||||
onClick={this.handleBackClick}
|
||||
>
|
||||
{I18n.t('Back')}
|
||||
</button>,
|
||||
<button
|
||||
key="commitChangeBtn"
|
||||
ref="commitChangeBtn"
|
||||
className="btn btn-primary"
|
||||
onClick={this.handleChangeClick}
|
||||
>
|
||||
{I18n.t('Change')}
|
||||
</button>
|
||||
]
|
||||
}
|
||||
|
||||
return buildButtonsToRender
|
||||
}
|
||||
|
||||
FileRenameForm.render = function() {
|
||||
return (
|
||||
<div>
|
||||
<Modal
|
||||
className="ReactModal__Content--canvas ReactModal__Content--mini-modal"
|
||||
ref="canvasModal"
|
||||
isOpen={this.props.fileOptions}
|
||||
title={I18n.t('Copy')}
|
||||
onRequestClose={this.props.onClose}
|
||||
closeWithX={this.props.closeWithX}
|
||||
>
|
||||
<ModalContent>
|
||||
{this.buildContent()}
|
||||
<ModalButtons>{this.buildButtons()}</ModalButtons>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default createReactClass(FileRenameForm)
|
||||
|
|
|
@ -23,10 +23,10 @@ import page from 'page'
|
|||
import FilesApp from 'compiled/react_files/components/FilesApp'
|
||||
import filesEnv from 'compiled/react_files/modules/filesEnv'
|
||||
import I18n from 'i18n!react_files'
|
||||
import Breadcrumbs from '../files/Breadcrumbs'
|
||||
import FolderTree from '../files/FolderTree'
|
||||
import FilesUsage from '../files/FilesUsage'
|
||||
import Toolbar from '../files/Toolbar'
|
||||
import Breadcrumbs from './Breadcrumbs'
|
||||
import FolderTree from './FolderTree'
|
||||
import FilesUsage from './FilesUsage'
|
||||
import Toolbar from './Toolbar'
|
||||
|
||||
FilesApp.previewItem = function(item) {
|
||||
this.clearSelectedItems(() => {
|
||||
|
|
|
@ -17,44 +17,44 @@
|
|||
*/
|
||||
|
||||
import React from 'react'
|
||||
import createReactClass from 'create-react-class';
|
||||
import createReactClass from 'create-react-class'
|
||||
import I18n from 'i18n!react_files'
|
||||
import FilesUsage from 'compiled/react_files/components/FilesUsage'
|
||||
import friendlyBytes from 'compiled/util/friendlyBytes'
|
||||
|
||||
FilesUsage.render = function () {
|
||||
if (this.state) {
|
||||
const percentUsed = Math.round(this.state.quota_used / this.state.quota * 100);
|
||||
const label = I18n.t('%{percentUsed} of %{bytesAvailable} used', {
|
||||
percentUsed: I18n.n(percentUsed, { percentage: true }),
|
||||
bytesAvailable: friendlyBytes(this.state.quota)
|
||||
});
|
||||
const srLabel = I18n.t('Files Quota: %{percentUsed} of %{bytesAvailable} used', {
|
||||
percentUsed: I18n.n(percentUsed, { percentage: true }),
|
||||
bytesAvailable: friendlyBytes(this.state.quota)
|
||||
});
|
||||
return (
|
||||
<div className='grid-row ef-quota-usage'>
|
||||
<div className='col-xs-3'>
|
||||
<div ref='container' className='progress-bar__bar-container' aria-hidden={true}>
|
||||
<div
|
||||
ref='bar'
|
||||
className='progress-bar__bar'
|
||||
style={{
|
||||
width: Math.min(percentUsed, 100) + '%'
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
FilesUsage.render = function() {
|
||||
if (this.state) {
|
||||
const percentUsed = Math.round((this.state.quota_used / this.state.quota) * 100)
|
||||
const label = I18n.t('%{percentUsed} of %{bytesAvailable} used', {
|
||||
percentUsed: I18n.n(percentUsed, {percentage: true}),
|
||||
bytesAvailable: friendlyBytes(this.state.quota)
|
||||
})
|
||||
const srLabel = I18n.t('Files Quota: %{percentUsed} of %{bytesAvailable} used', {
|
||||
percentUsed: I18n.n(percentUsed, {percentage: true}),
|
||||
bytesAvailable: friendlyBytes(this.state.quota)
|
||||
})
|
||||
return (
|
||||
<div className="grid-row ef-quota-usage">
|
||||
<div className="col-xs-3">
|
||||
<div ref="container" className="progress-bar__bar-container" aria-hidden>
|
||||
<div
|
||||
ref="bar"
|
||||
className="progress-bar__bar"
|
||||
style={{
|
||||
width: Math.min(percentUsed, 100) + '%'
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className='col-xs-9' style={{paddingLeft: '0px'}} aria-hidden={true}>
|
||||
{label}
|
||||
</div>
|
||||
<div className='screenreader-only'>{srLabel}</div>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return <div />;
|
||||
}
|
||||
};
|
||||
<div className="col-xs-9" style={{paddingLeft: '0px'}} aria-hidden>
|
||||
{label}
|
||||
</div>
|
||||
<div className="screenreader-only">{srLabel}</div>
|
||||
</div>
|
||||
)
|
||||
} else {
|
||||
return <div />
|
||||
}
|
||||
}
|
||||
|
||||
export default createReactClass(FilesUsage);
|
||||
export default createReactClass(FilesUsage)
|
||||
|
|
|
@ -17,31 +17,34 @@
|
|||
*/
|
||||
|
||||
import React from 'react'
|
||||
import createReactClass from 'create-react-class';
|
||||
import createReactClass from 'create-react-class'
|
||||
import Folder from 'compiled/models/Folder'
|
||||
import mimeClass from 'compiled/util/mimeClass'
|
||||
import FilesystemObjectThumbnail from 'compiled/react_files/components/FilesystemObjectThumbnail'
|
||||
|
||||
FilesystemObjectThumbnail.render = function () {
|
||||
var additionalClassName = this.props.className ? this.props.className : '';
|
||||
FilesystemObjectThumbnail.render = function() {
|
||||
const additionalClassName = this.props.className ? this.props.className : ''
|
||||
|
||||
if (this.state.thumbnail_url) {
|
||||
return (
|
||||
<span
|
||||
className={`media-object ef-thumbnail FilesystemObjectThumbnail ${additionalClassName}`}
|
||||
style = { {backgroundImage: `url('${this.state.thumbnail_url}')`} }
|
||||
></span>
|
||||
);
|
||||
} else {
|
||||
var thumbnailClassName = (this.props.model instanceof Folder) ?
|
||||
(this.props.model.get('for_submissions') ? 'folder-locked' : 'folder') :
|
||||
mimeClass(this.props.model.get('content-type'));
|
||||
return (
|
||||
<i
|
||||
className={`media-object ef-big-icon FilesystemObjectThumbnail mimeClass-${thumbnailClassName} ${additionalClassName}`}
|
||||
></i>
|
||||
);
|
||||
}
|
||||
};
|
||||
if (this.state.thumbnail_url) {
|
||||
return (
|
||||
<span
|
||||
className={`media-object ef-thumbnail FilesystemObjectThumbnail ${additionalClassName}`}
|
||||
style={{backgroundImage: `url('${this.state.thumbnail_url}')`}}
|
||||
/>
|
||||
)
|
||||
} else {
|
||||
const thumbnailClassName =
|
||||
this.props.model instanceof Folder
|
||||
? this.props.model.get('for_submissions')
|
||||
? 'folder-locked'
|
||||
: 'folder'
|
||||
: mimeClass(this.props.model.get('content-type'))
|
||||
return (
|
||||
<i
|
||||
className={`media-object ef-big-icon FilesystemObjectThumbnail mimeClass-${thumbnailClassName} ${additionalClassName}`}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default createReactClass(FilesystemObjectThumbnail);
|
||||
export default createReactClass(FilesystemObjectThumbnail)
|
||||
|
|
|
@ -22,11 +22,11 @@ import createReactClass from 'create-react-class'
|
|||
import FolderChild from 'compiled/react_files/components/FolderChild'
|
||||
import filesEnv from 'compiled/react_files/modules/filesEnv'
|
||||
import classnames from 'classnames'
|
||||
import ItemCog from '../files/ItemCog'
|
||||
import ItemCog from './ItemCog'
|
||||
import PublishCloud from '../shared/PublishCloud'
|
||||
import MasterCourseLock from '../shared/MasterCourseLock'
|
||||
import FilesystemObjectThumbnail from '../files/FilesystemObjectThumbnail'
|
||||
import UsageRightsIndicator from '../files/UsageRightsIndicator'
|
||||
import FilesystemObjectThumbnail from './FilesystemObjectThumbnail'
|
||||
import UsageRightsIndicator from './UsageRightsIndicator'
|
||||
import Folder from 'compiled/models/Folder'
|
||||
import preventDefault from 'compiled/fn/preventDefault'
|
||||
import FriendlyDatetime from '../shared/FriendlyDatetime'
|
||||
|
@ -104,7 +104,7 @@ FolderChild.renderEditingState = function() {
|
|||
}
|
||||
defaultValue={this.props.model.displayName()}
|
||||
maxLength="255"
|
||||
onKeyUp={(event) => {
|
||||
onKeyUp={event => {
|
||||
if (event.keyCode === 27) {
|
||||
this.cancelEditingName()
|
||||
}
|
||||
|
@ -192,7 +192,9 @@ FolderChild.renderUsageRightsIndicator = function() {
|
|||
|
||||
FolderChild.render = function() {
|
||||
const user = this.props.model.get('user') || {}
|
||||
const selectCheckboxLabel = I18n.t('Select %{itemName}', {itemName: this.props.model.displayName()})
|
||||
const selectCheckboxLabel = I18n.t('Select %{itemName}', {
|
||||
itemName: this.props.model.displayName()
|
||||
})
|
||||
const keyboardCheckboxClass = classnames({
|
||||
'screenreader-only': this.state.hideKeyboardCheck,
|
||||
'multiselectable-toggler': true
|
||||
|
|
|
@ -17,17 +17,11 @@
|
|||
*/
|
||||
|
||||
import React from 'react'
|
||||
import createReactClass from 'create-react-class';
|
||||
import createReactClass from 'create-react-class'
|
||||
import FolderTree from 'compiled/react_files/components/FolderTree'
|
||||
|
||||
FolderTree.render = function () {
|
||||
return (
|
||||
<div
|
||||
className='ef-folder-list'
|
||||
ref='FolderTreeHolder'
|
||||
>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
FolderTree.render = function() {
|
||||
return <div className="ef-folder-list" ref="FolderTreeHolder" />
|
||||
}
|
||||
|
||||
export default createReactClass(FolderTree);
|
||||
export default createReactClass(FolderTree)
|
||||
|
|
|
@ -25,8 +25,8 @@ import customPropTypes from 'compiled/react_files/modules/customPropTypes'
|
|||
import filesEnv from 'compiled/react_files/modules/filesEnv'
|
||||
import File from 'compiled/models/File'
|
||||
import Folder from 'compiled/models/Folder'
|
||||
import UsageRightsDialog from '../files/UsageRightsDialog'
|
||||
import openMoveDialog from '../files/utils/openMoveDialog'
|
||||
import UsageRightsDialog from './UsageRightsDialog'
|
||||
import openMoveDialog from './utils/openMoveDialog'
|
||||
import downloadStuffAsAZip from 'compiled/react_files/utils/downloadStuffAsAZip'
|
||||
import deleteStuff from 'compiled/react_files/utils/deleteStuff'
|
||||
import $ from 'jquery'
|
||||
|
|
|
@ -18,74 +18,70 @@
|
|||
|
||||
import I18n from 'i18n!react_files'
|
||||
import React from 'react'
|
||||
import createReactClass from 'create-react-class';
|
||||
import createReactClass from 'create-react-class'
|
||||
import MoveDialog from 'compiled/react_files/components/MoveDialog'
|
||||
import Modal from '../shared/modal'
|
||||
import ModalContent from '../shared/modal-content'
|
||||
import ModalButtons from '../shared/modal-buttons'
|
||||
import BBTreeBrowser from '../files/BBTreeBrowser'
|
||||
import BBTreeBrowser from './BBTreeBrowser'
|
||||
import classnames from 'classnames'
|
||||
|
||||
MoveDialog.renderMoveButton = function () {
|
||||
const buttonClassNames = classnames({
|
||||
'disabled': !this.state.destinationFolder,
|
||||
'btn': true,
|
||||
'btn-primary': true
|
||||
});
|
||||
if (this.state.isCopyingFile) {
|
||||
return (
|
||||
<button
|
||||
type='submit'
|
||||
aria-disabled={!this.state.destinationFolder}
|
||||
className={buttonClassNames}
|
||||
data-text-while-loading={I18n.t('Copying...')}
|
||||
>
|
||||
{I18n.t('Copy to Folder')}
|
||||
</button>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<button
|
||||
type='submit'
|
||||
aria-disabled={!this.state.destinationFolder}
|
||||
className={buttonClassNames}
|
||||
data-text-while-loading={I18n.t('Moving...')}
|
||||
>
|
||||
{I18n.t('Move')}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
MoveDialog.render = function () {
|
||||
MoveDialog.renderMoveButton = function() {
|
||||
const buttonClassNames = classnames({
|
||||
disabled: !this.state.destinationFolder,
|
||||
btn: true,
|
||||
'btn-primary': true
|
||||
})
|
||||
if (this.state.isCopyingFile) {
|
||||
return (
|
||||
<Modal
|
||||
className='ReactModal__Content--canvas ReactModal__Content--mini-modal'
|
||||
overlayClassName='ReactModal__Overlay--canvas'
|
||||
ref='canvasModal'
|
||||
isOpen={this.state.isOpen}
|
||||
title={this.getTitle()}
|
||||
onRequestClose={this.closeDialog}
|
||||
onSubmit={this.submit}
|
||||
<button
|
||||
type="submit"
|
||||
aria-disabled={!this.state.destinationFolder}
|
||||
className={buttonClassNames}
|
||||
data-text-while-loading={I18n.t('Copying...')}
|
||||
>
|
||||
<ModalContent>
|
||||
<BBTreeBrowser
|
||||
rootFoldersToShow={this.props.rootFoldersToShow}
|
||||
onSelectFolder={this.onSelectFolder}
|
||||
/>
|
||||
</ModalContent>
|
||||
<ModalButtons>
|
||||
<button
|
||||
type='button'
|
||||
className='btn'
|
||||
onClick={this.closeDialog}
|
||||
>
|
||||
{I18n.t('Cancel')}
|
||||
</button>
|
||||
{this.renderMoveButton()}
|
||||
</ModalButtons>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
{I18n.t('Copy to Folder')}
|
||||
</button>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<button
|
||||
type="submit"
|
||||
aria-disabled={!this.state.destinationFolder}
|
||||
className={buttonClassNames}
|
||||
data-text-while-loading={I18n.t('Moving...')}
|
||||
>
|
||||
{I18n.t('Move')}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default createReactClass(MoveDialog);
|
||||
MoveDialog.render = function() {
|
||||
return (
|
||||
<Modal
|
||||
className="ReactModal__Content--canvas ReactModal__Content--mini-modal"
|
||||
overlayClassName="ReactModal__Overlay--canvas"
|
||||
ref="canvasModal"
|
||||
isOpen={this.state.isOpen}
|
||||
title={this.getTitle()}
|
||||
onRequestClose={this.closeDialog}
|
||||
onSubmit={this.submit}
|
||||
>
|
||||
<ModalContent>
|
||||
<BBTreeBrowser
|
||||
rootFoldersToShow={this.props.rootFoldersToShow}
|
||||
onSelectFolder={this.onSelectFolder}
|
||||
/>
|
||||
</ModalContent>
|
||||
<ModalButtons>
|
||||
<button type="button" className="btn" onClick={this.closeDialog}>
|
||||
{I18n.t('Cancel')}
|
||||
</button>
|
||||
{this.renderMoveButton()}
|
||||
</ModalButtons>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default createReactClass(MoveDialog)
|
||||
|
|
|
@ -20,9 +20,9 @@ import React from 'react'
|
|||
import createReactClass from 'create-react-class'
|
||||
import I18n from 'i18n!restrict_student_access'
|
||||
import classNames from 'classnames'
|
||||
import UsageRightsSelectBox from '../files/UsageRightsSelectBox'
|
||||
import RestrictedRadioButtons from '../files/RestrictedRadioButtons'
|
||||
import DialogPreview from '../files/DialogPreview'
|
||||
import UsageRightsSelectBox from './UsageRightsSelectBox'
|
||||
import RestrictedRadioButtons from './RestrictedRadioButtons'
|
||||
import DialogPreview from './DialogPreview'
|
||||
import RestrictedDialogForm from 'compiled/react_files/components/RestrictedDialogForm'
|
||||
|
||||
RestrictedDialogForm.renderUsageRightsWarning = function() {
|
||||
|
@ -95,14 +95,14 @@ RestrictedDialogForm.render = function() {
|
|||
<div className="RestrictedDialogForm__preview col-xs-3">
|
||||
<DialogPreview itemsToShow={this.props.models} />
|
||||
</div>
|
||||
{/* If showUsageRights then show the select box for it.*/}
|
||||
{/* If showUsageRights then show the select box for it. */}
|
||||
{!!showUsageRights && (
|
||||
<div className="RestrictedDialogForm__usageRights col-xs-9">
|
||||
<UsageRightsSelectBox ref={e => (this.usageSelection = e)} />
|
||||
<hr />
|
||||
</div>
|
||||
)}
|
||||
{/* Not showing usage rights?, then show the form here.*/}
|
||||
{/* Not showing usage rights?, then show the form here. */}
|
||||
{!showUsageRights && this.renderRestrictedAccessForm()}
|
||||
</div>
|
||||
{/* If showUsageRights,] it needs to be here instead */}
|
||||
|
|
|
@ -103,22 +103,15 @@ class RestrictedRadioButtons extends React.Component {
|
|||
]
|
||||
|
||||
componentDidMount() {
|
||||
return $([
|
||||
this.unlock_at,
|
||||
this.lock_at
|
||||
]).datetime_field()
|
||||
return $([this.unlock_at, this.lock_at]).datetime_field()
|
||||
}
|
||||
|
||||
extractFormValues = () => ({
|
||||
hidden: this.state.selectedOption === 'link_only',
|
||||
unlock_at:
|
||||
(this.state.selectedOption === 'date_range' &&
|
||||
$(this.unlock_at).data('unfudged-date')) ||
|
||||
'',
|
||||
(this.state.selectedOption === 'date_range' && $(this.unlock_at).data('unfudged-date')) || '',
|
||||
lock_at:
|
||||
(this.state.selectedOption === 'date_range' &&
|
||||
$(this.lock_at).data('unfudged-date')) ||
|
||||
'',
|
||||
(this.state.selectedOption === 'date_range' && $(this.lock_at).data('unfudged-date')) || '',
|
||||
locked: this.state.selectedOption === 'unpublished'
|
||||
})
|
||||
|
||||
|
@ -144,12 +137,12 @@ class RestrictedRadioButtons extends React.Component {
|
|||
<div className="radio" key={index}>
|
||||
<label>
|
||||
<input
|
||||
ref={e => this[option.ref] = e}
|
||||
ref={e => (this[option.ref] = e)}
|
||||
type="radio"
|
||||
name="permissions"
|
||||
checked={this.isPermissionChecked(option)}
|
||||
onChange={option.onChange.bind(this)}
|
||||
/>
|
||||
/>
|
||||
<i className={option.iconClasses} aria-hidden />
|
||||
{option.text}
|
||||
</label>
|
||||
|
|
|
@ -21,12 +21,12 @@ import _ from 'underscore'
|
|||
import React from 'react'
|
||||
import createReactClass from 'create-react-class'
|
||||
import SearchResults from 'compiled/react_files/components/SearchResults'
|
||||
import NoResults from '../files/NoResults'
|
||||
import ColumnHeaders from '../files/ColumnHeaders'
|
||||
import NoResults from './NoResults'
|
||||
import ColumnHeaders from './ColumnHeaders'
|
||||
import Folder from 'compiled/models/Folder'
|
||||
import FolderChild from '../files/FolderChild'
|
||||
import LoadingIndicator from '../files/LoadingIndicator'
|
||||
import FilePreview from '../files/FilePreview'
|
||||
import FolderChild from './FolderChild'
|
||||
import LoadingIndicator from './LoadingIndicator'
|
||||
import FilePreview from './FilePreview'
|
||||
import page from 'page'
|
||||
import FocusStore from 'compiled/react_files/modules/FocusStore'
|
||||
|
||||
|
@ -34,7 +34,7 @@ SearchResults.displayErrors = function(errors) {
|
|||
let error_message = null
|
||||
|
||||
if (errors != null) {
|
||||
error_message = errors.map((error) => <li>{error.message}</li>)
|
||||
error_message = errors.map(error => <li>{error.message}</li>)
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -62,9 +62,9 @@ SearchResults.renderFilePreview = function() {
|
|||
if (this.props.query.preview != null && this.state.collection.length) {
|
||||
return (
|
||||
/*
|
||||
* Prepare and render the FilePreview if needed.
|
||||
* As long as ?preview is present in the url.
|
||||
*/
|
||||
* Prepare and render the FilePreview if needed.
|
||||
* As long as ?preview is present in the url.
|
||||
*/
|
||||
<FilePreview
|
||||
isOpen
|
||||
params={this.props.params}
|
||||
|
@ -113,22 +113,22 @@ SearchResults.render = function() {
|
|||
)
|
||||
)
|
||||
.map(child => (
|
||||
<FolderChild
|
||||
key={child.cid}
|
||||
model={child}
|
||||
isSelected={_.indexOf(this.props.selectedItems, child) >= 0}
|
||||
toggleSelected={this.props.toggleItemSelected.bind(null, child)}
|
||||
userCanManageFilesForContext={this.props.userCanManageFilesForContext}
|
||||
userCanRestrictFilesForContext={this.props.userCanRestrictFilesForContext}
|
||||
usageRightsRequiredForContext={this.props.usageRightsRequiredForContext}
|
||||
externalToolsForContext={this.props.externalToolsForContext}
|
||||
previewItem={this.props.previewItem.bind(null, child)}
|
||||
dndOptions={this.props.dndOptions}
|
||||
modalOptions={this.props.modalOptions}
|
||||
clearSelectedItems={this.props.clearSelectedItems}
|
||||
onMove={this.props.onMove}
|
||||
/>
|
||||
))}
|
||||
<FolderChild
|
||||
key={child.cid}
|
||||
model={child}
|
||||
isSelected={_.indexOf(this.props.selectedItems, child) >= 0}
|
||||
toggleSelected={this.props.toggleItemSelected.bind(null, child)}
|
||||
userCanManageFilesForContext={this.props.userCanManageFilesForContext}
|
||||
userCanRestrictFilesForContext={this.props.userCanRestrictFilesForContext}
|
||||
usageRightsRequiredForContext={this.props.usageRightsRequiredForContext}
|
||||
externalToolsForContext={this.props.externalToolsForContext}
|
||||
previewItem={this.props.previewItem.bind(null, child)}
|
||||
dndOptions={this.props.dndOptions}
|
||||
modalOptions={this.props.modalOptions}
|
||||
clearSelectedItems={this.props.clearSelectedItems}
|
||||
onMove={this.props.onMove}
|
||||
/>
|
||||
))}
|
||||
|
||||
<LoadingIndicator isLoading={!this.state.collection.loadedAll} />
|
||||
|
||||
|
|
|
@ -22,12 +22,12 @@ import _ from 'underscore'
|
|||
import classnames from 'classnames'
|
||||
import I18n from 'i18n!react_files'
|
||||
import ShowFolder from 'compiled/react_files/components/ShowFolder'
|
||||
import FilePreview from '../files/FilePreview'
|
||||
import FolderChild from '../files/FolderChild'
|
||||
import UploadDropZone from '../files/UploadDropZone'
|
||||
import ColumnHeaders from '../files/ColumnHeaders'
|
||||
import CurrentUploads from '../files/CurrentUploads'
|
||||
import LoadingIndicator from '../files/LoadingIndicator'
|
||||
import FilePreview from './FilePreview'
|
||||
import FolderChild from './FolderChild'
|
||||
import UploadDropZone from './UploadDropZone'
|
||||
import ColumnHeaders from './ColumnHeaders'
|
||||
import CurrentUploads from './CurrentUploads'
|
||||
import LoadingIndicator from './LoadingIndicator'
|
||||
import page from 'page'
|
||||
import FocusStore from 'compiled/react_files/modules/FocusStore'
|
||||
|
||||
|
|
|
@ -22,9 +22,9 @@ import React from 'react'
|
|||
import ReactDOM from 'react-dom'
|
||||
import page from 'page'
|
||||
import FocusStore from 'compiled/react_files/modules/FocusStore'
|
||||
import openMoveDialog from '../files/utils/openMoveDialog'
|
||||
import openMoveDialog from './utils/openMoveDialog'
|
||||
import deleteStuff from 'compiled/react_files/utils/deleteStuff'
|
||||
import UploadButton from '../files/UploadButton'
|
||||
import UploadButton from './UploadButton'
|
||||
import classnames from 'classnames'
|
||||
import preventDefault from 'compiled/fn/preventDefault'
|
||||
import Folder from 'compiled/models/Folder'
|
||||
|
@ -144,7 +144,8 @@ export default class Toolbar extends React.Component {
|
|||
className="btn btn-add-folder"
|
||||
aria-label={I18n.t('Add Folder')}
|
||||
>
|
||||
<i className="icon-plus" />
|
||||
<i className="icon-plus" />
|
||||
|
||||
<span className={phoneHiddenSet}>{I18n.t('Folder')}</span>
|
||||
</button>
|
||||
|
||||
|
@ -158,6 +159,7 @@ export default class Toolbar extends React.Component {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
renderDeleteButton(canManage) {
|
||||
if (canManage) {
|
||||
return (
|
||||
|
@ -178,6 +180,7 @@ export default class Toolbar extends React.Component {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
renderManageUsageRightsButton() {
|
||||
if (this.props.userCanManageFilesForContext && this.props.usageRightsRequiredForContext) {
|
||||
return (
|
||||
|
@ -196,6 +199,7 @@ export default class Toolbar extends React.Component {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
renderCopyCourseButton(canManage) {
|
||||
if (canManage) {
|
||||
return (
|
||||
|
@ -344,7 +348,7 @@ export default class Toolbar extends React.Component {
|
|||
<a
|
||||
ref="previewLink"
|
||||
href="#"
|
||||
onClick={!selectedItemIsFolder ? preventDefault(() => this.openPreview()) : (() => {})}
|
||||
onClick={!selectedItemIsFolder ? preventDefault(() => this.openPreview()) : () => {}}
|
||||
className={viewBtnClasses}
|
||||
title={label}
|
||||
role="button"
|
||||
|
|
|
@ -18,63 +18,55 @@
|
|||
|
||||
import I18n from 'i18n!upload_button'
|
||||
import React from 'react'
|
||||
import createReactClass from 'create-react-class';
|
||||
import FileRenameForm from '../files/FileRenameForm'
|
||||
import createReactClass from 'create-react-class'
|
||||
import FileRenameForm from './FileRenameForm'
|
||||
import ZipFileOptionsForm from './ZipFileOptionsForm'
|
||||
import UploadButton from 'compiled/react_files/components/UploadButton'
|
||||
UploadButton.buildPotentialModal = function () {
|
||||
if (this.state.zipOptions.length) {
|
||||
return (
|
||||
<ZipFileOptionsForm
|
||||
fileOptions= {this.state.zipOptions[0]}
|
||||
onZipOptionsResolved= {this.onZipOptionsResolved}
|
||||
onClose={this.onClose}
|
||||
/>
|
||||
);
|
||||
} else if (this.state.nameCollisions.length) {
|
||||
return (
|
||||
<FileRenameForm
|
||||
fileOptions= {this.state.nameCollisions[0]}
|
||||
onNameConflictResolved= {this.onNameConflictResolved}
|
||||
onClose= {this.onClose}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
UploadButton.hiddenPhoneClassname = function () {
|
||||
if (this.props.showingButtons) {
|
||||
return('hidden-phone');
|
||||
}
|
||||
}
|
||||
|
||||
UploadButton.render = function () {
|
||||
UploadButton.buildPotentialModal = function() {
|
||||
if (this.state.zipOptions.length) {
|
||||
return (
|
||||
<span>
|
||||
<form
|
||||
ref= 'form'
|
||||
className= 'hidden'
|
||||
>
|
||||
<input
|
||||
type='file'
|
||||
ref='addFileInput'
|
||||
onChange= {this.handleFilesInputChange}
|
||||
multiple= {true}
|
||||
/>
|
||||
</form>
|
||||
<button
|
||||
type= 'button'
|
||||
className= 'btn btn-primary btn-upload'
|
||||
onClick= {this.handleAddFilesClick}
|
||||
>
|
||||
<i className='icon-upload' aria-hidden />
|
||||
<span className= {this.hiddenPhoneClassname()} >
|
||||
{ I18n.t('Upload') }
|
||||
</span>
|
||||
</button>
|
||||
{ this.buildPotentialModal() }
|
||||
</span>
|
||||
);
|
||||
<ZipFileOptionsForm
|
||||
fileOptions={this.state.zipOptions[0]}
|
||||
onZipOptionsResolved={this.onZipOptionsResolved}
|
||||
onClose={this.onClose}
|
||||
/>
|
||||
)
|
||||
} else if (this.state.nameCollisions.length) {
|
||||
return (
|
||||
<FileRenameForm
|
||||
fileOptions={this.state.nameCollisions[0]}
|
||||
onNameConflictResolved={this.onNameConflictResolved}
|
||||
onClose={this.onClose}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default createReactClass(UploadButton);
|
||||
UploadButton.hiddenPhoneClassname = function() {
|
||||
if (this.props.showingButtons) {
|
||||
return 'hidden-phone'
|
||||
}
|
||||
}
|
||||
|
||||
UploadButton.render = function() {
|
||||
return (
|
||||
<span>
|
||||
<form ref="form" className="hidden">
|
||||
<input type="file" ref="addFileInput" onChange={this.handleFilesInputChange} multiple />
|
||||
</form>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-primary btn-upload"
|
||||
onClick={this.handleAddFilesClick}
|
||||
>
|
||||
<i className="icon-upload" aria-hidden />
|
||||
|
||||
<span className={this.hiddenPhoneClassname()}>{I18n.t('Upload')}</span>
|
||||
</button>
|
||||
{this.buildPotentialModal()}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
export default createReactClass(UploadButton)
|
||||
|
|
|
@ -17,64 +17,61 @@
|
|||
*/
|
||||
|
||||
import React from 'react'
|
||||
import createReactClass from 'create-react-class';
|
||||
import createReactClass from 'create-react-class'
|
||||
import I18n from 'i18n!react_files'
|
||||
import classnames from 'classnames'
|
||||
import UploadProgress from 'compiled/react_files/components/UploadProgress'
|
||||
import ProgressBar from '../shared/ProgressBar'
|
||||
import mimeClass from 'compiled/util/mimeClass'
|
||||
|
||||
UploadProgress.renderProgressBar = function () {
|
||||
if (this.props.uploader.error) {
|
||||
var errorMessage = (this.props.uploader.error.message) ?
|
||||
I18n.t('Error: %{message}', {message: this.props.uploader.error.message}) :
|
||||
I18n.t('Error uploading file.')
|
||||
UploadProgress.renderProgressBar = function() {
|
||||
if (this.props.uploader.error) {
|
||||
const errorMessage = this.props.uploader.error.message
|
||||
? I18n.t('Error: %{message}', {message: this.props.uploader.error.message})
|
||||
: I18n.t('Error uploading file.')
|
||||
|
||||
return (
|
||||
<span>
|
||||
{errorMessage}
|
||||
<button type='button' className='btn-link' onClick={ () => this.props.uploader.upload()}>
|
||||
{I18n.t('Retry')}
|
||||
</button>
|
||||
return (
|
||||
<span>
|
||||
{errorMessage}
|
||||
<button type="button" className="btn-link" onClick={() => this.props.uploader.upload()}>
|
||||
{I18n.t('Retry')}
|
||||
</button>
|
||||
</span>
|
||||
)
|
||||
} else {
|
||||
return <ProgressBar progress={this.props.uploader.roundProgress()} />
|
||||
}
|
||||
}
|
||||
|
||||
UploadProgress.render = function() {
|
||||
const rowClassNames = classnames({
|
||||
'ef-item-row': true,
|
||||
'text-error': this.props.uploader.error
|
||||
})
|
||||
|
||||
return (
|
||||
<div className={rowClassNames}>
|
||||
<div className="col-xs-6">
|
||||
<div className="media ellipsis">
|
||||
<span className="pull-left">
|
||||
<i className={`media-object mimeClass-${mimeClass(this.props.uploader.file.type)}`} />
|
||||
</span>
|
||||
<span className="media-body" ref="fileName">
|
||||
{this.props.uploader.getFileName()}
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
return <ProgressBar progress={this.props.uploader.roundProgress()} />
|
||||
}
|
||||
};
|
||||
|
||||
UploadProgress.render = function () {
|
||||
|
||||
var rowClassNames = classnames({
|
||||
'ef-item-row': true,
|
||||
'text-error': this.props.uploader.error
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={rowClassNames}>
|
||||
<div className='col-xs-6'>
|
||||
<div className='media ellipsis'>
|
||||
<span className='pull-left'>
|
||||
<i className={`media-object mimeClass-${mimeClass(this.props.uploader.file.type)}`} />
|
||||
</span>
|
||||
<span className='media-body' ref='fileName'>
|
||||
{this.props.uploader.getFileName()}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className='col-xs-5'>
|
||||
{this.renderProgressBar()}
|
||||
</div>
|
||||
<button
|
||||
type='button'
|
||||
onClick={this.props.uploader.cancel}
|
||||
aria-label={I18n.t('Cancel')}
|
||||
className='btn-link upload-progress-view__button'
|
||||
>
|
||||
x
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
</div>
|
||||
<div className="col-xs-5">{this.renderProgressBar()}</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={this.props.uploader.cancel}
|
||||
aria-label={I18n.t('Cancel')}
|
||||
className="btn-link upload-progress-view__button"
|
||||
>
|
||||
x
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default createReactClass(UploadProgress);
|
||||
export default createReactClass(UploadProgress)
|
||||
|
|
|
@ -20,9 +20,9 @@ import React from 'react'
|
|||
import createReactClass from 'create-react-class'
|
||||
import UsageRightsDialog from 'compiled/react_files/components/UsageRightsDialog'
|
||||
import I18n from 'i18n!usage_rights_modal'
|
||||
import UsageRightsSelectBox from '../files/UsageRightsSelectBox'
|
||||
import RestrictedRadioButtons from '../files/RestrictedRadioButtons'
|
||||
import DialogPreview from '../files/DialogPreview'
|
||||
import UsageRightsSelectBox from './UsageRightsSelectBox'
|
||||
import RestrictedRadioButtons from './RestrictedRadioButtons'
|
||||
import DialogPreview from './DialogPreview'
|
||||
import Folder from 'compiled/models/Folder'
|
||||
import {Modal} from '@instructure/ui-overlays'
|
||||
import {CloseButton, Button} from '@instructure/ui-buttons'
|
||||
|
@ -66,9 +66,10 @@ UsageRightsDialog.renderFolderTooltip = function(folders) {
|
|||
const toolTipFolders = folders.slice(MAX_FOLDERS_TO_SHOW)
|
||||
|
||||
if (toolTipFolders.length) {
|
||||
const renderItems = toolTipFolders.map(item => (
|
||||
{cid: item.cid, displayName: htmlEscape(item.displayName()).toString()}
|
||||
))
|
||||
const renderItems = toolTipFolders.map(item => ({
|
||||
cid: item.cid,
|
||||
displayName: htmlEscape(item.displayName()).toString()
|
||||
}))
|
||||
// Doing it this way so commas, don't show up when rendering the list out in the tooltip.
|
||||
const renderedNames = renderItems.map(item => item.displayName).join('<br />')
|
||||
|
||||
|
@ -85,7 +86,10 @@ UsageRightsDialog.renderFolderTooltip = function(folders) {
|
|||
<span className="screenreader-only">
|
||||
<ul>
|
||||
{renderItems.map((item, i) => (
|
||||
<li key={item.cid} ref={e => (this[`displayNameTooltip${i}-screenreader`] = e)}> {item.displayName}</li>
|
||||
<li key={item.cid} ref={e => (this[`displayNameTooltip${i}-screenreader`] = e)}>
|
||||
{' '}
|
||||
{item.displayName}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</span>
|
||||
|
|
|
@ -23,7 +23,7 @@ import ReactDOM from 'react-dom'
|
|||
import customPropTypes from 'compiled/react_files/modules/customPropTypes'
|
||||
import Folder from 'compiled/models/Folder'
|
||||
import filesEnv from 'compiled/react_files/modules/filesEnv'
|
||||
import UsageRightsDialog from '../files/UsageRightsDialog'
|
||||
import UsageRightsDialog from './UsageRightsDialog'
|
||||
|
||||
export default class UsageRightsIndicator extends React.Component {
|
||||
warningMessage = I18n.t('Before publishing this file, you must specify usage rights.')
|
||||
|
|
|
@ -92,9 +92,7 @@ export default class UsageRightsSelectBox extends React.Component {
|
|||
let x
|
||||
const obj = {
|
||||
use_justification: this.usageRightSelection.value,
|
||||
copyright: this.state.showTextBox
|
||||
? (x = this.copyright) && x.value
|
||||
: undefined,
|
||||
copyright: this.state.showTextBox ? (x = this.copyright) && x.value : undefined,
|
||||
cc_license: this.state.showCreativeCommonsOptions
|
||||
? (x = this.creativeCommons) && x.value
|
||||
: undefined
|
||||
|
|
|
@ -17,17 +17,17 @@
|
|||
*/
|
||||
|
||||
import $ from 'jquery'
|
||||
/* This file contains code specific to weird edge cases that can be removed later. For instance, if you
|
||||
* are writing some weird code around something that is broken in Jaws, it can live here
|
||||
*/
|
||||
/* This file contains code specific to weird edge cases that can be removed later. For instance, if you
|
||||
* are writing some weird code around something that is broken in Jaws, it can live here
|
||||
*/
|
||||
|
||||
var codeToRemoveLater = {
|
||||
hideFileTreeFromPreviewInJaws () {
|
||||
$("aside ul[role='tree']").attr('role', 'presentation');
|
||||
},
|
||||
revertJawsChangesBackToNormal () {
|
||||
$("aside ul[role='presentation']").attr('role', 'tree');
|
||||
}
|
||||
const codeToRemoveLater = {
|
||||
hideFileTreeFromPreviewInJaws() {
|
||||
$("aside ul[role='tree']").attr('role', 'presentation')
|
||||
},
|
||||
revertJawsChangesBackToNormal() {
|
||||
$("aside ul[role='presentation']").attr('role', 'tree')
|
||||
}
|
||||
}
|
||||
|
||||
export default codeToRemoveLater
|
||||
|
|
|
@ -21,81 +21,86 @@ import ReactDOM from 'react-dom'
|
|||
import page from 'page'
|
||||
import qs from 'qs'
|
||||
import filesEnv from 'compiled/react_files/modules/filesEnv'
|
||||
import FilesApp from '../files/FilesApp'
|
||||
import ShowFolder from '../files/ShowFolder'
|
||||
import SearchResults from '../files/SearchResults'
|
||||
import FilesApp from './FilesApp'
|
||||
import ShowFolder from './ShowFolder'
|
||||
import SearchResults from './SearchResults'
|
||||
|
||||
/**
|
||||
* Route Handlers
|
||||
/**
|
||||
* Route Handlers
|
||||
*/
|
||||
function renderShowFolder(ctx) {
|
||||
ReactDOM.render(
|
||||
<FilesApp
|
||||
query={ctx.query}
|
||||
params={ctx.params}
|
||||
splat={ctx.splat}
|
||||
pathname={ctx.pathname}
|
||||
contextAssetString={window.ENV.context_asset_string}
|
||||
>
|
||||
<ShowFolder />
|
||||
</FilesApp>,
|
||||
document.getElementById('content')
|
||||
)
|
||||
}
|
||||
|
||||
function renderSearchResults(ctx) {
|
||||
ReactDOM.render(
|
||||
<FilesApp
|
||||
query={ctx.query}
|
||||
params={ctx.params}
|
||||
splat={ctx.splat}
|
||||
pathname={ctx.pathname}
|
||||
contextAssetString={window.ENV.context_asset_string}
|
||||
>
|
||||
<SearchResults />
|
||||
</FilesApp>,
|
||||
document.getElementById('content')
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Middlewares
|
||||
*/
|
||||
|
||||
function parseQueryString(ctx, next) {
|
||||
ctx.query = qs.parse(ctx.querystring)
|
||||
next()
|
||||
}
|
||||
|
||||
function getFolderSplat(ctx, next) {
|
||||
/* This function only gets called when hitting the /folder/*
|
||||
* route so we make that assumption here with many of the
|
||||
* things being done.
|
||||
*/
|
||||
function renderShowFolder (ctx) {
|
||||
ReactDOM.render(
|
||||
<FilesApp
|
||||
query={ctx.query}
|
||||
params={ctx.params}
|
||||
splat={ctx.splat}
|
||||
pathname={ctx.pathname}
|
||||
contextAssetString={window.ENV.context_asset_string}
|
||||
>
|
||||
<ShowFolder />
|
||||
</FilesApp>
|
||||
, document.getElementById('content'));
|
||||
}
|
||||
const PATH_PREFIX = '/folder/'
|
||||
const index = ctx.pathname.indexOf(PATH_PREFIX) + PATH_PREFIX.length
|
||||
const rawSplat = ctx.pathname.slice(index)
|
||||
ctx.splat = rawSplat
|
||||
.split('/')
|
||||
.map(part => window.encodeURIComponent(part))
|
||||
.join('/')
|
||||
next()
|
||||
}
|
||||
|
||||
function renderSearchResults (ctx) {
|
||||
ReactDOM.render(
|
||||
<FilesApp
|
||||
query={ctx.query}
|
||||
params={ctx.params}
|
||||
splat={ctx.splat}
|
||||
pathname={ctx.pathname}
|
||||
contextAssetString={window.ENV.context_asset_string}
|
||||
>
|
||||
<SearchResults />
|
||||
</FilesApp>
|
||||
, document.getElementById('content'));
|
||||
}
|
||||
function getSplat(ctx, next) {
|
||||
ctx.splat = ''
|
||||
next()
|
||||
}
|
||||
|
||||
/**
|
||||
* Middlewares
|
||||
*/
|
||||
|
||||
function parseQueryString (ctx, next) {
|
||||
ctx.query = qs.parse(ctx.querystring);
|
||||
next();
|
||||
}
|
||||
|
||||
function getFolderSplat (ctx, next) {
|
||||
/* This function only gets called when hitting the /folder/*
|
||||
* route so we make that assumption here with many of the
|
||||
* things being done.
|
||||
*/
|
||||
const PATH_PREFIX = '/folder/';
|
||||
const index = ctx.pathname.indexOf(PATH_PREFIX) + PATH_PREFIX.length;
|
||||
const rawSplat = ctx.pathname.slice(index);
|
||||
ctx.splat = rawSplat.split('/').map((part) => window.encodeURIComponent(part)).join('/');
|
||||
next();
|
||||
}
|
||||
|
||||
function getSplat (ctx, next) {
|
||||
ctx.splat = '';
|
||||
next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Route Configuration
|
||||
*/
|
||||
page.base(filesEnv.baseUrl);
|
||||
page('*', getSplat); // Generally this will overridden by the folder route's middleware
|
||||
page('*', parseQueryString); // Middleware to parse querystring to object
|
||||
page('/', renderShowFolder);
|
||||
page('/search', renderSearchResults);
|
||||
page('/folder', '/');
|
||||
page('/folder/*', getFolderSplat, renderShowFolder);
|
||||
/**
|
||||
* Route Configuration
|
||||
*/
|
||||
page.base(filesEnv.baseUrl)
|
||||
page('*', getSplat) // Generally this will overridden by the folder route's middleware
|
||||
page('*', parseQueryString) // Middleware to parse querystring to object
|
||||
page('/', renderShowFolder)
|
||||
page('/search', renderSearchResults)
|
||||
page('/folder', '/')
|
||||
page('/folder/*', getFolderSplat, renderShowFolder)
|
||||
|
||||
export default {
|
||||
start () {
|
||||
page.start();
|
||||
},
|
||||
getFolderSplat // Export getSplat for testing
|
||||
};
|
||||
start() {
|
||||
page.start()
|
||||
},
|
||||
getFolderSplat // Export getSplat for testing
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
import moxios from 'moxios'
|
||||
import sinon from 'sinon'
|
||||
import { uploadFile } from 'jsx/files/utils/apiFileUtils'
|
||||
import {uploadFile} from 'jsx/files/utils/apiFileUtils'
|
||||
|
||||
describe('apiFileUtils', () => {
|
||||
beforeEach(() => {
|
||||
|
@ -30,19 +30,19 @@ describe('apiFileUtils', () => {
|
|||
})
|
||||
|
||||
describe('uploadFile', () => {
|
||||
it('runs the onSuccess method after upload', (done) => {
|
||||
it('runs the onSuccess method after upload', done => {
|
||||
const onSuccess = sinon.spy()
|
||||
const onFail = sinon.spy()
|
||||
moxios.stubRequest('/api/v1/folders/1/files', {
|
||||
status: 200,
|
||||
response: {
|
||||
upload_url: "http://new_url",
|
||||
upload_url: 'http://new_url',
|
||||
upload_params: {
|
||||
Filename: "file",
|
||||
key: "folder/filename",
|
||||
"content-type": "image/png"
|
||||
Filename: 'file',
|
||||
key: 'folder/filename',
|
||||
'content-type': 'image/png'
|
||||
},
|
||||
file_param: "attachment[uploaded_data]"
|
||||
file_param: 'attachment[uploaded_data]'
|
||||
}
|
||||
})
|
||||
moxios.stubRequest('http://new_url', {
|
||||
|
@ -61,19 +61,19 @@ describe('apiFileUtils', () => {
|
|||
})
|
||||
})
|
||||
|
||||
it('runs the onFailure method on upload failure', (done) => {
|
||||
it('runs the onFailure method on upload failure', done => {
|
||||
const onSuccess = sinon.spy()
|
||||
const onFail = sinon.spy()
|
||||
moxios.stubRequest('/api/v1/folders/1/files', {
|
||||
status: 200,
|
||||
response: {
|
||||
upload_url: "http://new_url",
|
||||
upload_url: 'http://new_url',
|
||||
upload_params: {
|
||||
Filename: "file",
|
||||
key: "folder/filename",
|
||||
"content-type": "image/png"
|
||||
Filename: 'file',
|
||||
key: 'folder/filename',
|
||||
'content-type': 'image/png'
|
||||
},
|
||||
file_param: "attachment[uploaded_data]"
|
||||
file_param: 'attachment[uploaded_data]'
|
||||
}
|
||||
})
|
||||
moxios.stubRequest('http://new_url', {
|
||||
|
@ -93,7 +93,7 @@ describe('apiFileUtils', () => {
|
|||
})
|
||||
|
||||
describe('onFileUploadInfoReceived', () => {
|
||||
it('runs the onFailure on file prep failure', (done) => {
|
||||
it('runs the onFailure on file prep failure', done => {
|
||||
const onSuccess = sinon.spy()
|
||||
const onFail = sinon.spy()
|
||||
moxios.stubRequest('/api/v1/folders/1/files', {
|
||||
|
|
|
@ -18,31 +18,37 @@ import axios from 'axios'
|
|||
|
||||
const stringIds = {Accept: 'application/json+canvas-string-ids'}
|
||||
|
||||
export function getRootFolder (contextType, contextId) {
|
||||
export function getRootFolder(contextType, contextId) {
|
||||
return axios.get(`/api/v1/${contextType}/${contextId}/folders/root`, stringIds)
|
||||
}
|
||||
|
||||
function createFormData (data) {
|
||||
function createFormData(data) {
|
||||
const formData = new FormData()
|
||||
Object.keys(data).forEach(key => formData.append(key, data[key]))
|
||||
return formData
|
||||
}
|
||||
|
||||
function onFileUploadInfoReceived (file, uploadInfo, onSuccess, onFailure) {
|
||||
const formData = createFormData({...uploadInfo.upload_params, 'file': file})
|
||||
function onFileUploadInfoReceived(file, uploadInfo, onSuccess, onFailure) {
|
||||
const formData = createFormData({...uploadInfo.upload_params, file})
|
||||
const config = {'Content-Type': 'multipart/form-data', ...stringIds}
|
||||
axios.post(uploadInfo.upload_url, formData, config)
|
||||
axios
|
||||
.post(uploadInfo.upload_url, formData, config)
|
||||
.then(response => onSuccess(response.data))
|
||||
.catch(response => onFailure(response))
|
||||
}
|
||||
|
||||
export function uploadFile (file, folderId, onSuccess, onFailure) {
|
||||
axios.post(`/api/v1/folders/${folderId}/files`, {
|
||||
name: file.name,
|
||||
size: file.size,
|
||||
parent_folder_id: folderId,
|
||||
on_duplicate: 'rename'
|
||||
}, stringIds)
|
||||
.then(response => onFileUploadInfoReceived(file, response.data, onSuccess, onFailure))
|
||||
.catch(response => onFailure(response))
|
||||
export function uploadFile(file, folderId, onSuccess, onFailure) {
|
||||
axios
|
||||
.post(
|
||||
`/api/v1/folders/${folderId}/files`,
|
||||
{
|
||||
name: file.name,
|
||||
size: file.size,
|
||||
parent_folder_id: folderId,
|
||||
on_duplicate: 'rename'
|
||||
},
|
||||
stringIds
|
||||
)
|
||||
.then(response => onFileUploadInfoReceived(file, response.data, onSuccess, onFailure))
|
||||
.catch(response => onFailure(response))
|
||||
}
|
||||
|
|
|
@ -19,37 +19,42 @@
|
|||
import _ from 'underscore'
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import MoveDialog from '../../files/MoveDialog'
|
||||
import MoveDialog from '../MoveDialog'
|
||||
import filesEnv from 'compiled/react_files/modules/filesEnv'
|
||||
import $ from 'jquery'
|
||||
|
||||
function openMoveDialog (thingsToMove, {contextType, contextId, returnFocusTo, clearSelectedItems, onMove}) {
|
||||
function openMoveDialog(
|
||||
thingsToMove,
|
||||
{contextType, contextId, returnFocusTo, clearSelectedItems, onMove}
|
||||
) {
|
||||
const rootFolderToShow = _.find(filesEnv.rootFolders, folder => {
|
||||
return (
|
||||
`${folder.get('context_type').toLowerCase()}s` === contextType &&
|
||||
String(folder.get('context_id')) === String(contextId)
|
||||
)
|
||||
})
|
||||
|
||||
const rootFolderToShow = _.find(filesEnv.rootFolders, (folder) => {
|
||||
return (`${folder.get('context_type').toLowerCase()}s` === contextType) && (String(folder.get('context_id')) === String(contextId));
|
||||
});
|
||||
const $moveDialog = $('<div>').appendTo(document.body)
|
||||
|
||||
const $moveDialog = $('<div>').appendTo(document.body);
|
||||
|
||||
const handleClose = () => {
|
||||
ReactDOM.unmountComponentAtNode($moveDialog[0]);
|
||||
$moveDialog.remove();
|
||||
$(returnFocusTo).focus();
|
||||
};
|
||||
|
||||
const handleMove = (models) => {
|
||||
onMove(models) && clearSelectedItems();
|
||||
};
|
||||
|
||||
ReactDOM.render(
|
||||
<MoveDialog
|
||||
thingsToMove={thingsToMove}
|
||||
rootFoldersToShow={(filesEnv.showingAllContexts) ? filesEnv.rootFolders : [rootFolderToShow] }
|
||||
onClose={handleClose}
|
||||
onMove={handleMove}
|
||||
/>
|
||||
, $moveDialog[0]
|
||||
);
|
||||
const handleClose = () => {
|
||||
ReactDOM.unmountComponentAtNode($moveDialog[0])
|
||||
$moveDialog.remove()
|
||||
$(returnFocusTo).focus()
|
||||
}
|
||||
|
||||
const handleMove = models => {
|
||||
onMove(models) && clearSelectedItems()
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<MoveDialog
|
||||
thingsToMove={thingsToMove}
|
||||
rootFoldersToShow={filesEnv.showingAllContexts ? filesEnv.rootFolders : [rootFolderToShow]}
|
||||
onClose={handleClose}
|
||||
onMove={handleMove}
|
||||
/>,
|
||||
$moveDialog[0]
|
||||
)
|
||||
}
|
||||
|
||||
export default openMoveDialog
|
||||
|
|
|
@ -26,7 +26,7 @@ import {Text} from '@instructure/ui-elements'
|
|||
|
||||
import {showFlashError} from '../shared/FlashAlert'
|
||||
import I18n from 'i18n!grade_summary'
|
||||
import SelectMenu from "./SelectMenu"
|
||||
import SelectMenu from './SelectMenu'
|
||||
|
||||
export default class SelectMenuGroup extends React.Component {
|
||||
static propTypes = {
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
import _ from 'underscore'
|
||||
import round from 'compiled/util/round'
|
||||
import AssignmentGroupGradeCalculator from '../gradebook/AssignmentGroupGradeCalculator'
|
||||
import AssignmentGroupGradeCalculator from './AssignmentGroupGradeCalculator'
|
||||
import {
|
||||
bigSum,
|
||||
sum,
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
import _ from 'underscore'
|
||||
import I18n from 'i18n!modules'
|
||||
import React from 'react'
|
||||
import assignmentUtils from '../../gradebook/SISGradePassback/assignmentUtils'
|
||||
import assignmentUtils from './assignmentUtils'
|
||||
import classnames from 'classnames'
|
||||
|
||||
class AssignmentCorrectionRow extends React.Component {
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import I18n from 'i18n!modules'
|
||||
import PostGradesDialog from '../../gradebook/SISGradePassback/PostGradesDialog'
|
||||
import PostGradesDialog from './PostGradesDialog'
|
||||
import classnames from 'classnames'
|
||||
|
||||
// The PostGradesApp mounts a single "Sync Grades" button, which pops up
|
||||
|
|
|
@ -18,10 +18,10 @@
|
|||
|
||||
import _ from 'underscore'
|
||||
import React from 'react'
|
||||
import assignmentUtils from '../../gradebook/SISGradePassback/assignmentUtils'
|
||||
import PostGradesDialogCorrectionsPage from '../../gradebook/SISGradePassback/PostGradesDialogCorrectionsPage'
|
||||
import PostGradesDialogNeedsGradingPage from '../../gradebook/SISGradePassback/PostGradesDialogNeedsGradingPage'
|
||||
import PostGradesDialogSummaryPage from '../../gradebook/SISGradePassback/PostGradesDialogSummaryPage'
|
||||
import assignmentUtils from './assignmentUtils'
|
||||
import PostGradesDialogCorrectionsPage from './PostGradesDialogCorrectionsPage'
|
||||
import PostGradesDialogNeedsGradingPage from './PostGradesDialogNeedsGradingPage'
|
||||
import PostGradesDialogSummaryPage from './PostGradesDialogSummaryPage'
|
||||
|
||||
class PostGradesDialog extends React.Component {
|
||||
componentDidMount() {
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
import _ from 'underscore'
|
||||
import I18n from 'i18n!modules'
|
||||
import React from 'react'
|
||||
import assignmentUtils from '../../gradebook/SISGradePassback/assignmentUtils'
|
||||
import AssignmentCorrectionRow from '../../gradebook/SISGradePassback/AssignmentCorrectionRow'
|
||||
import assignmentUtils from './assignmentUtils'
|
||||
import AssignmentCorrectionRow from './AssignmentCorrectionRow'
|
||||
|
||||
class PostGradesDialogCorrectionsPage extends React.Component {
|
||||
componentDidMount() {
|
||||
|
|
|
@ -19,21 +19,21 @@
|
|||
import $ from 'jquery'
|
||||
import _ from 'underscore'
|
||||
import createStore from '../../shared/helpers/createStore'
|
||||
import assignmentUtils from '../../gradebook/SISGradePassback/assignmentUtils'
|
||||
import assignmentUtils from './assignmentUtils'
|
||||
|
||||
var PostGradesStore = state => {
|
||||
var store = $.extend(createStore(state), {
|
||||
const PostGradesStore = state => {
|
||||
const store = $.extend(createStore(state), {
|
||||
reset() {
|
||||
var assignments = this.getAssignments()
|
||||
const assignments = this.getAssignments()
|
||||
_.each(assignments, a => (a.please_ignore = false))
|
||||
this.setState({
|
||||
assignments: assignments,
|
||||
assignments,
|
||||
pleaseShowNeedsGradingPage: false
|
||||
})
|
||||
},
|
||||
|
||||
hasAssignments() {
|
||||
var assignments = this.getAssignments()
|
||||
const assignments = this.getAssignments()
|
||||
if (assignments != undefined && assignments.length > 0) {
|
||||
return true
|
||||
} else {
|
||||
|
@ -42,12 +42,12 @@ var PostGradesStore = state => {
|
|||
},
|
||||
|
||||
getSISSectionId(section_id) {
|
||||
var sections = this.getState().sections
|
||||
const sections = this.getState().sections
|
||||
return sections && sections[section_id] ? sections[section_id].sis_section_id : null
|
||||
},
|
||||
|
||||
allOverrideIds(a) {
|
||||
var overrides = []
|
||||
const overrides = []
|
||||
_.each(a.overrides, o => {
|
||||
overrides.push(o.course_section_id)
|
||||
})
|
||||
|
@ -55,22 +55,22 @@ var PostGradesStore = state => {
|
|||
},
|
||||
|
||||
overrideForEveryone(a) {
|
||||
var overrides = this.allOverrideIds(a)
|
||||
var sections = _.keys(this.getState().sections)
|
||||
var section_ids_with_no_overrides = $(sections)
|
||||
const overrides = this.allOverrideIds(a)
|
||||
const sections = _.keys(this.getState().sections)
|
||||
const section_ids_with_no_overrides = $(sections)
|
||||
.not(overrides)
|
||||
.get()
|
||||
|
||||
var section_for_everyone = _.find(section_ids_with_no_overrides, o => {
|
||||
const section_for_everyone = _.find(section_ids_with_no_overrides, o => {
|
||||
return state.selected.id == o
|
||||
})
|
||||
return section_for_everyone
|
||||
},
|
||||
|
||||
setGradeBookAssignments(gradebookAssignments) {
|
||||
var assignments = []
|
||||
for (var id in gradebookAssignments) {
|
||||
var gba = gradebookAssignments[id]
|
||||
const assignments = []
|
||||
for (const id in gradebookAssignments) {
|
||||
const gba = gradebookAssignments[id]
|
||||
// Only accept assignments suitable to post, e.g. published, post_to_sis
|
||||
if (assignmentUtils.suitableToPost(gba)) {
|
||||
// Push a copy, and only of relevant attributes
|
||||
|
@ -82,11 +82,11 @@ var PostGradesStore = state => {
|
|||
_.each(assignments, a => {
|
||||
a.original_error = assignmentUtils.hasError(assignments, a)
|
||||
})
|
||||
this.setState({assignments: assignments})
|
||||
this.setState({assignments})
|
||||
},
|
||||
|
||||
setSections(sections) {
|
||||
this.setState({sections: sections})
|
||||
this.setState({sections})
|
||||
this.setSelectedSection(this.getState().sectionToShow)
|
||||
},
|
||||
|
||||
|
@ -96,21 +96,21 @@ var PostGradesStore = state => {
|
|||
a.currentlySelected.type == 'course' &&
|
||||
a.currentlySelected.id.toString() == a.overrideForThisSection.course_section_id
|
||||
) {
|
||||
return a.due_at != null ? true : false
|
||||
return a.due_at != null
|
||||
} else if (
|
||||
a.overrideForThisSection != undefined &&
|
||||
a.currentlySelected.type == 'section' &&
|
||||
a.currentlySelected.id.toString() == a.overrideForThisSection.course_section_id
|
||||
) {
|
||||
return a.overrideForThisSection.due_at != null ? true : false
|
||||
return a.overrideForThisSection.due_at != null
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
},
|
||||
|
||||
getAssignments() {
|
||||
var assignments = this.getState().assignments
|
||||
var state = this.getState()
|
||||
const assignments = this.getState().assignments
|
||||
const state = this.getState()
|
||||
if (state.selected.type == 'section') {
|
||||
_.each(assignments, a => {
|
||||
a.recentlyUpdated = false
|
||||
|
@ -120,8 +120,8 @@ var PostGradesStore = state => {
|
|||
return override.course_section_id == state.selected.id
|
||||
})
|
||||
|
||||
//Handle assignment with overrides and the 'Everyone Else' scenario with a section that does not have any overrides
|
||||
//cleanup overrideForThisSection logic
|
||||
// Handle assignment with overrides and the 'Everyone Else' scenario with a section that does not have any overrides
|
||||
// cleanup overrideForThisSection logic
|
||||
if (a.overrideForThisSection == undefined) {
|
||||
a.selectedSectionForEveryone = this.overrideForEveryone(a)
|
||||
}
|
||||
|
@ -132,12 +132,12 @@ var PostGradesStore = state => {
|
|||
a.currentlySelected = state.selected
|
||||
a.sectionCount = _.keys(state.sections).length
|
||||
|
||||
//Course is currentlySlected with sections that have overrides AND are invalid
|
||||
// Course is currentlySlected with sections that have overrides AND are invalid
|
||||
a.overrideForThisSection = _.find(a.overrides, override => {
|
||||
return override.due_at == null || typeof override.due_at == 'object'
|
||||
return override.due_at == null || typeof override.due_at === 'object'
|
||||
})
|
||||
|
||||
//Handle assignment with overrides and the 'Everyone Else' scenario with the course currentlySelected
|
||||
// Handle assignment with overrides and the 'Everyone Else' scenario with the course currentlySelected
|
||||
if (a.overrideForThisSection == undefined) {
|
||||
a.selectedSectionForEveryone = this.overrideForEveryone(a)
|
||||
}
|
||||
|
@ -147,14 +147,14 @@ var PostGradesStore = state => {
|
|||
},
|
||||
|
||||
getAssignment(assignment_id) {
|
||||
var assignments = this.getAssignments()
|
||||
const assignments = this.getAssignments()
|
||||
return _.find(assignments, a => a.id == assignment_id)
|
||||
},
|
||||
|
||||
setSelectedSection(section) {
|
||||
var state = this.getState()
|
||||
var section_id = parseInt(section)
|
||||
var selected
|
||||
const state = this.getState()
|
||||
const section_id = parseInt(section)
|
||||
let selected
|
||||
if (section) {
|
||||
selected = {
|
||||
type: 'section',
|
||||
|
@ -169,20 +169,20 @@ var PostGradesStore = state => {
|
|||
}
|
||||
}
|
||||
|
||||
this.setState({selected: selected, sectionToShow: section})
|
||||
this.setState({selected, sectionToShow: section})
|
||||
},
|
||||
|
||||
updateAssignment(assignment_id, newAttrs) {
|
||||
var assignments = this.getAssignments()
|
||||
var assignment = _.find(assignments, a => a.id == assignment_id)
|
||||
const assignments = this.getAssignments()
|
||||
const assignment = _.find(assignments, a => a.id == assignment_id)
|
||||
$.extend(assignment, newAttrs)
|
||||
this.setState({assignments: assignments})
|
||||
this.setState({assignments})
|
||||
},
|
||||
|
||||
updateAssignmentDate(assignment_id, date) {
|
||||
var assignments = this.getState().assignments
|
||||
var assignment = _.find(assignments, a => a.id == assignment_id)
|
||||
//the assignment has an override and the override being updated is for the section that is currentlySelected update it
|
||||
const assignments = this.getState().assignments
|
||||
const assignment = _.find(assignments, a => a.id == assignment_id)
|
||||
// the assignment has an override and the override being updated is for the section that is currentlySelected update it
|
||||
if (
|
||||
assignment.overrideForThisSection != undefined &&
|
||||
assignment.currentlySelected.id.toString() ==
|
||||
|
@ -192,10 +192,10 @@ var PostGradesStore = state => {
|
|||
assignment.please_ignore = false
|
||||
assignment.hadOriginalErrors = true
|
||||
|
||||
this.setState({assignments: assignments})
|
||||
this.setState({assignments})
|
||||
}
|
||||
|
||||
//the section override being set from the course level of the sction dropdown
|
||||
// the section override being set from the course level of the sction dropdown
|
||||
else if (
|
||||
assignment.overrideForThisSection != undefined &&
|
||||
assignment.currentlySelected.id.toString() !=
|
||||
|
@ -205,10 +205,10 @@ var PostGradesStore = state => {
|
|||
assignment.please_ignore = false
|
||||
assignment.hadOriginalErrors = true
|
||||
|
||||
this.setState({assignments: assignments})
|
||||
this.setState({assignments})
|
||||
}
|
||||
|
||||
//update normal assignment and the 'Everyone Else' scenario if the course is currentlySelected
|
||||
// update normal assignment and the 'Everyone Else' scenario if the course is currentlySelected
|
||||
else {
|
||||
this.updateAssignment(assignment_id, {
|
||||
due_at: date,
|
||||
|
@ -223,8 +223,8 @@ var PostGradesStore = state => {
|
|||
},
|
||||
|
||||
saveAssignments() {
|
||||
var assignments = assignmentUtils.withOriginalErrorsNotIgnored(this.getAssignments())
|
||||
var course_id = this.getState().course.id
|
||||
const assignments = assignmentUtils.withOriginalErrorsNotIgnored(this.getAssignments())
|
||||
const course_id = this.getState().course.id
|
||||
_.each(assignments, a => {
|
||||
this.assignmentOverrideOrigianlErrorCheck(a)
|
||||
assignmentUtils.saveAssignmentToCanvas(course_id, a)
|
||||
|
@ -232,18 +232,18 @@ var PostGradesStore = state => {
|
|||
},
|
||||
|
||||
postGrades() {
|
||||
var assignments = assignmentUtils.notIgnored(this.getAssignments())
|
||||
var selected = this.getState().selected
|
||||
const assignments = assignmentUtils.notIgnored(this.getAssignments())
|
||||
const selected = this.getState().selected
|
||||
assignmentUtils.postGradesThroughCanvas(selected, assignments)
|
||||
},
|
||||
|
||||
getPage() {
|
||||
var state = this.getState()
|
||||
const state = this.getState()
|
||||
if (state.pleaseShowNeedsGradingPage) {
|
||||
return 'needsGrading'
|
||||
} else {
|
||||
var originals = assignmentUtils.withOriginalErrors(this.getAssignments())
|
||||
var withErrorsCount = _.keys(assignmentUtils.withErrors(this.getAssignments())).length
|
||||
const originals = assignmentUtils.withOriginalErrors(this.getAssignments())
|
||||
const withErrorsCount = _.keys(assignmentUtils.withErrors(this.getAssignments())).length
|
||||
if (withErrorsCount == 0 && (state.pleaseShowSummaryPage || originals.length == 0)) {
|
||||
return 'summary'
|
||||
} else {
|
||||
|
|
|
@ -20,9 +20,9 @@ import $ from 'jquery'
|
|||
import _ from 'underscore'
|
||||
import '../../shared/helpers/createStore'
|
||||
|
||||
let assignmentUtils = {
|
||||
const assignmentUtils = {
|
||||
copyFromGradebook(assignment) {
|
||||
var a = _.pick(assignment, ['id', 'name', 'due_at', 'needs_grading_count', 'overrides'])
|
||||
const a = _.pick(assignment, ['id', 'name', 'due_at', 'needs_grading_count', 'overrides'])
|
||||
a.please_ignore = false
|
||||
a.original_error = false
|
||||
return a
|
||||
|
@ -53,7 +53,7 @@ let assignmentUtils = {
|
|||
},
|
||||
|
||||
noDueDateForEveryoneElseOverride(a) {
|
||||
var has_overrides = a.overrides != undefined ? a.overrides.length > 0 : false
|
||||
const has_overrides = a.overrides != undefined ? a.overrides.length > 0 : false
|
||||
if (has_overrides && a.overrides.length != a.sectionCount && !a.due_at) {
|
||||
return true
|
||||
} else {
|
||||
|
@ -86,7 +86,7 @@ let assignmentUtils = {
|
|||
) {
|
||||
a.original_error = true
|
||||
}
|
||||
//for handling original error detection of a valid override for one section and an invalid override for another section
|
||||
// for handling original error detection of a valid override for one section and an invalid override for another section
|
||||
else if (
|
||||
a.overrideForThisSection != undefined &&
|
||||
a.overrideForThisSection.due_at != null &&
|
||||
|
@ -96,7 +96,7 @@ let assignmentUtils = {
|
|||
) {
|
||||
a.original_error = false
|
||||
}
|
||||
//for handling original error detection of a valid override for one section and the EveryoneElse "override" scenario
|
||||
// for handling original error detection of a valid override for one section and the EveryoneElse "override" scenario
|
||||
else if (
|
||||
a.overrideForThisSection != undefined &&
|
||||
a.overrideForThisSection.due_at != null &&
|
||||
|
@ -107,7 +107,7 @@ let assignmentUtils = {
|
|||
) {
|
||||
a.original_error = false
|
||||
}
|
||||
//for handling original error detection of an override for one section and the EveryoneElse "override" scenario but the second section is currentlySelected and IS NOT valid
|
||||
// for handling original error detection of an override for one section and the EveryoneElse "override" scenario but the second section is currentlySelected and IS NOT valid
|
||||
else if (
|
||||
a.overrideForThisSection == undefined &&
|
||||
assignmentUtils.noDueDateForEveryoneElseOverride(a) &&
|
||||
|
@ -116,7 +116,7 @@ let assignmentUtils = {
|
|||
) {
|
||||
a.original_error = true
|
||||
}
|
||||
//for handling original error detection of an override for one section and the EveryoneElse "override" scenario but the second section is currentlySelected and IS valid
|
||||
// for handling original error detection of an override for one section and the EveryoneElse "override" scenario but the second section is currentlySelected and IS valid
|
||||
else if (
|
||||
a.overrideForThisSection == undefined &&
|
||||
a.due_at != null &&
|
||||
|
@ -125,7 +125,7 @@ let assignmentUtils = {
|
|||
) {
|
||||
a.original_error = false
|
||||
}
|
||||
//for handling original error detection of an "override" in the 'EveryoneElse "override" scenario but the course is currentlySelected and IS NOT valid
|
||||
// for handling original error detection of an "override" in the 'EveryoneElse "override" scenario but the course is currentlySelected and IS NOT valid
|
||||
else if (
|
||||
a.overrideForThisSection == undefined &&
|
||||
assignmentUtils.noDueDateForEveryoneElseOverride(a) &&
|
||||
|
@ -135,7 +135,7 @@ let assignmentUtils = {
|
|||
) {
|
||||
a.original_error = true
|
||||
}
|
||||
//for handling original error detection of an "override" in the 'EveryoneElse "override" scenario but the course is currentlySelected and IS valid
|
||||
// for handling original error detection of an "override" in the 'EveryoneElse "override" scenario but the course is currentlySelected and IS valid
|
||||
else if (
|
||||
a.overrideForThisSection == undefined &&
|
||||
a.due_at != null &&
|
||||
|
@ -150,7 +150,7 @@ let assignmentUtils = {
|
|||
},
|
||||
|
||||
withOriginalErrorsNotIgnored(assignments) {
|
||||
return _.filter(assignments, a => (a.original_error || a.hadOriginalErrors) && !a.please_ignore);
|
||||
return _.filter(assignments, a => (a.original_error || a.hadOriginalErrors) && !a.please_ignore)
|
||||
},
|
||||
|
||||
withErrors(assignments) {
|
||||
|
@ -166,24 +166,24 @@ let assignmentUtils = {
|
|||
},
|
||||
|
||||
hasError(assignments, a) {
|
||||
////Decided to ignore
|
||||
// //Decided to ignore
|
||||
if (a.please_ignore) return false
|
||||
|
||||
////Not unique
|
||||
// //Not unique
|
||||
if (assignmentUtils.notUniqueName(assignments, a)) return true
|
||||
|
||||
////Name too long
|
||||
// //Name too long
|
||||
if (assignmentUtils.nameTooLong(a)) return true
|
||||
|
||||
////Name empty
|
||||
// //Name empty
|
||||
if (assignmentUtils.nameEmpty(a)) return true
|
||||
|
||||
////Non-override missing due_at
|
||||
var has_overrides = a.overrides != undefined ? a.overrides.length > 0 : false
|
||||
// //Non-override missing due_at
|
||||
const has_overrides = a.overrides != undefined ? a.overrides.length > 0 : false
|
||||
if (!has_overrides && !a.due_at) return true
|
||||
|
||||
////Override missing due_at
|
||||
var has_this_override = a.overrideForThisSection != undefined
|
||||
// //Override missing due_at
|
||||
const has_this_override = a.overrideForThisSection != undefined
|
||||
if (
|
||||
has_this_override &&
|
||||
a.overrideForThisSection.due_at == null &&
|
||||
|
@ -191,7 +191,7 @@ let assignmentUtils = {
|
|||
)
|
||||
return true
|
||||
|
||||
////Override missing due_at while currentlySelecteed is at the course level
|
||||
// //Override missing due_at while currentlySelecteed is at the course level
|
||||
if (
|
||||
has_this_override &&
|
||||
a.overrideForThisSection.due_at == null &&
|
||||
|
@ -199,10 +199,10 @@ let assignmentUtils = {
|
|||
)
|
||||
return true
|
||||
|
||||
////Has one override and another override for 'Everyone Else'
|
||||
////
|
||||
////The override for 'Everyone Else' isn't really an override and references
|
||||
////the assignments actual due_at. So we must check for this behavior
|
||||
// //Has one override and another override for 'Everyone Else'
|
||||
// //
|
||||
// //The override for 'Everyone Else' isn't really an override and references
|
||||
// //the assignments actual due_at. So we must check for this behavior
|
||||
if (
|
||||
assignmentUtils.noDueDateForEveryoneElseOverride(a) &&
|
||||
a.currentlySelected != undefined &&
|
||||
|
@ -211,7 +211,7 @@ let assignmentUtils = {
|
|||
)
|
||||
return true
|
||||
|
||||
////Has only one override but the section that is currently selected does not have an override thus causing the assignment to have due_at that is null making it invalid
|
||||
// //Has only one override but the section that is currently selected does not have an override thus causing the assignment to have due_at that is null making it invalid
|
||||
if (
|
||||
assignmentUtils.noDueDateForEveryoneElseOverride(a) &&
|
||||
a.overrideForThisSection == undefined &&
|
||||
|
@ -220,7 +220,7 @@ let assignmentUtils = {
|
|||
)
|
||||
return true
|
||||
|
||||
////'Everyone Else' scenario and the course is currentlySelected but due_at is null making it invalid
|
||||
// //'Everyone Else' scenario and the course is currentlySelected but due_at is null making it invalid
|
||||
if (
|
||||
assignmentUtils.noDueDateForEveryoneElseOverride(a) &&
|
||||
a.overrideForThisSection == undefined &&
|
||||
|
@ -230,7 +230,7 @@ let assignmentUtils = {
|
|||
)
|
||||
return true
|
||||
|
||||
////Passes all tests, looks good.
|
||||
// //Passes all tests, looks good.
|
||||
return false
|
||||
},
|
||||
|
||||
|
@ -242,9 +242,9 @@ let assignmentUtils = {
|
|||
// if the date on an override is being updated confirm by checking if the due_at is an object
|
||||
if (
|
||||
assignment.overrideForThisSection != undefined &&
|
||||
typeof assignment.overrideForThisSection.due_at == 'object'
|
||||
typeof assignment.overrideForThisSection.due_at === 'object'
|
||||
) {
|
||||
//allows the validation process to determine when it has been updated and can display the correct page
|
||||
// allows the validation process to determine when it has been updated and can display the correct page
|
||||
assignment.hadOriginalErrors = false
|
||||
var url =
|
||||
'/api/v1/courses/' +
|
||||
|
@ -253,8 +253,8 @@ let assignmentUtils = {
|
|||
assignment.id +
|
||||
'/overrides/' +
|
||||
assignment.overrideForThisSection.id
|
||||
//sets up form data to allow a single override to be updated
|
||||
var fd = new FormData()
|
||||
// sets up form data to allow a single override to be updated
|
||||
const fd = new FormData()
|
||||
fd.append(
|
||||
'assignment_override[due_at]',
|
||||
assignment.overrideForThisSection.due_at.toISOString()
|
||||
|
@ -266,7 +266,7 @@ let assignmentUtils = {
|
|||
processData: false,
|
||||
contentType: false,
|
||||
error: err => {
|
||||
var msg =
|
||||
let msg =
|
||||
'An error occurred saving assignment override, (' +
|
||||
assignment.overrideForThisSection.id +
|
||||
'). '
|
||||
|
@ -289,13 +289,13 @@ let assignmentUtils = {
|
|||
data: JSON.stringify(data),
|
||||
contentType: 'application/json; charset=utf-8',
|
||||
error: err => {
|
||||
var msg = 'An error occurred saving assignment (' + assignment.id + '). '
|
||||
let msg = 'An error occurred saving assignment (' + assignment.id + '). '
|
||||
msg += 'HTTP Error ' + data.status + ' : ' + data.statusText
|
||||
$.flashError(msg)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
//allows the validation process to determine when it has been updated and can display the correct page
|
||||
// allows the validation process to determine when it has been updated and can display the correct page
|
||||
assignment.hadOriginalErrors = false
|
||||
var url = '/api/v1/courses/' + course_id + '/assignments/' + assignment.id
|
||||
var data = {
|
||||
|
@ -309,7 +309,7 @@ let assignmentUtils = {
|
|||
data: JSON.stringify(data),
|
||||
contentType: 'application/json; charset=utf-8',
|
||||
error: err => {
|
||||
var msg = 'An error occurred saving assignment (' + assignment.id + '). '
|
||||
let msg = 'An error occurred saving assignment (' + assignment.id + '). '
|
||||
msg += 'HTTP Error ' + data.status + ' : ' + data.statusText
|
||||
$.flashError(msg)
|
||||
}
|
||||
|
@ -321,8 +321,8 @@ let assignmentUtils = {
|
|||
// Expects a list of assignments that will later be queried for grades via
|
||||
// SIS App's workers
|
||||
postGradesThroughCanvas(selected, assignments) {
|
||||
var url = '/api/v1/' + selected.type + 's/' + selected.id + '/post_grades/'
|
||||
var data = {assignments: _.map(assignments, assignment => assignment.id)}
|
||||
const url = '/api/v1/' + selected.type + 's/' + selected.id + '/post_grades/'
|
||||
const data = {assignments: _.map(assignments, assignment => assignment.id)}
|
||||
$.ajax(url, {
|
||||
type: 'POST',
|
||||
data: JSON.stringify(data),
|
||||
|
@ -335,7 +335,7 @@ let assignmentUtils = {
|
|||
}
|
||||
},
|
||||
error: err => {
|
||||
var msg =
|
||||
let msg =
|
||||
'An error occurred posting grades for (' + selected.type + ' : ' + selected.id + '). '
|
||||
msg += 'HTTP Error ' + data.status + ' : ' + data.statusText
|
||||
$.flashError(msg)
|
||||
|
|
|
@ -20,7 +20,7 @@ import I18n from 'i18n!sharedGradeFormatHelper'
|
|||
import round from 'compiled/util/round'
|
||||
import numberHelper from '../../../shared/helpers/numberHelper'
|
||||
import {scoreToPercentage} from './GradeCalculationHelper'
|
||||
import {scoreToGrade} from '../../../gradebook/GradingSchemeHelper'
|
||||
import {scoreToGrade} from '../../GradingSchemeHelper'
|
||||
|
||||
const POINTS = 'points'
|
||||
const PERCENT = 'percent'
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import GradeFormatHelper from '../../../gradebook/shared/helpers/GradeFormatHelper'
|
||||
import GradeFormatHelper from './GradeFormatHelper'
|
||||
|
||||
const DEFAULT_GRADE = ''
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
*/
|
||||
|
||||
import _ from 'underscore'
|
||||
|
||||
function uniqueEffectiveDueDates(assignment) {
|
||||
const dueDates = _.map(assignment.effectiveDueDates, dueDateInfo => {
|
||||
const dueAt = dueDateInfo.due_at
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
import _ from 'underscore'
|
||||
import I18n from 'i18n!modules'
|
||||
import React from 'react'
|
||||
import assignmentUtils from '../../gradezilla/SISGradePassback/assignmentUtils'
|
||||
import assignmentUtils from './assignmentUtils'
|
||||
import classnames from 'classnames'
|
||||
|
||||
class AssignmentCorrectionRow extends React.Component {
|
||||
|
|
|
@ -21,7 +21,7 @@ import {bool, func, shape, string} from 'prop-types'
|
|||
import ReactDOM from 'react-dom'
|
||||
import $ from 'jquery'
|
||||
import I18n from 'i18n!modules'
|
||||
import PostGradesDialog from '../../gradezilla/SISGradePassback/PostGradesDialog'
|
||||
import PostGradesDialog from './PostGradesDialog'
|
||||
import classnames from 'classnames'
|
||||
|
||||
// The PostGradesApp mounts a single "Sync Grades" button, which pops up
|
||||
|
|
|
@ -18,10 +18,10 @@
|
|||
|
||||
import _ from 'underscore'
|
||||
import React from 'react'
|
||||
import assignmentUtils from '../../gradezilla/SISGradePassback/assignmentUtils'
|
||||
import PostGradesDialogCorrectionsPage from '../../gradezilla/SISGradePassback/PostGradesDialogCorrectionsPage'
|
||||
import PostGradesDialogNeedsGradingPage from '../../gradezilla/SISGradePassback/PostGradesDialogNeedsGradingPage'
|
||||
import PostGradesDialogSummaryPage from '../../gradezilla/SISGradePassback/PostGradesDialogSummaryPage'
|
||||
import assignmentUtils from './assignmentUtils'
|
||||
import PostGradesDialogCorrectionsPage from './PostGradesDialogCorrectionsPage'
|
||||
import PostGradesDialogNeedsGradingPage from './PostGradesDialogNeedsGradingPage'
|
||||
import PostGradesDialogSummaryPage from './PostGradesDialogSummaryPage'
|
||||
|
||||
class PostGradesDialog extends React.Component {
|
||||
componentDidMount() {
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
import _ from 'underscore'
|
||||
import I18n from 'i18n!modules'
|
||||
import React from 'react'
|
||||
import assignmentUtils from '../../gradezilla/SISGradePassback/assignmentUtils'
|
||||
import AssignmentCorrectionRow from '../../gradezilla/SISGradePassback/AssignmentCorrectionRow'
|
||||
import assignmentUtils from './assignmentUtils'
|
||||
import AssignmentCorrectionRow from './AssignmentCorrectionRow'
|
||||
|
||||
class PostGradesDialogCorrectionsPage extends React.Component {
|
||||
componentDidMount() {
|
||||
|
|
|
@ -19,21 +19,21 @@
|
|||
import $ from 'jquery'
|
||||
import _ from 'underscore'
|
||||
import createStore from '../../shared/helpers/createStore'
|
||||
import assignmentUtils from '../../gradezilla/SISGradePassback/assignmentUtils'
|
||||
import assignmentUtils from './assignmentUtils'
|
||||
|
||||
var PostGradesStore = state => {
|
||||
var store = $.extend(createStore(state), {
|
||||
const PostGradesStore = state => {
|
||||
const store = $.extend(createStore(state), {
|
||||
reset() {
|
||||
var assignments = this.getAssignments()
|
||||
const assignments = this.getAssignments()
|
||||
_.each(assignments, a => (a.please_ignore = false))
|
||||
this.setState({
|
||||
assignments: assignments,
|
||||
assignments,
|
||||
pleaseShowNeedsGradingPage: false
|
||||
})
|
||||
},
|
||||
|
||||
hasAssignments() {
|
||||
var assignments = this.getAssignments()
|
||||
const assignments = this.getAssignments()
|
||||
if (assignments != undefined && assignments.length > 0) {
|
||||
return true
|
||||
} else {
|
||||
|
@ -42,12 +42,12 @@ var PostGradesStore = state => {
|
|||
},
|
||||
|
||||
getSISSectionId(section_id) {
|
||||
var sections = this.getState().sections
|
||||
const sections = this.getState().sections
|
||||
return sections && sections[section_id] ? sections[section_id].sis_section_id : null
|
||||
},
|
||||
|
||||
allOverrideIds(a) {
|
||||
var overrides = []
|
||||
const overrides = []
|
||||
_.each(a.overrides, o => {
|
||||
overrides.push(o.course_section_id)
|
||||
})
|
||||
|
@ -55,13 +55,13 @@ var PostGradesStore = state => {
|
|||
},
|
||||
|
||||
overrideForEveryone(a) {
|
||||
var overrides = this.allOverrideIds(a)
|
||||
var sections = _.keys(this.getState().sections)
|
||||
var section_ids_with_no_overrides = $(sections)
|
||||
const overrides = this.allOverrideIds(a)
|
||||
const sections = _.keys(this.getState().sections)
|
||||
const section_ids_with_no_overrides = $(sections)
|
||||
.not(overrides)
|
||||
.get()
|
||||
|
||||
var section_for_everyone = _.find(section_ids_with_no_overrides, o => {
|
||||
const section_for_everyone = _.find(section_ids_with_no_overrides, o => {
|
||||
return state.selected.id == o
|
||||
})
|
||||
return section_for_everyone
|
||||
|
@ -72,9 +72,9 @@ var PostGradesStore = state => {
|
|||
},
|
||||
|
||||
setGradeBookAssignments(gradebookAssignments) {
|
||||
var assignments = []
|
||||
for (var id in gradebookAssignments) {
|
||||
var gba = gradebookAssignments[id]
|
||||
const assignments = []
|
||||
for (const id in gradebookAssignments) {
|
||||
const gba = gradebookAssignments[id]
|
||||
// Only accept assignments suitable to post, e.g. published, post_to_sis
|
||||
if (assignmentUtils.suitableToPost(gba)) {
|
||||
// Push a copy, and only of relevant attributes
|
||||
|
@ -86,11 +86,11 @@ var PostGradesStore = state => {
|
|||
_.each(assignments, a => {
|
||||
a.original_error = assignmentUtils.hasError(assignments, a)
|
||||
})
|
||||
this.setState({assignments: assignments})
|
||||
this.setState({assignments})
|
||||
},
|
||||
|
||||
setSections(sections) {
|
||||
this.setState({sections: sections})
|
||||
this.setState({sections})
|
||||
this.setSelectedSection(this.getState().sectionToShow)
|
||||
},
|
||||
|
||||
|
@ -100,21 +100,21 @@ var PostGradesStore = state => {
|
|||
a.currentlySelected.type == 'course' &&
|
||||
a.currentlySelected.id.toString() == a.overrideForThisSection.course_section_id
|
||||
) {
|
||||
return a.due_at != null ? true : false
|
||||
return a.due_at != null
|
||||
} else if (
|
||||
a.overrideForThisSection != undefined &&
|
||||
a.currentlySelected.type == 'section' &&
|
||||
a.currentlySelected.id.toString() == a.overrideForThisSection.course_section_id
|
||||
) {
|
||||
return a.overrideForThisSection.due_at != null ? true : false
|
||||
return a.overrideForThisSection.due_at != null
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
},
|
||||
|
||||
getAssignments() {
|
||||
var assignments = this.getState().assignments
|
||||
var state = this.getState()
|
||||
const assignments = this.getState().assignments
|
||||
const state = this.getState()
|
||||
if (state.selected.type == 'section') {
|
||||
_.each(assignments, a => {
|
||||
a.recentlyUpdated = false
|
||||
|
@ -124,8 +124,8 @@ var PostGradesStore = state => {
|
|||
return override.course_section_id == state.selected.id
|
||||
})
|
||||
|
||||
//Handle assignment with overrides and the 'Everyone Else' scenario with a section that does not have any overrides
|
||||
//cleanup overrideForThisSection logic
|
||||
// Handle assignment with overrides and the 'Everyone Else' scenario with a section that does not have any overrides
|
||||
// cleanup overrideForThisSection logic
|
||||
if (a.overrideForThisSection == undefined) {
|
||||
a.selectedSectionForEveryone = this.overrideForEveryone(a)
|
||||
}
|
||||
|
@ -136,12 +136,12 @@ var PostGradesStore = state => {
|
|||
a.currentlySelected = state.selected
|
||||
a.sectionCount = _.keys(state.sections).length
|
||||
|
||||
//Course is currentlySlected with sections that have overrides AND are invalid
|
||||
// Course is currentlySlected with sections that have overrides AND are invalid
|
||||
a.overrideForThisSection = _.find(a.overrides, override => {
|
||||
return override.due_at == null || typeof override.due_at == 'object'
|
||||
return override.due_at == null || typeof override.due_at === 'object'
|
||||
})
|
||||
|
||||
//Handle assignment with overrides and the 'Everyone Else' scenario with the course currentlySelected
|
||||
// Handle assignment with overrides and the 'Everyone Else' scenario with the course currentlySelected
|
||||
if (a.overrideForThisSection == undefined) {
|
||||
a.selectedSectionForEveryone = this.overrideForEveryone(a)
|
||||
}
|
||||
|
@ -151,14 +151,14 @@ var PostGradesStore = state => {
|
|||
},
|
||||
|
||||
getAssignment(assignment_id) {
|
||||
var assignments = this.getAssignments()
|
||||
const assignments = this.getAssignments()
|
||||
return _.find(assignments, a => a.id == assignment_id)
|
||||
},
|
||||
|
||||
setSelectedSection(section) {
|
||||
var state = this.getState()
|
||||
var section_id = parseInt(section)
|
||||
var selected
|
||||
const state = this.getState()
|
||||
const section_id = parseInt(section)
|
||||
let selected
|
||||
if (section) {
|
||||
selected = {
|
||||
type: 'section',
|
||||
|
@ -173,20 +173,20 @@ var PostGradesStore = state => {
|
|||
}
|
||||
}
|
||||
|
||||
this.setState({selected: selected, sectionToShow: section})
|
||||
this.setState({selected, sectionToShow: section})
|
||||
},
|
||||
|
||||
updateAssignment(assignment_id, newAttrs) {
|
||||
var assignments = this.getAssignments()
|
||||
var assignment = _.find(assignments, a => a.id == assignment_id)
|
||||
const assignments = this.getAssignments()
|
||||
const assignment = _.find(assignments, a => a.id == assignment_id)
|
||||
$.extend(assignment, newAttrs)
|
||||
this.setState({assignments: assignments})
|
||||
this.setState({assignments})
|
||||
},
|
||||
|
||||
updateAssignmentDate(assignment_id, date) {
|
||||
var assignments = this.getState().assignments
|
||||
var assignment = _.find(assignments, a => a.id == assignment_id)
|
||||
//the assignment has an override and the override being updated is for the section that is currentlySelected update it
|
||||
const assignments = this.getState().assignments
|
||||
const assignment = _.find(assignments, a => a.id == assignment_id)
|
||||
// the assignment has an override and the override being updated is for the section that is currentlySelected update it
|
||||
if (
|
||||
assignment.overrideForThisSection != undefined &&
|
||||
assignment.currentlySelected.id.toString() ==
|
||||
|
@ -196,10 +196,10 @@ var PostGradesStore = state => {
|
|||
assignment.please_ignore = false
|
||||
assignment.hadOriginalErrors = true
|
||||
|
||||
this.setState({assignments: assignments})
|
||||
this.setState({assignments})
|
||||
}
|
||||
|
||||
//the section override being set from the course level of the sction dropdown
|
||||
// the section override being set from the course level of the sction dropdown
|
||||
else if (
|
||||
assignment.overrideForThisSection != undefined &&
|
||||
assignment.currentlySelected.id.toString() !=
|
||||
|
@ -209,10 +209,10 @@ var PostGradesStore = state => {
|
|||
assignment.please_ignore = false
|
||||
assignment.hadOriginalErrors = true
|
||||
|
||||
this.setState({assignments: assignments})
|
||||
this.setState({assignments})
|
||||
}
|
||||
|
||||
//update normal assignment and the 'Everyone Else' scenario if the course is currentlySelected
|
||||
// update normal assignment and the 'Everyone Else' scenario if the course is currentlySelected
|
||||
else {
|
||||
this.updateAssignment(assignment_id, {
|
||||
due_at: date,
|
||||
|
@ -227,8 +227,8 @@ var PostGradesStore = state => {
|
|||
},
|
||||
|
||||
saveAssignments() {
|
||||
var assignments = assignmentUtils.withOriginalErrorsNotIgnored(this.getAssignments())
|
||||
var course_id = this.getState().course.id
|
||||
const assignments = assignmentUtils.withOriginalErrorsNotIgnored(this.getAssignments())
|
||||
const course_id = this.getState().course.id
|
||||
_.each(assignments, a => {
|
||||
this.assignmentOverrideOrigianlErrorCheck(a)
|
||||
assignmentUtils.saveAssignmentToCanvas(course_id, a)
|
||||
|
@ -236,18 +236,18 @@ var PostGradesStore = state => {
|
|||
},
|
||||
|
||||
postGrades() {
|
||||
var assignments = assignmentUtils.notIgnored(this.getAssignments())
|
||||
var selected = this.getState().selected
|
||||
const assignments = assignmentUtils.notIgnored(this.getAssignments())
|
||||
const selected = this.getState().selected
|
||||
assignmentUtils.postGradesThroughCanvas(selected, assignments)
|
||||
},
|
||||
|
||||
getPage() {
|
||||
var state = this.getState()
|
||||
const state = this.getState()
|
||||
if (state.pleaseShowNeedsGradingPage) {
|
||||
return 'needsGrading'
|
||||
} else {
|
||||
var originals = assignmentUtils.withOriginalErrors(this.getAssignments())
|
||||
var withErrorsCount = _.keys(assignmentUtils.withErrors(this.getAssignments())).length
|
||||
const originals = assignmentUtils.withOriginalErrors(this.getAssignments())
|
||||
const withErrorsCount = _.keys(assignmentUtils.withErrors(this.getAssignments())).length
|
||||
if (withErrorsCount == 0 && (state.pleaseShowSummaryPage || originals.length == 0)) {
|
||||
return 'summary'
|
||||
} else {
|
||||
|
|
|
@ -20,9 +20,9 @@ import $ from 'jquery'
|
|||
import _ from 'underscore'
|
||||
import '../../shared/helpers/createStore'
|
||||
|
||||
let assignmentUtils = {
|
||||
const assignmentUtils = {
|
||||
copyFromGradebook(assignment) {
|
||||
var a = _.pick(assignment, ['id', 'name', 'due_at', 'needs_grading_count', 'overrides'])
|
||||
const a = _.pick(assignment, ['id', 'name', 'due_at', 'needs_grading_count', 'overrides'])
|
||||
a.please_ignore = false
|
||||
a.original_error = false
|
||||
return a
|
||||
|
@ -53,7 +53,7 @@ let assignmentUtils = {
|
|||
},
|
||||
|
||||
noDueDateForEveryoneElseOverride(a) {
|
||||
var has_overrides = a.overrides != undefined ? a.overrides.length > 0 : false
|
||||
const has_overrides = a.overrides != undefined ? a.overrides.length > 0 : false
|
||||
if (has_overrides && a.overrides.length != a.sectionCount && !a.due_at) {
|
||||
return true
|
||||
} else {
|
||||
|
@ -86,7 +86,7 @@ let assignmentUtils = {
|
|||
) {
|
||||
a.original_error = true
|
||||
}
|
||||
//for handling original error detection of a valid override for one section and an invalid override for another section
|
||||
// for handling original error detection of a valid override for one section and an invalid override for another section
|
||||
else if (
|
||||
a.overrideForThisSection != undefined &&
|
||||
a.overrideForThisSection.due_at != null &&
|
||||
|
@ -96,7 +96,7 @@ let assignmentUtils = {
|
|||
) {
|
||||
a.original_error = false
|
||||
}
|
||||
//for handling original error detection of a valid override for one section and the EveryoneElse "override" scenario
|
||||
// for handling original error detection of a valid override for one section and the EveryoneElse "override" scenario
|
||||
else if (
|
||||
a.overrideForThisSection != undefined &&
|
||||
a.overrideForThisSection.due_at != null &&
|
||||
|
@ -107,7 +107,7 @@ let assignmentUtils = {
|
|||
) {
|
||||
a.original_error = false
|
||||
}
|
||||
//for handling original error detection of an override for one section and the EveryoneElse "override" scenario but the second section is currentlySelected and IS NOT valid
|
||||
// for handling original error detection of an override for one section and the EveryoneElse "override" scenario but the second section is currentlySelected and IS NOT valid
|
||||
else if (
|
||||
a.overrideForThisSection == undefined &&
|
||||
assignmentUtils.noDueDateForEveryoneElseOverride(a) &&
|
||||
|
@ -116,7 +116,7 @@ let assignmentUtils = {
|
|||
) {
|
||||
a.original_error = true
|
||||
}
|
||||
//for handling original error detection of an override for one section and the EveryoneElse "override" scenario but the second section is currentlySelected and IS valid
|
||||
// for handling original error detection of an override for one section and the EveryoneElse "override" scenario but the second section is currentlySelected and IS valid
|
||||
else if (
|
||||
a.overrideForThisSection == undefined &&
|
||||
a.due_at != null &&
|
||||
|
@ -125,7 +125,7 @@ let assignmentUtils = {
|
|||
) {
|
||||
a.original_error = false
|
||||
}
|
||||
//for handling original error detection of an "override" in the 'EveryoneElse "override" scenario but the course is currentlySelected and IS NOT valid
|
||||
// for handling original error detection of an "override" in the 'EveryoneElse "override" scenario but the course is currentlySelected and IS NOT valid
|
||||
else if (
|
||||
a.overrideForThisSection == undefined &&
|
||||
assignmentUtils.noDueDateForEveryoneElseOverride(a) &&
|
||||
|
@ -135,7 +135,7 @@ let assignmentUtils = {
|
|||
) {
|
||||
a.original_error = true
|
||||
}
|
||||
//for handling original error detection of an "override" in the 'EveryoneElse "override" scenario but the course is currentlySelected and IS valid
|
||||
// for handling original error detection of an "override" in the 'EveryoneElse "override" scenario but the course is currentlySelected and IS valid
|
||||
else if (
|
||||
a.overrideForThisSection == undefined &&
|
||||
a.due_at != null &&
|
||||
|
@ -150,7 +150,7 @@ let assignmentUtils = {
|
|||
},
|
||||
|
||||
withOriginalErrorsNotIgnored(assignments) {
|
||||
return _.filter(assignments, a => (a.original_error || a.hadOriginalErrors) && !a.please_ignore);
|
||||
return _.filter(assignments, a => (a.original_error || a.hadOriginalErrors) && !a.please_ignore)
|
||||
},
|
||||
|
||||
withErrors(assignments) {
|
||||
|
@ -166,24 +166,24 @@ let assignmentUtils = {
|
|||
},
|
||||
|
||||
hasError(assignments, a) {
|
||||
////Decided to ignore
|
||||
// //Decided to ignore
|
||||
if (a.please_ignore) return false
|
||||
|
||||
////Not unique
|
||||
// //Not unique
|
||||
if (assignmentUtils.notUniqueName(assignments, a)) return true
|
||||
|
||||
////Name too long
|
||||
// //Name too long
|
||||
if (assignmentUtils.nameTooLong(a)) return true
|
||||
|
||||
////Name empty
|
||||
// //Name empty
|
||||
if (assignmentUtils.nameEmpty(a)) return true
|
||||
|
||||
////Non-override missing due_at
|
||||
var has_overrides = a.overrides != undefined ? a.overrides.length > 0 : false
|
||||
// //Non-override missing due_at
|
||||
const has_overrides = a.overrides != undefined ? a.overrides.length > 0 : false
|
||||
if (!has_overrides && !a.due_at) return true
|
||||
|
||||
////Override missing due_at
|
||||
var has_this_override = a.overrideForThisSection != undefined
|
||||
// //Override missing due_at
|
||||
const has_this_override = a.overrideForThisSection != undefined
|
||||
if (
|
||||
has_this_override &&
|
||||
a.overrideForThisSection.due_at == null &&
|
||||
|
@ -191,7 +191,7 @@ let assignmentUtils = {
|
|||
)
|
||||
return true
|
||||
|
||||
////Override missing due_at while currentlySelecteed is at the course level
|
||||
// //Override missing due_at while currentlySelecteed is at the course level
|
||||
if (
|
||||
has_this_override &&
|
||||
a.overrideForThisSection.due_at == null &&
|
||||
|
@ -199,10 +199,10 @@ let assignmentUtils = {
|
|||
)
|
||||
return true
|
||||
|
||||
////Has one override and another override for 'Everyone Else'
|
||||
////
|
||||
////The override for 'Everyone Else' isn't really an override and references
|
||||
////the assignments actual due_at. So we must check for this behavior
|
||||
// //Has one override and another override for 'Everyone Else'
|
||||
// //
|
||||
// //The override for 'Everyone Else' isn't really an override and references
|
||||
// //the assignments actual due_at. So we must check for this behavior
|
||||
if (
|
||||
assignmentUtils.noDueDateForEveryoneElseOverride(a) &&
|
||||
a.currentlySelected != undefined &&
|
||||
|
@ -211,7 +211,7 @@ let assignmentUtils = {
|
|||
)
|
||||
return true
|
||||
|
||||
////Has only one override but the section that is currently selected does not have an override thus causing the assignment to have due_at that is null making it invalid
|
||||
// //Has only one override but the section that is currently selected does not have an override thus causing the assignment to have due_at that is null making it invalid
|
||||
if (
|
||||
assignmentUtils.noDueDateForEveryoneElseOverride(a) &&
|
||||
a.overrideForThisSection == undefined &&
|
||||
|
@ -220,7 +220,7 @@ let assignmentUtils = {
|
|||
)
|
||||
return true
|
||||
|
||||
////'Everyone Else' scenario and the course is currentlySelected but due_at is null making it invalid
|
||||
// //'Everyone Else' scenario and the course is currentlySelected but due_at is null making it invalid
|
||||
if (
|
||||
assignmentUtils.noDueDateForEveryoneElseOverride(a) &&
|
||||
a.overrideForThisSection == undefined &&
|
||||
|
@ -230,7 +230,7 @@ let assignmentUtils = {
|
|||
)
|
||||
return true
|
||||
|
||||
////Passes all tests, looks good.
|
||||
// //Passes all tests, looks good.
|
||||
return false
|
||||
},
|
||||
|
||||
|
@ -242,9 +242,9 @@ let assignmentUtils = {
|
|||
// if the date on an override is being updated confirm by checking if the due_at is an object
|
||||
if (
|
||||
assignment.overrideForThisSection != undefined &&
|
||||
typeof assignment.overrideForThisSection.due_at == 'object'
|
||||
typeof assignment.overrideForThisSection.due_at === 'object'
|
||||
) {
|
||||
//allows the validation process to determine when it has been updated and can display the correct page
|
||||
// allows the validation process to determine when it has been updated and can display the correct page
|
||||
assignment.hadOriginalErrors = false
|
||||
var url =
|
||||
'/api/v1/courses/' +
|
||||
|
@ -253,8 +253,8 @@ let assignmentUtils = {
|
|||
assignment.id +
|
||||
'/overrides/' +
|
||||
assignment.overrideForThisSection.id
|
||||
//sets up form data to allow a single override to be updated
|
||||
var fd = new FormData()
|
||||
// sets up form data to allow a single override to be updated
|
||||
const fd = new FormData()
|
||||
fd.append(
|
||||
'assignment_override[due_at]',
|
||||
assignment.overrideForThisSection.due_at.toISOString()
|
||||
|
@ -266,7 +266,7 @@ let assignmentUtils = {
|
|||
processData: false,
|
||||
contentType: false,
|
||||
error: err => {
|
||||
var msg =
|
||||
let msg =
|
||||
'An error occurred saving assignment override, (' +
|
||||
assignment.overrideForThisSection.id +
|
||||
'). '
|
||||
|
@ -289,13 +289,13 @@ let assignmentUtils = {
|
|||
data: JSON.stringify(data),
|
||||
contentType: 'application/json; charset=utf-8',
|
||||
error: err => {
|
||||
var msg = 'An error occurred saving assignment (' + assignment.id + '). '
|
||||
let msg = 'An error occurred saving assignment (' + assignment.id + '). '
|
||||
msg += 'HTTP Error ' + data.status + ' : ' + data.statusText
|
||||
$.flashError(msg)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
//allows the validation process to determine when it has been updated and can display the correct page
|
||||
// allows the validation process to determine when it has been updated and can display the correct page
|
||||
assignment.hadOriginalErrors = false
|
||||
var url = '/api/v1/courses/' + course_id + '/assignments/' + assignment.id
|
||||
var data = {
|
||||
|
@ -309,7 +309,7 @@ let assignmentUtils = {
|
|||
data: JSON.stringify(data),
|
||||
contentType: 'application/json; charset=utf-8',
|
||||
error: err => {
|
||||
var msg = 'An error occurred saving assignment (' + assignment.id + '). '
|
||||
let msg = 'An error occurred saving assignment (' + assignment.id + '). '
|
||||
msg += 'HTTP Error ' + data.status + ' : ' + data.statusText
|
||||
$.flashError(msg)
|
||||
}
|
||||
|
@ -321,8 +321,8 @@ let assignmentUtils = {
|
|||
// Expects a list of assignments that will later be queried for grades via
|
||||
// SIS App's workers
|
||||
postGradesThroughCanvas(selected, assignments) {
|
||||
var url = '/api/v1/' + selected.type + 's/' + selected.id + '/post_grades/'
|
||||
var data = {assignments: _.map(assignments, assignment => assignment.id)}
|
||||
const url = '/api/v1/' + selected.type + 's/' + selected.id + '/post_grades/'
|
||||
const data = {assignments: _.map(assignments, assignment => assignment.id)}
|
||||
$.ajax(url, {
|
||||
type: 'POST',
|
||||
data: JSON.stringify(data),
|
||||
|
@ -335,7 +335,7 @@ let assignmentUtils = {
|
|||
}
|
||||
},
|
||||
error: err => {
|
||||
var msg =
|
||||
let msg =
|
||||
'An error occurred posting grades for (' + selected.type + ' : ' + selected.id + '). '
|
||||
msg += 'HTTP Error ' + data.status + ' : ' + data.statusText
|
||||
$.flashError(msg)
|
||||
|
|
|
@ -59,9 +59,7 @@ function render(options) {
|
|||
if (options.enrollmentLabel) {
|
||||
const title = I18n.t('This user is currently not able to access the course')
|
||||
// xsslint safeString.identifier title
|
||||
enrollmentStatus = ` <span title="${title}" class="label">${
|
||||
options.enrollmentLabel
|
||||
}</span>`
|
||||
enrollmentStatus = ` <span title="${title}" class="label">${options.enrollmentLabel}</span>`
|
||||
}
|
||||
|
||||
if (options.secondaryInfo) {
|
||||
|
|
|
@ -47,9 +47,7 @@ class GradebookExportManager {
|
|||
|
||||
this.exportingUrl = exportingUrl
|
||||
this.monitoringBaseUrl = GradebookExportManager.DEFAULT_MONITORING_BASE_URL
|
||||
this.attachmentBaseUrl = `${
|
||||
GradebookExportManager.DEFAULT_ATTACHMENT_BASE_URL
|
||||
}/${currentUserId}/files`
|
||||
this.attachmentBaseUrl = `${GradebookExportManager.DEFAULT_ATTACHMENT_BASE_URL}/${currentUserId}/files`
|
||||
this.currentUserId = currentUserId
|
||||
|
||||
if (existingExport) {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
*/
|
||||
|
||||
import _ from 'underscore'
|
||||
|
||||
function uniqueEffectiveDueDates(assignment) {
|
||||
const dueDates = _.map(assignment.effectiveDueDates, dueDateInfo => {
|
||||
const dueAt = dueDateInfo.due_at
|
||||
|
|
|
@ -19,13 +19,13 @@
|
|||
import _ from 'underscore'
|
||||
import $ from 'jquery'
|
||||
import 'jquery.ajaxJSON'
|
||||
import 'jquery.instructure_misc_helpers' /* replaceTags */
|
||||
import 'jquery.instructure_misc_helpers' /* replaceTags */
|
||||
import 'jquery.instructure_misc_plugins' /* showIf */
|
||||
import 'jquery.templateData'
|
||||
import 'compiled/jquery/mediaCommentThumbnail'
|
||||
import 'media_comments' /* mediaComment */
|
||||
import axios from 'axios'
|
||||
import { camelize } from 'convert_case'
|
||||
import {camelize} from 'convert_case'
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import gradingPeriodSetsApi from 'compiled/api/gradingPeriodSetsApi'
|
||||
|
@ -37,37 +37,39 @@ import CourseGradeCalculator from '../gradebook/CourseGradeCalculator'
|
|||
import {scopeToUser} from '../gradebook/EffectiveDueDates'
|
||||
import {scoreToGrade} from '../gradebook/GradingSchemeHelper'
|
||||
import GradeFormatHelper from '../gradebook/shared/helpers/GradeFormatHelper'
|
||||
import StatusPill from '../grading/StatusPill'
|
||||
import StatusPill from './StatusPill'
|
||||
import SelectMenuGroup from '../grade_summary/SelectMenuGroup'
|
||||
import {scoreToPercentage} from '../gradebook/shared/helpers/GradeCalculationHelper'
|
||||
|
||||
const GradeSummary = {
|
||||
getSelectedGradingPeriodId () {
|
||||
getSelectedGradingPeriodId() {
|
||||
const currentGradingPeriodId = ENV.current_grading_period_id
|
||||
|
||||
if (!currentGradingPeriodId || currentGradingPeriodId === '0') {
|
||||
return null;
|
||||
return null
|
||||
}
|
||||
|
||||
return currentGradingPeriodId
|
||||
},
|
||||
|
||||
getAssignmentId ($assignment) {
|
||||
return $assignment.getTemplateData({ textValues: ['assignment_id'] }).assignment_id
|
||||
getAssignmentId($assignment) {
|
||||
return $assignment.getTemplateData({textValues: ['assignment_id']}).assignment_id
|
||||
},
|
||||
|
||||
parseScoreText (text, numericalDefault, formattedDefault) {
|
||||
const defaultNumericalValue = (typeof numericalDefault === 'number') ? numericalDefault : null
|
||||
const defaultFormattedValue = (typeof formattedDefault === 'string') ? formattedDefault : '-'
|
||||
parseScoreText(text, numericalDefault, formattedDefault) {
|
||||
const defaultNumericalValue = typeof numericalDefault === 'number' ? numericalDefault : null
|
||||
const defaultFormattedValue = typeof formattedDefault === 'string' ? formattedDefault : '-'
|
||||
let numericalValue = numberHelper.parse(text)
|
||||
numericalValue = isNaN(numericalValue) ? defaultNumericalValue : numericalValue
|
||||
return {
|
||||
numericalValue,
|
||||
formattedValue: GradeFormatHelper.formatGrade(numericalValue, { defaultValue: defaultFormattedValue })
|
||||
formattedValue: GradeFormatHelper.formatGrade(numericalValue, {
|
||||
defaultValue: defaultFormattedValue
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
getOriginalScore ($assignment) {
|
||||
getOriginalScore($assignment) {
|
||||
let numericalValue = parseFloat($assignment.find('.original_points').text())
|
||||
numericalValue = isNaN(numericalValue) ? null : numericalValue
|
||||
return {
|
||||
|
@ -76,50 +78,57 @@ const GradeSummary = {
|
|||
}
|
||||
},
|
||||
|
||||
onEditWhatIfScore ($assignmentScore, $ariaAnnouncer) {
|
||||
// Store the original score so that it can be restored when the "What-If" score is reverted.
|
||||
onEditWhatIfScore($assignmentScore, $ariaAnnouncer) {
|
||||
// Store the original score so that it can be restored when the "What-If" score is reverted.
|
||||
if (!$assignmentScore.find('.grade').data('originalValue')) {
|
||||
$assignmentScore.find('.grade').data('originalValue', $assignmentScore.find('.grade').html())
|
||||
}
|
||||
|
||||
const $screenreaderLinkClone = $assignmentScore.find('.screenreader-only').clone(true)
|
||||
$assignmentScore.find('.grade').data('screenreader_link', $screenreaderLinkClone)
|
||||
$assignmentScore.find('.grade').empty().append($('#grade_entry'))
|
||||
$assignmentScore
|
||||
.find('.grade')
|
||||
.empty()
|
||||
.append($('#grade_entry'))
|
||||
$assignmentScore.find('.score_value').hide()
|
||||
$ariaAnnouncer.text(I18n.t('Enter a What-If score.'))
|
||||
|
||||
// Get the current shown score (possibly a "What-If" score)
|
||||
// and use it as the default value in the text entry field
|
||||
const whatIfScoreText = $assignmentScore.parents('.student_assignment').find('.what_if_score').text()
|
||||
// Get the current shown score (possibly a "What-If" score)
|
||||
// and use it as the default value in the text entry field
|
||||
const whatIfScoreText = $assignmentScore
|
||||
.parents('.student_assignment')
|
||||
.find('.what_if_score')
|
||||
.text()
|
||||
const score = GradeSummary.parseScoreText(whatIfScoreText, 0, '0')
|
||||
$('#grade_entry').val(score.formattedValue)
|
||||
.show()
|
||||
.focus()
|
||||
.select()
|
||||
$('#grade_entry')
|
||||
.val(score.formattedValue)
|
||||
.show()
|
||||
.focus()
|
||||
.select()
|
||||
},
|
||||
|
||||
onScoreChange ($assignment, options) {
|
||||
onScoreChange($assignment, options) {
|
||||
const originalScore = GradeSummary.getOriginalScore($assignment)
|
||||
|
||||
// parse the score entered by the user
|
||||
// parse the score entered by the user
|
||||
const enteredScoreText = $assignment.find('#grade_entry').val()
|
||||
let score = GradeSummary.parseScoreText(enteredScoreText)
|
||||
|
||||
// if the user cleared the score, use the previous What-If score
|
||||
// if the user cleared the score, use the previous What-If score
|
||||
if (score.numericalValue == null) {
|
||||
const previousWhatIfScore = $assignment.find('.what_if_score').text()
|
||||
score = GradeSummary.parseScoreText(previousWhatIfScore)
|
||||
}
|
||||
|
||||
// if there is no What-If score, use the original score
|
||||
// if there is no What-If score, use the original score
|
||||
if (score.numericalValue == null) {
|
||||
score = originalScore
|
||||
}
|
||||
|
||||
// set 'isChanged' to true if the user entered the score already on the submission
|
||||
// set 'isChanged' to true if the user entered the score already on the submission
|
||||
const isChanged = score.numericalValue != originalScore.numericalValue // eslint-disable-line eqeqeq
|
||||
|
||||
// update '.what_if_score' with the parsed value from '#grade_entry'
|
||||
// update '.what_if_score' with the parsed value from '#grade_entry'
|
||||
$assignment.find('.what_if_score').text(score.formattedValue)
|
||||
|
||||
let shouldUpdate = options.update
|
||||
|
@ -131,19 +140,28 @@ const GradeSummary = {
|
|||
const assignmentId = GradeSummary.getAssignmentId($assignment)
|
||||
|
||||
if (shouldUpdate) {
|
||||
const url = $.replaceTags($('.update_submission_url').attr('href'), 'assignment_id', assignmentId)
|
||||
// if the original score was entered, remove the student entered score
|
||||
const url = $.replaceTags(
|
||||
$('.update_submission_url').attr('href'),
|
||||
'assignment_id',
|
||||
assignmentId
|
||||
)
|
||||
// if the original score was entered, remove the student entered score
|
||||
const scoreForUpdate = isChanged ? score.numericalValue : null
|
||||
$.ajaxJSON(url, 'PUT', { 'submission[student_entered_score]': scoreForUpdate },
|
||||
(data) => {
|
||||
const updatedData = {student_entered_score: data.submission.student_entered_score}
|
||||
$assignment.fillTemplateData({ data: updatedData })
|
||||
},
|
||||
$.noop
|
||||
)
|
||||
$.ajaxJSON(
|
||||
url,
|
||||
'PUT',
|
||||
{'submission[student_entered_score]': scoreForUpdate},
|
||||
data => {
|
||||
const updatedData = {student_entered_score: data.submission.student_entered_score}
|
||||
$assignment.fillTemplateData({data: updatedData})
|
||||
},
|
||||
$.noop
|
||||
)
|
||||
}
|
||||
|
||||
$('#grade_entry').hide().appendTo($('body'))
|
||||
$('#grade_entry')
|
||||
.hide()
|
||||
.appendTo($('body'))
|
||||
|
||||
const $grade = $assignment.find('.grade')
|
||||
|
||||
|
@ -160,14 +178,19 @@ const GradeSummary = {
|
|||
if (isChanged) {
|
||||
$assignmentScore.attr('title', '')
|
||||
$scoreTeaser.text(I18n.t('This is a What-If score'))
|
||||
const $revertScore = $('#revert_score_template').clone(true).attr('id', '').show()
|
||||
const $revertScore = $('#revert_score_template')
|
||||
.clone(true)
|
||||
.attr('id', '')
|
||||
.show()
|
||||
$assignmentScore.find('.score_holder').append($revertScore)
|
||||
$grade.addClass('changed')
|
||||
|
||||
// this is to distinguish between the revert_all_scores_link in the right nav and
|
||||
// the revert arrows within the grade_summary page grid
|
||||
// this is to distinguish between the revert_all_scores_link in the right nav and
|
||||
// the revert arrows within the grade_summary page grid
|
||||
if (options.refocus) {
|
||||
setTimeout(() => { $assignment.find('.revert_score_link').focus() }, 0)
|
||||
setTimeout(() => {
|
||||
$assignment.find('.revert_score_link').focus()
|
||||
}, 0)
|
||||
}
|
||||
} else {
|
||||
setTooltipForScore($assignment)
|
||||
|
@ -176,7 +199,9 @@ const GradeSummary = {
|
|||
$assignment.find('.revert_score_link').remove()
|
||||
|
||||
if (options.refocus) {
|
||||
setTimeout(() => { $assignment.find('.grade').focus() }, 0)
|
||||
setTimeout(() => {
|
||||
$assignment.find('.grade').focus()
|
||||
}, 0)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -189,10 +214,10 @@ const GradeSummary = {
|
|||
GradeSummary.updateStudentGrades()
|
||||
},
|
||||
|
||||
onScoreRevert ($assignment, options) {
|
||||
onScoreRevert($assignment, options) {
|
||||
const $assignmentScore = $assignment.find('.assignment_score')
|
||||
const $grade = $assignmentScore.find('.grade')
|
||||
const opts = { refocus: true, skipEval: false, ...options }
|
||||
const opts = {refocus: true, skipEval: false, ...options}
|
||||
const score = GradeSummary.getOriginalScore($assignment)
|
||||
let title
|
||||
|
||||
|
@ -228,7 +253,9 @@ const GradeSummary = {
|
|||
$grade.prepend($screenreaderLinkClone)
|
||||
|
||||
if (opts.refocus) {
|
||||
setTimeout(() => { $assignment.find('.grade').focus() }, 0)
|
||||
setTimeout(() => {
|
||||
$assignment.find('.grade').focus()
|
||||
}, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -267,30 +294,30 @@ function setTooltipForScore($assignment) {
|
|||
$tooltipScoreTeaser.text(tooltipText)
|
||||
}
|
||||
|
||||
function getGradingPeriodSet () {
|
||||
function getGradingPeriodSet() {
|
||||
if (ENV.grading_period_set) {
|
||||
return gradingPeriodSetsApi.deserializeSet(ENV.grading_period_set)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
function calculateGrades () {
|
||||
function calculateGrades() {
|
||||
let grades
|
||||
|
||||
if (ENV.effective_due_dates && ENV.grading_period_set) {
|
||||
grades = CourseGradeCalculator.calculate(
|
||||
ENV.submissions,
|
||||
ENV.assignment_groups,
|
||||
ENV.group_weighting_scheme,
|
||||
getGradingPeriodSet(),
|
||||
scopeToUser(ENV.effective_due_dates, ENV.student_id)
|
||||
)
|
||||
ENV.submissions,
|
||||
ENV.assignment_groups,
|
||||
ENV.group_weighting_scheme,
|
||||
getGradingPeriodSet(),
|
||||
scopeToUser(ENV.effective_due_dates, ENV.student_id)
|
||||
)
|
||||
} else {
|
||||
grades = CourseGradeCalculator.calculate(
|
||||
ENV.submissions,
|
||||
ENV.assignment_groups,
|
||||
ENV.group_weighting_scheme
|
||||
)
|
||||
ENV.submissions,
|
||||
ENV.assignment_groups,
|
||||
ENV.group_weighting_scheme
|
||||
)
|
||||
}
|
||||
|
||||
const selectedGradingPeriodId = GradeSummary.getSelectedGradingPeriodId()
|
||||
|
@ -301,20 +328,20 @@ function calculateGrades () {
|
|||
return grades
|
||||
}
|
||||
|
||||
function canBeConvertedToGrade (score, possible) {
|
||||
function canBeConvertedToGrade(score, possible) {
|
||||
return possible > 0 && !isNaN(score)
|
||||
}
|
||||
|
||||
function calculatePercentGrade (score, possible) {
|
||||
function calculatePercentGrade(score, possible) {
|
||||
const percentGrade = scoreToPercentage(score, possible)
|
||||
return round(percentGrade, round.DEFAULT)
|
||||
}
|
||||
|
||||
function formatPercentGrade (percentGrade) {
|
||||
function formatPercentGrade(percentGrade) {
|
||||
return I18n.n(percentGrade, {percentage: true})
|
||||
}
|
||||
|
||||
function calculateGrade (score, possible) {
|
||||
function calculateGrade(score, possible) {
|
||||
if (canBeConvertedToGrade(score, possible)) {
|
||||
return formatPercentGrade(calculatePercentGrade(score, possible))
|
||||
}
|
||||
|
@ -322,13 +349,13 @@ function calculateGrade (score, possible) {
|
|||
return I18n.t('N/A')
|
||||
}
|
||||
|
||||
function subtotalByGradingPeriod () {
|
||||
function subtotalByGradingPeriod() {
|
||||
const gpset = ENV.grading_period_set
|
||||
const gpselected = GradeSummary.getSelectedGradingPeriodId()
|
||||
return ((!gpselected || gpselected === 0) && gpset && gpset.weighted)
|
||||
return (!gpselected || gpselected === 0) && gpset && gpset.weighted
|
||||
}
|
||||
|
||||
function calculateSubtotals (byGradingPeriod, calculatedGrades, currentOrFinal) {
|
||||
function calculateSubtotals(byGradingPeriod, calculatedGrades, currentOrFinal) {
|
||||
const subtotals = []
|
||||
let params
|
||||
if (byGradingPeriod) {
|
||||
|
@ -366,21 +393,21 @@ function calculateSubtotals (byGradingPeriod, calculatedGrades, currentOrFinal)
|
|||
return subtotals
|
||||
}
|
||||
|
||||
function finalGradePointsPossibleText (groupWeightingScheme, scoreWithPointsPossible) {
|
||||
if (groupWeightingScheme === "percent") {
|
||||
return "";
|
||||
function finalGradePointsPossibleText(groupWeightingScheme, scoreWithPointsPossible) {
|
||||
if (groupWeightingScheme === 'percent') {
|
||||
return ''
|
||||
}
|
||||
|
||||
const gradingPeriodId = GradeSummary.getSelectedGradingPeriodId();
|
||||
const gradingPeriodSet = getGradingPeriodSet();
|
||||
const gradingPeriodId = GradeSummary.getSelectedGradingPeriodId()
|
||||
const gradingPeriodSet = getGradingPeriodSet()
|
||||
if (gradingPeriodId == null && gradingPeriodSet && gradingPeriodSet.weighted) {
|
||||
return "";
|
||||
return ''
|
||||
}
|
||||
|
||||
return scoreWithPointsPossible;
|
||||
return scoreWithPointsPossible
|
||||
}
|
||||
|
||||
function calculateTotals (calculatedGrades, currentOrFinal, groupWeightingScheme) {
|
||||
function calculateTotals(calculatedGrades, currentOrFinal, groupWeightingScheme) {
|
||||
const gradeChanged = $('.grade.changed').length > 0
|
||||
const showTotalGradeAsPoints = ENV.show_total_grade_as_points
|
||||
|
||||
|
@ -394,16 +421,19 @@ function calculateTotals (calculatedGrades, currentOrFinal, groupWeightingScheme
|
|||
|
||||
const finalScore = calculatedGrades[currentOrFinal].score
|
||||
const finalPossible = calculatedGrades[currentOrFinal].possible
|
||||
const scoreAsPoints = `${I18n.n(finalScore, {precision: round.DEFAULT})} / ${I18n.n(finalPossible, {precision: round.DEFAULT})}`
|
||||
const scoreAsPoints = `${I18n.n(finalScore, {precision: round.DEFAULT})} / ${I18n.n(
|
||||
finalPossible,
|
||||
{precision: round.DEFAULT}
|
||||
)}`
|
||||
const scoreAsPercent = calculateGrade(finalScore, finalPossible)
|
||||
|
||||
let finalGrade
|
||||
let teaserText
|
||||
|
||||
if (gradingSchemeEnabled()) {
|
||||
const scoreToUse = overrideScorePresent() ?
|
||||
ENV.effective_final_score :
|
||||
calculatePercentGrade(finalScore, finalPossible)
|
||||
const scoreToUse = overrideScorePresent()
|
||||
? ENV.effective_final_score
|
||||
: calculatePercentGrade(finalScore, finalPossible)
|
||||
|
||||
const letterGrade = scoreToGrade(scoreToUse, ENV.grading_scheme)
|
||||
$('.final_grade .letter_grade').text(letterGrade)
|
||||
|
@ -424,16 +454,18 @@ function calculateTotals (calculatedGrades, currentOrFinal, groupWeightingScheme
|
|||
$finalGradeRow.find('.grade').text(finalGrade)
|
||||
$finalGradeRow.find('.score_teaser').text(teaserText)
|
||||
|
||||
const pointsPossibleText = finalGradePointsPossibleText(groupWeightingScheme, scoreAsPoints);
|
||||
$finalGradeRow.find('.points_possible').text(pointsPossibleText);
|
||||
const pointsPossibleText = finalGradePointsPossibleText(groupWeightingScheme, scoreAsPoints)
|
||||
$finalGradeRow.find('.points_possible').text(pointsPossibleText)
|
||||
|
||||
if (groupWeightingScheme === 'percent') {
|
||||
$finalGradeRow.find('.score_teaser').hide()
|
||||
}
|
||||
|
||||
if (gradeChanged) {
|
||||
// User changed their points for an assignment => let's let them know their updated points
|
||||
const msg = I18n.t('Based on What-If scores, the new total is now %{grade}', {grade: finalGrade})
|
||||
// User changed their points for an assignment => let's let them know their updated points
|
||||
const msg = I18n.t('Based on What-If scores, the new total is now %{grade}', {
|
||||
grade: finalGrade
|
||||
})
|
||||
$.screenReaderFlashMessageExclusive(msg)
|
||||
}
|
||||
|
||||
|
@ -452,8 +484,10 @@ function overrideScorePresent() {
|
|||
return ENV.effective_final_score != null
|
||||
}
|
||||
|
||||
function updateStudentGrades () {
|
||||
const droppedMessage = I18n.t('This assignment is dropped and will not be considered in the total calculation')
|
||||
function updateStudentGrades() {
|
||||
const droppedMessage = I18n.t(
|
||||
'This assignment is dropped and will not be considered in the total calculation'
|
||||
)
|
||||
const ignoreUngradedSubmissions = $('#only_consider_graded_assignments').attr('checked')
|
||||
const currentOrFinal = ignoreUngradedSubmissions ? 'current' : 'final'
|
||||
const groupWeightingScheme = ENV.group_weighting_scheme
|
||||
|
@ -464,12 +498,17 @@ function updateStudentGrades () {
|
|||
$('.dropped').attr('aria-label', '')
|
||||
$('.dropped').attr('title', '')
|
||||
|
||||
// mark dropped assignments
|
||||
$('.student_assignment').find('.points_possible').attr('aria-label', '')
|
||||
// mark dropped assignments
|
||||
$('.student_assignment')
|
||||
.find('.points_possible')
|
||||
.attr('aria-label', '')
|
||||
|
||||
_.forEach(calculatedGrades.assignmentGroups, (grades) => {
|
||||
_.forEach(grades[currentOrFinal].submissions, (submission) => {
|
||||
$(`#submission_${submission.submission.assignment_id}`).toggleClass('dropped', !!submission.drop)
|
||||
_.forEach(calculatedGrades.assignmentGroups, grades => {
|
||||
_.forEach(grades[currentOrFinal].submissions, submission => {
|
||||
$(`#submission_${submission.submission.assignment_id}`).toggleClass(
|
||||
'dropped',
|
||||
!!submission.drop
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -481,8 +520,8 @@ function updateStudentGrades () {
|
|||
}
|
||||
}
|
||||
|
||||
function updateScoreForAssignment (assignmentId, score) {
|
||||
const submission = _.find(ENV.submissions, s => (`${s.assignment_id}`) === (`${assignmentId}`))
|
||||
function updateScoreForAssignment(assignmentId, score) {
|
||||
const submission = _.find(ENV.submissions, s => `${s.assignment_id}` === `${assignmentId}`)
|
||||
|
||||
if (submission) {
|
||||
submission.score = score
|
||||
|
@ -491,15 +530,15 @@ function updateScoreForAssignment (assignmentId, score) {
|
|||
}
|
||||
}
|
||||
|
||||
function bindShowAllDetailsButton ($ariaAnnouncer) {
|
||||
$('#show_all_details_button').click((event) => {
|
||||
function bindShowAllDetailsButton($ariaAnnouncer) {
|
||||
$('#show_all_details_button').click(event => {
|
||||
event.preventDefault()
|
||||
const $button = $('#show_all_details_button')
|
||||
$button.toggleClass('showAll')
|
||||
|
||||
if ($button.hasClass('showAll')) {
|
||||
$button.text(I18n.t('Hide All Details'))
|
||||
$('tr.student_assignment.editable').each(function () {
|
||||
$('tr.student_assignment.editable').each(function() {
|
||||
const assignmentId = $(this).getTemplateValue('assignment_id')
|
||||
const muted = $(this).data('muted')
|
||||
if (!muted) {
|
||||
|
@ -529,11 +568,11 @@ function goToURL(url) {
|
|||
}
|
||||
|
||||
function saveAssignmentOrder(order) {
|
||||
return axios.post(ENV.save_assignment_order_url, { assignment_order: order })
|
||||
return axios.post(ENV.save_assignment_order_url, {assignment_order: order})
|
||||
}
|
||||
|
||||
function coursesWithGrades() {
|
||||
return ENV.courses_with_grades.map((course) => camelize(course))
|
||||
return ENV.courses_with_grades.map(course => camelize(course))
|
||||
}
|
||||
|
||||
function getSelectMenuGroupProps() {
|
||||
|
@ -560,17 +599,17 @@ function renderSelectMenuGroup() {
|
|||
)
|
||||
}
|
||||
|
||||
function setup () {
|
||||
$(document).ready(function () {
|
||||
function setup() {
|
||||
$(document).ready(function() {
|
||||
GradeSummary.updateStudentGrades()
|
||||
const showAllWhatIfButton = $(this).find('#student-grades-whatif button')
|
||||
const revertButton = $(this).find('#revert-all-to-actual-score')
|
||||
const $ariaAnnouncer = $(this).find('#aria-announcer')
|
||||
|
||||
$('.revert_all_scores_link').click((event) => {
|
||||
$('.revert_all_scores_link').click(event => {
|
||||
event.preventDefault()
|
||||
// we pass in refocus: false here so the focus won't go to the revert arrows within the grid
|
||||
$('#grades_summary .revert_score_link').each(function () {
|
||||
// we pass in refocus: false here so the focus won't go to the revert arrows within the grid
|
||||
$('#grades_summary .revert_score_link').each(function() {
|
||||
$(this).trigger('click', {skipEval: true, refocus: false})
|
||||
})
|
||||
$('#.show_guess_grades.exists').show()
|
||||
|
@ -579,36 +618,42 @@ function setup () {
|
|||
$.screenReaderFlashMessageExclusive(I18n.t('Grades are now reverted to original scores'))
|
||||
})
|
||||
|
||||
// manages toggling and screenreader focus for comments, scoring, and rubric details
|
||||
$('.toggle_comments_link, .toggle_score_details_link, ' +
|
||||
'.toggle_rubric_assessments_link, .toggle_final_grade_info').click(function (event) {
|
||||
event.preventDefault()
|
||||
const $row = $(`#${$(this).attr('aria-controls')}`)
|
||||
const originEl = this
|
||||
// manages toggling and screenreader focus for comments, scoring, and rubric details
|
||||
$(
|
||||
'.toggle_comments_link, .toggle_score_details_link, ' +
|
||||
'.toggle_rubric_assessments_link, .toggle_final_grade_info'
|
||||
).click(function(event) {
|
||||
event.preventDefault()
|
||||
const $row = $(`#${$(this).attr('aria-controls')}`)
|
||||
const originEl = this
|
||||
|
||||
$(originEl).attr('aria-expanded', $row.css('display') === 'none')
|
||||
$row.toggle()
|
||||
$(originEl).attr('aria-expanded', $row.css('display') === 'none')
|
||||
$row.toggle()
|
||||
|
||||
if ($row.css('display') !== 'none') {
|
||||
$row.find('.screenreader-toggle').focus()
|
||||
}
|
||||
})
|
||||
if ($row.css('display') !== 'none') {
|
||||
$row.find('.screenreader-toggle').focus()
|
||||
}
|
||||
})
|
||||
|
||||
$('.screenreader-toggle').click(function (event) {
|
||||
$('.screenreader-toggle').click(function(event) {
|
||||
event.preventDefault()
|
||||
const ariaControl = $(this).data('aria')
|
||||
const originEl = $(`a[aria-controls='${ariaControl}']`)
|
||||
|
||||
$(originEl).attr('aria-expanded', false)
|
||||
$(originEl).focus()
|
||||
$(this).closest('.rubric_assessments, .comments').hide()
|
||||
$(this)
|
||||
.closest('.rubric_assessments, .comments')
|
||||
.hide()
|
||||
})
|
||||
|
||||
function editWhatIfScore (event) {
|
||||
function editWhatIfScore(event) {
|
||||
if (event.type === 'click' || event.keyCode === 13) {
|
||||
if ($('#grades_summary.editable').length === 0 ||
|
||||
$(this).find('#grade_entry').length > 0 ||
|
||||
$(event.target).closest('.revert_score_link').length > 0) {
|
||||
if (
|
||||
$('#grades_summary.editable').length === 0 ||
|
||||
$(this).find('#grade_entry').length > 0 ||
|
||||
$(event.target).closest('.revert_score_link').length > 0
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -618,32 +663,35 @@ function setup () {
|
|||
|
||||
$('.student_assignment.editable .assignment_score').on('click keypress', editWhatIfScore)
|
||||
|
||||
$('#grade_entry').keydown(function (event) {
|
||||
$('#grade_entry').keydown(function(event) {
|
||||
if (event.keyCode === 13) {
|
||||
// Enter Key: Finish Changes
|
||||
// Enter Key: Finish Changes
|
||||
$ariaAnnouncer.text('')
|
||||
$(this)[0].blur()
|
||||
} else if (event.keyCode === 27) {
|
||||
// Escape Key: Clear the Text Field
|
||||
// Escape Key: Clear the Text Field
|
||||
$ariaAnnouncer.text('')
|
||||
const val = $(this).parents('.student_assignment')
|
||||
.addClass('dont_update')
|
||||
.find('.original_score')
|
||||
.text()
|
||||
$(this).val(val || '')[0].blur()
|
||||
const val = $(this)
|
||||
.parents('.student_assignment')
|
||||
.addClass('dont_update')
|
||||
.find('.original_score')
|
||||
.text()
|
||||
$(this)
|
||||
.val(val || '')[0]
|
||||
.blur()
|
||||
}
|
||||
})
|
||||
|
||||
$('#grades_summary .student_assignment').bind('score_change', function (_event, options) {
|
||||
$('#grades_summary .student_assignment').bind('score_change', function(_event, options) {
|
||||
GradeSummary.onScoreChange($(this), options)
|
||||
})
|
||||
|
||||
$('#grade_entry').blur(function () {
|
||||
$('#grade_entry').blur(function() {
|
||||
const $assignment = $(this).parents('.student_assignment')
|
||||
$assignment.triggerHandler('score_change', { update: true, refocus: true })
|
||||
$assignment.triggerHandler('score_change', {update: true, refocus: true})
|
||||
})
|
||||
|
||||
$('#grades_summary').delegate('.revert_score_link', 'click', function (event, options) {
|
||||
$('#grades_summary').delegate('.revert_score_link', 'click', function(event, options) {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
|
||||
|
@ -652,20 +700,27 @@ function setup () {
|
|||
|
||||
$('#grades_summary:not(.editable) .assignment_score').css('cursor', 'default')
|
||||
|
||||
$('#grades_summary tr').hover(function () {
|
||||
$(this).find('th.title .context').addClass('context_hover')
|
||||
}, function () {
|
||||
$(this).find('th.title .context').removeClass('context_hover')
|
||||
})
|
||||
$('#grades_summary tr').hover(
|
||||
function() {
|
||||
$(this)
|
||||
.find('th.title .context')
|
||||
.addClass('context_hover')
|
||||
},
|
||||
function() {
|
||||
$(this)
|
||||
.find('th.title .context')
|
||||
.removeClass('context_hover')
|
||||
}
|
||||
)
|
||||
|
||||
$('.show_guess_grades_link').click(() => {
|
||||
$('#grades_summary .student_entered_score').each(function () {
|
||||
$('#grades_summary .student_entered_score').each(function() {
|
||||
const score = GradeSummary.parseScoreText($(this).text())
|
||||
if (score.numericalValue != null) {
|
||||
const $assignment = $(this).parents('.student_assignment')
|
||||
$assignment.find('.what_if_score').text(score.formattedValue)
|
||||
$assignment.find('.score_value').hide()
|
||||
$assignment.triggerHandler('score_change', { update: false, refocus: false })
|
||||
$assignment.triggerHandler('score_change', {update: false, refocus: false})
|
||||
}
|
||||
})
|
||||
$('.show_guess_grades').hide()
|
||||
|
@ -673,16 +728,18 @@ function setup () {
|
|||
$.screenReaderFlashMessageExclusive(I18n.t('Grades are now showing what-if scores'))
|
||||
})
|
||||
|
||||
$('#grades_summary .student_entered_score').each(function () {
|
||||
$('#grades_summary .student_entered_score').each(function() {
|
||||
const score = GradeSummary.parseScoreText($(this).text())
|
||||
if (score.numericalValue != null) {
|
||||
$('.show_guess_grades').show().addClass('exists')
|
||||
$('.show_guess_grades')
|
||||
.show()
|
||||
.addClass('exists')
|
||||
}
|
||||
})
|
||||
|
||||
$('.comments .play_comment_link').mediaCommentThumbnail('normal')
|
||||
|
||||
$('.play_comment_link').live('click', function (event) {
|
||||
$('.play_comment_link').live('click', function(event) {
|
||||
event.preventDefault()
|
||||
const $parent = $(this).parents('.comment_media')
|
||||
const commentId = $parent.getTemplateData({textValues: ['media_comment_id']}).media_comment_id
|
||||
|
@ -698,9 +755,11 @@ function setup () {
|
|||
}
|
||||
})
|
||||
|
||||
$('#only_consider_graded_assignments').change(() => {
|
||||
GradeSummary.updateStudentGrades()
|
||||
}).triggerHandler('change')
|
||||
$('#only_consider_graded_assignments')
|
||||
.change(() => {
|
||||
GradeSummary.updateStudentGrades()
|
||||
})
|
||||
.triggerHandler('change')
|
||||
|
||||
bindShowAllDetailsButton($ariaAnnouncer)
|
||||
StatusPill.renderPills()
|
||||
|
|
|
@ -70,6 +70,5 @@ export function resolveHideAssignmentGradesStatus(progress) {
|
|||
return resolveProgress({
|
||||
url: `/api/v1/progress/${progress.id}`,
|
||||
workflow_state: progress.workflowState
|
||||
})
|
||||
.then(results => camelize(results))
|
||||
}).then(results => camelize(results))
|
||||
}
|
||||
|
|
|
@ -228,12 +228,7 @@ class GradingStandard extends React.Component {
|
|||
renderSaveButton = () => {
|
||||
if (this.state.saving) {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
ref="saveButton"
|
||||
className="btn btn-primary save_button"
|
||||
disabled
|
||||
>
|
||||
<button type="button" ref="saveButton" className="btn btn-primary save_button" disabled>
|
||||
{I18n.t('Saving...')}
|
||||
</button>
|
||||
)
|
||||
|
|
|
@ -30,60 +30,66 @@
|
|||
// refreshGradesCb executes the normal speedGrader refresh grades
|
||||
// actions, plus whatever callback is passed in as an argument
|
||||
|
||||
|
||||
function quizzesNextSpeedGrading (EG, $iframe_holder, registerCb, refreshGradesCb, speedGraderWindow = window) {
|
||||
function quizzesNextChange (submission) {
|
||||
EG.refreshSubmissionsToView();
|
||||
if (submission && submission.submission_history) {
|
||||
let lastIndex = submission.submission_history.length - 1;
|
||||
// set submission to selected in dropdown
|
||||
$("#submission_to_view option:eq(" + lastIndex + ")").attr("selected", "selected");
|
||||
}
|
||||
EG.showGrade();
|
||||
EG.showDiscussion();
|
||||
EG.showRubric();
|
||||
EG.updateStatsInHeader();
|
||||
EG.refreshFullRubric();
|
||||
EG.setGradeReadOnly(true);
|
||||
function quizzesNextSpeedGrading(
|
||||
EG,
|
||||
$iframe_holder,
|
||||
registerCb,
|
||||
refreshGradesCb,
|
||||
speedGraderWindow = window
|
||||
) {
|
||||
function quizzesNextChange(submission) {
|
||||
EG.refreshSubmissionsToView()
|
||||
if (submission && submission.submission_history) {
|
||||
const lastIndex = submission.submission_history.length - 1
|
||||
// set submission to selected in dropdown
|
||||
$('#submission_to_view option:eq(' + lastIndex + ')').attr('selected', 'selected')
|
||||
}
|
||||
|
||||
// gets the submission from the speed_grader.js
|
||||
// function that will call this
|
||||
function postChangeSubmissionMessage (submission) {
|
||||
var frame = $iframe_holder.children()[0];
|
||||
if (frame && frame.contentWindow) {
|
||||
frame.contentWindow.postMessage(
|
||||
{
|
||||
submission,
|
||||
subject: 'canvas.speedGraderSubmissionChange'
|
||||
}, '*'
|
||||
);
|
||||
}
|
||||
EG.showSubmissionDetails();
|
||||
quizzesNextChange(submission);
|
||||
}
|
||||
|
||||
function onMessage (e) {
|
||||
var message = e.data;
|
||||
switch (message.subject) {
|
||||
case 'quizzesNext.register':
|
||||
EG.setGradeReadOnly(true);
|
||||
registerCb(postChangeSubmissionMessage);
|
||||
break;
|
||||
case 'quizzesNext.submissionUpdate':
|
||||
refreshGradesCb(quizzesNextChange);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
speedGraderWindow.addEventListener('message', onMessage);
|
||||
|
||||
// expose for testing
|
||||
return {
|
||||
onMessage: onMessage,
|
||||
postChangeSubmissionMessage: postChangeSubmissionMessage,
|
||||
quizzesNextChange: quizzesNextChange
|
||||
};
|
||||
EG.showGrade()
|
||||
EG.showDiscussion()
|
||||
EG.showRubric()
|
||||
EG.updateStatsInHeader()
|
||||
EG.refreshFullRubric()
|
||||
EG.setGradeReadOnly(true)
|
||||
}
|
||||
|
||||
// gets the submission from the speed_grader.js
|
||||
// function that will call this
|
||||
function postChangeSubmissionMessage(submission) {
|
||||
const frame = $iframe_holder.children()[0]
|
||||
if (frame && frame.contentWindow) {
|
||||
frame.contentWindow.postMessage(
|
||||
{
|
||||
submission,
|
||||
subject: 'canvas.speedGraderSubmissionChange'
|
||||
},
|
||||
'*'
|
||||
)
|
||||
}
|
||||
EG.showSubmissionDetails()
|
||||
quizzesNextChange(submission)
|
||||
}
|
||||
|
||||
function onMessage(e) {
|
||||
const message = e.data
|
||||
switch (message.subject) {
|
||||
case 'quizzesNext.register':
|
||||
EG.setGradeReadOnly(true)
|
||||
registerCb(postChangeSubmissionMessage)
|
||||
break
|
||||
case 'quizzesNext.submissionUpdate':
|
||||
refreshGradesCb(quizzesNextChange)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
speedGraderWindow.addEventListener('message', onMessage)
|
||||
|
||||
// expose for testing
|
||||
return {
|
||||
onMessage,
|
||||
postChangeSubmissionMessage,
|
||||
quizzesNextChange
|
||||
}
|
||||
}
|
||||
|
||||
export default quizzesNextSpeedGrading
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import GraphiQLExplorer from 'graphiql-explorer';
|
||||
import GraphiQLExplorer from 'graphiql-explorer'
|
||||
|
||||
// makeDefaultArg and getDefulatScalarArgValue
|
||||
// are used to fill in the default argument for
|
||||
|
@ -26,7 +26,7 @@ import GraphiQLExplorer from 'graphiql-explorer';
|
|||
// https://github.com/OneGraph/graphiql-explorer-example/blob/master/src/CustomArgs.js
|
||||
|
||||
export function makeDefaultArg(_parentField, _arg) {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
export function getDefaultScalarArgValue(parentField, arg, argType) {
|
||||
|
@ -35,5 +35,5 @@ export function getDefaultScalarArgValue(parentField, arg, argType) {
|
|||
if (argType.name === 'ID') {
|
||||
return {kind: 'StringValue', value: '1'}
|
||||
}
|
||||
return GraphiQLExplorer.defaultValue(argType);
|
||||
return GraphiQLExplorer.defaultValue(argType)
|
||||
}
|
||||
|
|
|
@ -19,20 +19,18 @@
|
|||
import React from 'react'
|
||||
import GraphiQL from 'graphiql'
|
||||
import GraphiQLExplorer from 'graphiql-explorer'
|
||||
import {getIntrospectionQuery, buildClientSchema} from 'graphql';
|
||||
import {getIntrospectionQuery, buildClientSchema} from 'graphql'
|
||||
import axios from 'axios'
|
||||
import 'graphiql/graphiql.css'
|
||||
import {makeDefaultArg, getDefaultScalarArgValue} from './CustomArgs';
|
||||
import {makeDefaultArg, getDefaultScalarArgValue} from './CustomArgs'
|
||||
import StorageAPI from 'graphiql/dist/utility/StorageAPI'
|
||||
|
||||
function fetcher (params) {
|
||||
return axios.post(
|
||||
'/api/graphql',
|
||||
JSON.stringify(params),
|
||||
{
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
}
|
||||
).then(({data}) => data)
|
||||
function fetcher(params) {
|
||||
return axios
|
||||
.post('/api/graphql', JSON.stringify(params), {
|
||||
headers: {'Content-Type': 'application/json'}
|
||||
})
|
||||
.then(({data}) => data)
|
||||
}
|
||||
|
||||
export default class GraphiQLApp extends React.Component {
|
||||
|
@ -53,7 +51,7 @@ export default class GraphiQLApp extends React.Component {
|
|||
|
||||
componentDidMount() {
|
||||
return fetcher({
|
||||
query: getIntrospectionQuery(),
|
||||
query: getIntrospectionQuery()
|
||||
}).then(result => {
|
||||
this.setState({
|
||||
schema: buildClientSchema(result.data)
|
||||
|
@ -61,7 +59,7 @@ export default class GraphiQLApp extends React.Component {
|
|||
})
|
||||
}
|
||||
|
||||
_handleEditQuery = (query) => {
|
||||
_handleEditQuery = query => {
|
||||
this.setState({query})
|
||||
}
|
||||
|
||||
|
@ -88,7 +86,9 @@ export default class GraphiQLApp extends React.Component {
|
|||
makeDefaultArg={makeDefaultArg}
|
||||
/>
|
||||
<GraphiQL
|
||||
ref={ref => {this._graphiql = ref}}
|
||||
ref={ref => {
|
||||
this._graphiql = ref
|
||||
}}
|
||||
fetcher={fetcher}
|
||||
schema={schema}
|
||||
query={query}
|
||||
|
|
|
@ -24,11 +24,11 @@ import I18n from 'i18n!student_groups'
|
|||
import {Spinner} from '@instructure/ui-elements'
|
||||
import UserCollection from 'compiled/collections/UserCollection'
|
||||
import ContextGroupCollection from 'compiled/collections/ContextGroupCollection'
|
||||
import BackboneState from '../groups/mixins/BackboneState'
|
||||
import PaginatedGroupList from '../groups/components/PaginatedGroupList'
|
||||
import Filter from '../groups/components/Filter'
|
||||
import NewGroupDialog from '../groups/components/NewGroupDialog'
|
||||
import ManageGroupDialog from '../groups/components/ManageGroupDialog'
|
||||
import BackboneState from './mixins/BackboneState'
|
||||
import PaginatedGroupList from './components/PaginatedGroupList'
|
||||
import Filter from './components/Filter'
|
||||
import NewGroupDialog from './components/NewGroupDialog'
|
||||
import ManageGroupDialog from './components/ManageGroupDialog'
|
||||
|
||||
const StudentView = createReactClass({
|
||||
displayName: 'StudentView',
|
||||
|
@ -150,7 +150,7 @@ const StudentView = createReactClass({
|
|||
},
|
||||
|
||||
_extendAttribute(model, attribute, hash) {
|
||||
const copy = Object.assign({}, model.get(attribute))
|
||||
const copy = {...model.get(attribute)}
|
||||
model.set(attribute, Object.assign(copy, hash))
|
||||
},
|
||||
|
||||
|
|
|
@ -21,9 +21,9 @@ import _ from 'underscore'
|
|||
import $ from 'jquery'
|
||||
import React from 'react'
|
||||
import createReactClass from 'create-react-class'
|
||||
import BackboneState from '../../groups/mixins/BackboneState'
|
||||
import PaginatedUserCheckList from '../../groups/components/PaginatedUserCheckList'
|
||||
import InfiniteScroll from '../../groups/mixins/InfiniteScroll'
|
||||
import BackboneState from '../mixins/BackboneState'
|
||||
import PaginatedUserCheckList from './PaginatedUserCheckList'
|
||||
import InfiniteScroll from '../mixins/InfiniteScroll'
|
||||
import 'jquery.instructure_forms'
|
||||
|
||||
const ManageGroupDialog = createReactClass({
|
||||
|
|
|
@ -21,9 +21,9 @@ import _ from 'underscore'
|
|||
import $ from 'jquery'
|
||||
import React from 'react'
|
||||
import createReactClass from 'create-react-class'
|
||||
import BackboneState from '../../groups/mixins/BackboneState'
|
||||
import PaginatedUserCheckList from '../../groups/components/PaginatedUserCheckList'
|
||||
import InfiniteScroll from '../../groups/mixins/InfiniteScroll'
|
||||
import BackboneState from '../mixins/BackboneState'
|
||||
import PaginatedUserCheckList from './PaginatedUserCheckList'
|
||||
import InfiniteScroll from '../mixins/InfiniteScroll'
|
||||
import 'jquery.instructure_forms'
|
||||
|
||||
const NewGroupDialog = createReactClass({
|
||||
|
@ -120,7 +120,7 @@ const NewGroupDialog = createReactClass({
|
|||
checked={this.state.checked}
|
||||
users={users}
|
||||
onUserCheck={this._onUserCheck}
|
||||
labelId='inviteLabel'
|
||||
labelId="inviteLabel"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
import I18n from 'i18n!student_groups'
|
||||
import React from 'react'
|
||||
import createReactClass from 'create-react-class'
|
||||
import InfiniteScroll from '../../groups/mixins/InfiniteScroll'
|
||||
import Group from '../../groups/components/Group'
|
||||
import InfiniteScroll from '../mixins/InfiniteScroll'
|
||||
import Group from './Group'
|
||||
|
||||
const PaginatedGroupList = createReactClass({
|
||||
displayName: 'PaginatedGroupList',
|
||||
|
|
|
@ -17,50 +17,64 @@
|
|||
*/
|
||||
|
||||
import Backbone from 'Backbone'
|
||||
var BackboneState = {
|
||||
_forceUpdate() {this.forceUpdate()}, // strips off args that backbone sends and react incorrectly believes is a callback
|
||||
|
||||
_on(object, name, callback, context) {
|
||||
object.on(name, callback, context);
|
||||
},
|
||||
const BackboneState = {
|
||||
_forceUpdate() {
|
||||
this.forceUpdate()
|
||||
}, // strips off args that backbone sends and react incorrectly believes is a callback
|
||||
|
||||
_off(object, name, callback, context) {
|
||||
object.off(name, callback, context);
|
||||
},
|
||||
_on(object, name, callback, context) {
|
||||
object.on(name, callback, context)
|
||||
},
|
||||
|
||||
_listen(func, state, exceptState) {
|
||||
for (var stateKey in state) {
|
||||
if (state.hasOwnProperty(stateKey)) {
|
||||
if (!(exceptState && exceptState.hasOwnProperty(stateKey) && state[stateKey] === exceptState[stateKey])) {
|
||||
var stateObject = state[stateKey];
|
||||
if (stateObject instanceof Backbone.Collection) {
|
||||
func(stateObject, 'add remove reset sort fetch beforeFetch change', this._forceUpdate, this);
|
||||
} else if (stateObject instanceof Backbone.Model) {
|
||||
func(stateObject, 'change', this._forceUpdate, this);
|
||||
}
|
||||
_off(object, name, callback, context) {
|
||||
object.off(name, callback, context)
|
||||
},
|
||||
|
||||
_listen(func, state, exceptState) {
|
||||
for (const stateKey in state) {
|
||||
if (state.hasOwnProperty(stateKey)) {
|
||||
if (
|
||||
!(
|
||||
exceptState &&
|
||||
exceptState.hasOwnProperty(stateKey) &&
|
||||
state[stateKey] === exceptState[stateKey]
|
||||
)
|
||||
) {
|
||||
const stateObject = state[stateKey]
|
||||
if (stateObject instanceof Backbone.Collection) {
|
||||
func(
|
||||
stateObject,
|
||||
'add remove reset sort fetch beforeFetch change',
|
||||
this._forceUpdate,
|
||||
this
|
||||
)
|
||||
} else if (stateObject instanceof Backbone.Model) {
|
||||
func(stateObject, 'change', this._forceUpdate, this)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
componentWillUpdate(nextProps, nextState) {
|
||||
// stop listening to backbone objects in state that aren't in nextState
|
||||
this._listen(this._off, this.state, nextState);
|
||||
},
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
// start listening to backbone objects in state that aren't in prevState
|
||||
this._listen(this._on, this.state, prevState);
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
// start listening to backbone objects in state
|
||||
this._listen(this._on, this.state);
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
// stop listening to backbone objects in state
|
||||
this._listen(this._off, this.state);
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
componentWillUpdate(nextProps, nextState) {
|
||||
// stop listening to backbone objects in state that aren't in nextState
|
||||
this._listen(this._off, this.state, nextState)
|
||||
},
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
// start listening to backbone objects in state that aren't in prevState
|
||||
this._listen(this._on, this.state, prevState)
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
// start listening to backbone objects in state
|
||||
this._listen(this._on, this.state)
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
// stop listening to backbone objects in state
|
||||
this._listen(this._off, this.state)
|
||||
}
|
||||
}
|
||||
export default BackboneState
|
||||
|
|
|
@ -18,54 +18,59 @@
|
|||
|
||||
import _ from 'underscore'
|
||||
import ReactDOM from 'react-dom'
|
||||
var InfiniteScroll = {
|
||||
topPosition(el) {
|
||||
if (!el) {
|
||||
return 0;
|
||||
}
|
||||
return el.offsetTop + this.topPosition(el.offsetParent);
|
||||
},
|
||||
|
||||
loadMoreIfNeeded: _.throttle(function() {
|
||||
var atBottom = false;
|
||||
if (this.scrollElement) {
|
||||
atBottom = this.scrollElement.scrollTop + this.scrollElement.clientHeight + 100 >= this.scrollElement.scrollHeight;
|
||||
} else {
|
||||
var el = ReactDOM.findDOMNode(this)
|
||||
var scrollTop = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
|
||||
atBottom = this.topPosition(el) + el.offsetHeight - scrollTop - window.innerHeight < 100;
|
||||
}
|
||||
if (atBottom) {
|
||||
this.loadMore();
|
||||
}
|
||||
}, 100),
|
||||
const InfiniteScroll = {
|
||||
topPosition(el) {
|
||||
if (!el) {
|
||||
return 0
|
||||
}
|
||||
return el.offsetTop + this.topPosition(el.offsetParent)
|
||||
},
|
||||
|
||||
attachScroll() {
|
||||
if (this.refs.scrollElement) {
|
||||
this.scrollElement = this.refs.scrollElement
|
||||
}
|
||||
(this.scrollElement || window).addEventListener('scroll', this.loadMoreIfNeeded);
|
||||
(this.scrollElement || window).addEventListener('resize', this.loadMoreIfNeeded);
|
||||
this.loadMoreIfNeeded();
|
||||
},
|
||||
loadMoreIfNeeded: _.throttle(function() {
|
||||
let atBottom = false
|
||||
if (this.scrollElement) {
|
||||
atBottom =
|
||||
this.scrollElement.scrollTop + this.scrollElement.clientHeight + 100 >=
|
||||
this.scrollElement.scrollHeight
|
||||
} else {
|
||||
const el = ReactDOM.findDOMNode(this)
|
||||
const scrollTop =
|
||||
window.pageYOffset !== undefined
|
||||
? window.pageYOffset
|
||||
: (document.documentElement || document.body.parentNode || document.body).scrollTop
|
||||
atBottom = this.topPosition(el) + el.offsetHeight - scrollTop - window.innerHeight < 100
|
||||
}
|
||||
if (atBottom) {
|
||||
this.loadMore()
|
||||
}
|
||||
}, 100),
|
||||
|
||||
detachScroll() {
|
||||
(this.scrollElement || window).removeEventListener('scroll', this.loadMoreIfNeeded);
|
||||
(this.scrollElement || window).removeEventListener('resize', this.loadMoreIfNeeded);
|
||||
this.scrollElement = null;
|
||||
},
|
||||
attachScroll() {
|
||||
if (this.refs.scrollElement) {
|
||||
this.scrollElement = this.refs.scrollElement
|
||||
}
|
||||
;(this.scrollElement || window).addEventListener('scroll', this.loadMoreIfNeeded)
|
||||
;(this.scrollElement || window).addEventListener('resize', this.loadMoreIfNeeded)
|
||||
this.loadMoreIfNeeded()
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
this.attachScroll();
|
||||
},
|
||||
detachScroll() {
|
||||
;(this.scrollElement || window).removeEventListener('scroll', this.loadMoreIfNeeded)
|
||||
;(this.scrollElement || window).removeEventListener('resize', this.loadMoreIfNeeded)
|
||||
this.scrollElement = null
|
||||
},
|
||||
|
||||
componentDidUpdate() {
|
||||
this.attachScroll();
|
||||
},
|
||||
componentDidMount() {
|
||||
this.attachScroll()
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
this.detachScroll();
|
||||
},
|
||||
componentDidUpdate() {
|
||||
this.attachScroll()
|
||||
},
|
||||
|
||||
};
|
||||
componentWillUnmount() {
|
||||
this.detachScroll()
|
||||
}
|
||||
}
|
||||
export default InfiniteScroll
|
||||
|
|
|
@ -76,15 +76,17 @@ class TeacherFeedbackForm extends React.Component {
|
|||
}
|
||||
|
||||
renderCourseOptions = () => {
|
||||
const options = this.state.courses.filter(c => !c.access_restricted_by_date).map(c => {
|
||||
const value = `course_${c.id}_admins`
|
||||
const options = this.state.courses
|
||||
.filter(c => !c.access_restricted_by_date)
|
||||
.map(c => {
|
||||
const value = `course_${c.id}_admins`
|
||||
|
||||
return (
|
||||
<option key={value} value={value} selected={window.ENV.context_id == c.id}>
|
||||
{c.name}
|
||||
</option>
|
||||
)
|
||||
})
|
||||
return (
|
||||
<option key={value} value={value} selected={window.ENV.context_id == c.id}>
|
||||
{c.name}
|
||||
</option>
|
||||
)
|
||||
})
|
||||
|
||||
if (!this.state.coursesLoaded) {
|
||||
options.push(<option key="loading">{I18n.t('Loading courses...')}</option>)
|
||||
|
|
|
@ -16,23 +16,23 @@
|
|||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
class LoginFormSwitcher {
|
||||
constructor($loginForm, $forgotPasswordForm) {
|
||||
this.$loginForm = $loginForm;
|
||||
this.$forgotPasswordForm = $forgotPasswordForm;
|
||||
}
|
||||
|
||||
switchToLogin() {
|
||||
this.$forgotPasswordForm.hide();
|
||||
this.$loginForm.show();
|
||||
this.$loginForm.find("input:visible:first").focus();
|
||||
}
|
||||
|
||||
switchToForgotPassword() {
|
||||
this.$loginForm.hide();
|
||||
this.$forgotPasswordForm.show();
|
||||
this.$forgotPasswordForm.find("input:visible:first").focus();
|
||||
}
|
||||
class LoginFormSwitcher {
|
||||
constructor($loginForm, $forgotPasswordForm) {
|
||||
this.$loginForm = $loginForm
|
||||
this.$forgotPasswordForm = $forgotPasswordForm
|
||||
}
|
||||
|
||||
switchToLogin() {
|
||||
this.$forgotPasswordForm.hide()
|
||||
this.$loginForm.show()
|
||||
this.$loginForm.find('input:visible:first').focus()
|
||||
}
|
||||
|
||||
switchToForgotPassword() {
|
||||
this.$loginForm.hide()
|
||||
this.$forgotPasswordForm.show()
|
||||
this.$forgotPasswordForm.find('input:visible:first').focus()
|
||||
}
|
||||
}
|
||||
|
||||
export default LoginFormSwitcher
|
||||
|
|
Loading…
Reference in New Issue