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:
Clay Diffrient 2019-10-07 14:06:18 -06:00
parent c82d0c28a5
commit 3e38077e3f
63 changed files with 1397 additions and 1336 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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" />

View File

@ -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)

View File

@ -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(() => {

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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'

View File

@ -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)

View File

@ -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 */}

View File

@ -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>

View File

@ -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} />

View File

@ -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'

View File

@ -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" />&nbsp;
<i className="icon-plus" />
&nbsp;
<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"

View File

@ -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 />&nbsp;
<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 />
&nbsp;
<span className={this.hiddenPhoneClassname()}>{I18n.t('Upload')}</span>
</button>
{this.buildPotentialModal()}
</span>
)
}
export default createReactClass(UploadButton)

View File

@ -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)

View File

@ -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>

View File

@ -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.')

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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', {

View File

@ -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))
}

View File

@ -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

View File

@ -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 = {

View File

@ -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,

View File

@ -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 {

View File

@ -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

View File

@ -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() {

View File

@ -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() {

View File

@ -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 {

View File

@ -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)

View File

@ -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'

View File

@ -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 = ''

View File

@ -17,6 +17,7 @@
*/
import _ from 'underscore'
function uniqueEffectiveDueDates(assignment) {
const dueDates = _.map(assignment.effectiveDueDates, dueDateInfo => {
const dueAt = dueDateInfo.due_at

View File

@ -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 {

View File

@ -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

View File

@ -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() {

View File

@ -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() {

View File

@ -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 {

View File

@ -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)

View File

@ -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 = `&nbsp;<span title="${title}" class="label">${
options.enrollmentLabel
}</span>`
enrollmentStatus = `&nbsp;<span title="${title}" class="label">${options.enrollmentLabel}</span>`
}
if (options.secondaryInfo) {

View File

@ -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) {

View File

@ -17,6 +17,7 @@
*/
import _ from 'underscore'
function uniqueEffectiveDueDates(assignment) {
const dueDates = _.map(assignment.effectiveDueDates, dueDateInfo => {
const dueAt = dueDateInfo.due_at

View File

@ -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()

View File

@ -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))
}

View File

@ -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>
)

View File

@ -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

View File

@ -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)
}

View File

@ -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}

View File

@ -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))
},

View File

@ -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({

View File

@ -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>

View File

@ -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',

View File

@ -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

View File

@ -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

View File

@ -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>)

View File

@ -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