Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
ef4b5cb8
Commit
ef4b5cb8
authored
Apr 05, 2017
by
Brian Jacobel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Clean up spec and feature; both pass lint and run in Karma
parent
c5df4aa6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
147 additions
and
132 deletions
+147
-132
.babelrc
+1
-1
common/static/common/js/karma.common.conf.js
+11
-10
openedx/features/course_experience/static/course_experience/js/CourseOutline.js
+26
-21
openedx/features/course_experience/static/course_experience/js/spec/CourseOutline_spec.js
+55
-46
openedx/features/course_experience/templates/course_experience/course-outline-fragment.html
+1
-1
webpack.config.js
+53
-53
No files found.
.babelrc
View file @
ef4b5cb8
...
...
@@ -9,7 +9,7 @@
"IE >= 11"
]
},
"modules":
"commonjs"
"modules":
false
}
]
]
...
...
common/static/common/js/karma.common.conf.js
View file @
ef4b5cb8
...
...
@@ -170,7 +170,8 @@ function junitSettings(config) {
* @param {String} pattern
* @return {String}
*/
var
defaultNormalizeFunc
=
function
(
appRoot
,
pattern
)
{
// I'd like to change fix the no-shadow violation on the next line, but it would break this shared conf's API.
function
defaultNormalizeFunc
(
appRoot
,
pattern
)
{
// eslint-disable-line no-shadow
if
(
pattern
.
match
(
/^common
\/
js/
))
{
pattern
=
path
.
join
(
appRoot
,
'/common/static/'
+
pattern
);
}
else
if
(
pattern
.
match
(
/^xmodule_js
\/
common_static/
))
{
...
...
@@ -178,9 +179,9 @@ var defaultNormalizeFunc = function(appRoot, pattern) {
pattern
.
replace
(
/^xmodule_js
\/
common_static
\/
/
,
''
));
}
return
pattern
;
}
;
}
var
normalizePathsForCoverage
=
function
(
files
,
normalizeFunc
,
preprocessors
)
{
function
normalizePathsForCoverage
(
files
,
normalizeFunc
,
preprocessors
)
{
var
normalizeFn
=
normalizeFunc
||
defaultNormalizeFunc
,
normalizedFile
,
filesForCoverage
=
{};
...
...
@@ -193,7 +194,7 @@ var normalizePathsForCoverage = function(files, normalizeFunc, preprocessors) {
});
return
filesForCoverage
;
}
;
}
/**
* Sets defaults for each file pattern.
...
...
@@ -202,7 +203,7 @@ var normalizePathsForCoverage = function(files, normalizeFunc, preprocessors) {
* @param {Object} files
* @return {Object}
*/
var
setDefaults
=
function
(
files
)
{
function
setDefaults
(
files
)
{
return
files
.
map
(
function
(
f
)
{
var
file
=
_
.
isObject
(
f
)
?
f
:
{
pattern
:
f
};
if
(
!
file
.
included
&&
!
file
.
webpack
)
{
...
...
@@ -210,9 +211,9 @@ var setDefaults = function(files) {
}
return
file
;
});
}
;
}
var
getBaseConfig
=
function
(
config
,
useRequireJs
)
{
function
getBaseConfig
(
config
,
useRequireJs
)
{
var
getFrameworkFiles
=
function
()
{
var
files
=
[
'node_modules/jquery/dist/jquery.js'
,
...
...
@@ -347,9 +348,9 @@ var getBaseConfig = function(config, useRequireJs) {
webpack
:
webpackConfig
};
}
;
}
var
configure
=
function
(
config
,
options
)
{
function
configure
(
config
,
options
)
{
var
useRequireJs
=
options
.
useRequireJs
===
undefined
?
true
:
useRequireJs
,
baseConfig
=
getBaseConfig
(
config
,
useRequireJs
);
...
...
@@ -397,7 +398,7 @@ var configure = function(config, options) {
files
:
files
,
preprocessors
:
preprocessors
}));
}
;
}
module
.
exports
=
{
configure
:
configure
,
...
...
openedx/features/course_experience/static/course_experience/js/CourseOutline.js
View file @
ef4b5cb8
import
*
as
constants
from
'edx-ui-toolkit/src/js/utils/constants'
;
import
log
from
'logger'
;
/* globals Logger */
export
class
CourseOutline
{
constructor
(
root
)
{
document
.
querySelector
(
root
).
addEventListener
(
'keydown'
,
(
event
)
=>
{
const
focusable
=
[...
document
.
querySelectorAll
(
'.outline-item.focusable'
)];
const
currentFocusIndex
=
focusable
.
indexOf
(
event
.
target
);
// import constants from 'edx-ui-toolkit/src/js/utils/constants';
switch
(
event
.
keyCode
)
{
// eslint-disable-line default-case
case
constants
.
keyCodes
.
down
:
// @TODO: Figure out how to make webpack handle default exports when libraryTarget: 'window'
export
class
CourseOutline
{
// eslint-disable-line import/prefer-default-export
constructor
()
{
const
focusable
=
[...
document
.
querySelectorAll
(
'.outline-item.focusable'
)];
focusable
.
forEach
(
el
=>
el
.
addEventListener
(
'keydown'
,
(
event
)
=>
{
const
index
=
focusable
.
indexOf
(
event
.
target
);
switch
(
event
.
key
)
{
// eslint-disable-line default-case
case
'ArrowDown'
:
// @TODO: Get these from the UI Toolkit
event
.
preventDefault
();
focusable
[
Math
.
min
(
currentFocusI
ndex
+
1
,
focusable
.
length
-
1
)].
focus
();
focusable
[
Math
.
min
(
i
ndex
+
1
,
focusable
.
length
-
1
)].
focus
();
break
;
case
constants
.
keyCodes
.
up
:
case
'ArrowUp'
:
// @TODO: Get these from the UI Toolkit
event
.
preventDefault
();
focusable
[
Math
.
max
(
currentFocusI
ndex
-
1
,
0
)].
focus
();
focusable
[
Math
.
max
(
i
ndex
-
1
,
0
)].
focus
();
break
;
}
});
})
)
;
document
.
querySelectorAll
(
'a:not([href^="#"])'
).
addEventListener
(
'click'
,
(
event
)
=>
{
log
(
'edx.ui.lms.link_clicked'
,
{
current_url
:
window
.
location
.
href
,
target_url
:
event
.
currentTarget
.
href
}
document
.
querySelectorAll
(
'a:not([href^="#"])'
)
.
forEach
(
link
=>
link
.
addEventListener
(
'click'
,
(
event
)
=>
{
Logger
.
log
(
'edx.ui.lms.link_clicked'
,
{
current_url
:
window
.
location
.
href
,
target_url
:
event
.
currentTarget
.
href
,
},
);
});
}),
);
}
}
openedx/features/course_experience/static/course_experience/js/spec/CourseOutline_spec.js
View file @
ef4b5cb8
import
*
as
constants
from
"edx-ui-toolkit/js/utils/constants"
;
import
log
from
'logger'
;
import
{
CourseOutline
}
from
"../CourseOutline"
;
/* globals Logger, loadFixtures */
// import constants from 'edx-ui-toolkit/src/js/utils/constants';
import
{
CourseOutline
}
from
'../CourseOutline'
;
describe
(
'Course outline factory'
,
()
=>
{
let
outline
;
// eslint-disable-line no-unused-vars
// Our block IDs are invalid DOM selectors unless we first escape `:`, `+` and `@`
const
escapeIds
=
idObj
=>
Object
.
assign
({},
...
Object
.
keys
(
idObj
).
map
(
key
=>
({
[
key
]:
idObj
[
key
]
.
replace
(
/@/g
,
'
\\
@'
)
.
replace
(
/:/
,
'
\\
:'
)
.
replace
(
/
\+
/g
,
'
\\
+'
),
})));
const
outlineIds
=
escapeIds
({
homeworkLabsAndDemos
:
'a#block-v1:edX+DemoX+Demo_Course+type@sequential+block@graded_simulations'
,
homeworkEssays
:
'a#block-v1:edX+DemoX+Demo_Course+type@sequential+block@175e76c4951144a29d46211361266e0e'
,
lesson3BeSocial
:
'a#block-v1:edX+DemoX+Demo_Course+type@sequential+block@48ecb924d7fe4b66a230137626bfa93e'
,
exampleWeek3BeSocial
:
'li#block-v1:edX+DemoX+Demo_Course+type@chapter+block@social_integration'
,
});
describe
(
'keyboard listener'
,
()
=>
{
const
triggerKeyListener
=
(
current
,
destination
,
key
Code
)
=>
{
const
triggerKeyListener
=
(
current
,
destination
,
key
)
=>
{
current
.
focus
();
spyOn
(
destination
,
'focus'
);
$
(
'.block-tree'
).
trigger
(
$
.
Event
(
'keydown'
,
{
keyCode
,
target
:
current
,
}),
);
current
.
dispatchEvent
(
new
KeyboardEvent
(
'keydown'
,
{
key
}));
};
beforeEach
(()
=>
{
loadFixtures
(
'course_experience/fixtures/course-outline-fragment.html'
);
new
CourseOutline
(
'.block-tree'
);
outline
=
new
CourseOutline
(
);
});
describe
(
'when the down arrow is pressed'
,
()
=>
{
it
(
'moves focus from a subsection to the next subsection in the outline'
,
()
=>
{
const
current
=
$
(
'a.focusable:contains("Homework - Labs and Demos")'
)[
0
]
;
const
destination
=
$
(
'a.focusable:contains("Homework - Essays")'
)[
0
]
;
const
current
=
document
.
querySelector
(
outlineIds
.
homeworkLabsAndDemos
)
;
const
destination
=
document
.
querySelector
(
outlineIds
.
homeworkEssays
)
;
triggerKeyListener
(
current
,
destination
,
constants
.
keyCodes
.
down
);
triggerKeyListener
(
current
,
destination
,
'ArrowDown'
);
// @TODO: Get these from the UI Toolkit
expect
(
destination
.
focus
).
toHaveBeenCalled
();
});
it
(
'moves focus to the s
ection list if at a section boundary
'
,
()
=>
{
const
current
=
$
(
'li.focusable:contains("Example Week 3: Be Social")'
)[
0
]
;
const
destination
=
$
(
'ol.focusable:contains("Lesson 3 - Be Social")'
)[
0
]
;
it
(
'moves focus to the s
ubsection list if at the top of a section
'
,
()
=>
{
const
current
=
document
.
querySelector
(
outlineIds
.
exampleWeek3BeSocial
)
;
const
destination
=
document
.
querySelector
(
`
${
outlineIds
.
exampleWeek3BeSocial
}
> ol`
)
;
triggerKeyListener
(
current
,
destination
,
constants
.
keyCodes
.
down
);
triggerKeyListener
(
current
,
destination
,
'ArrowDown'
);
// @TODO: Get these from the UI Toolkit
expect
(
destination
.
focus
).
toHaveBeenCalled
();
});
it
(
'moves focus to the next section if on the last subsection'
,
()
=>
{
const
current
=
$
(
'a.focusable:contains("Homework - Essays")'
)[
0
]
;
const
destination
=
$
(
'li.focusable:contains("Example Week 3: Be Social")'
)[
0
]
;
const
current
=
document
.
querySelector
(
outlineIds
.
homeworkEssays
)
;
const
destination
=
document
.
querySelector
(
outlineIds
.
exampleWeek3BeSocial
)
;
triggerKeyListener
(
current
,
destination
,
constants
.
keyCodes
.
down
);
triggerKeyListener
(
current
,
destination
,
'ArrowDown'
);
// @TODO: Get these from the UI Toolkit
expect
(
destination
.
focus
).
toHaveBeenCalled
();
});
...
...
@@ -52,53 +66,48 @@ describe('Course outline factory', () => {
describe
(
'when the up arrow is pressed'
,
()
=>
{
it
(
'moves focus from a subsection to the previous subsection in the outline'
,
()
=>
{
const
current
=
$
(
'a.focusable:contains("Homework - Essays")'
)[
0
]
;
const
destination
=
$
(
'a.focusable:contains("Homework - Labs and Demos")'
)[
0
]
;
const
current
=
document
.
querySelector
(
outlineIds
.
homeworkEssays
)
;
const
destination
=
document
.
querySelector
(
outlineIds
.
homeworkLabsAndDemos
)
;
triggerKeyListener
(
current
,
destination
,
constants
.
keyCodes
.
up
);
triggerKeyListener
(
current
,
destination
,
'ArrowUp'
);
// @TODO: Get these from the UI Toolkit
expect
(
destination
.
focus
).
toHaveBeenCalled
();
});
it
(
'moves focus to the section
group
if at the first subsection'
,
()
=>
{
const
current
=
$
(
'a.focusable:contains("Lesson 3 - Be Social")'
)[
0
]
;
const
destination
=
$
(
'ol.focusable:contains("Lesson 3 - Be Social")'
)[
0
]
;
it
(
'moves focus to the section
list
if at the first subsection'
,
()
=>
{
const
current
=
document
.
querySelector
(
outlineIds
.
lesson3BeSocial
)
;
const
destination
=
document
.
querySelector
(
`
${
outlineIds
.
exampleWeek3BeSocial
}
> ol`
)
;
triggerKeyListener
(
current
,
destination
,
constants
.
keyCodes
.
up
);
triggerKeyListener
(
current
,
destination
,
'ArrowUp'
);
// @TODO: Get these from the UI Toolkit
expect
(
destination
.
focus
).
toHaveBeenCalled
();
});
it
(
'moves focus last subsection of the previous section if at a section boundary'
,
()
=>
{
const
current
=
$
(
'li.focusable:contains("Example Week 3: Be Social")'
)[
0
]
;
const
destination
=
$
(
'a.focusable:contains("Homework - Essays")'
)[
0
]
;
const
current
=
document
.
querySelector
(
outlineIds
.
exampleWeek3BeSocial
)
;
const
destination
=
document
.
querySelector
(
outlineIds
.
homeworkEssays
)
;
triggerKeyListener
(
current
,
destination
,
constants
.
keyCodes
.
up
);
triggerKeyListener
(
current
,
destination
,
'ArrowUp'
);
// @TODO: Get these from the UI Toolkit
expect
(
destination
.
focus
).
toHaveBeenCalled
();
});
});
});
describe
(
"eventing"
,
function
()
{
beforeEach
(
function
()
{
loadFixtures
(
"course_experience/fixtures/course-outline-fragment.html"
);
CourseOutlineFactory
(
".block-tree"
);
spyOn
(
Logger
,
"log"
);
describe
(
'eventing'
,
()
=>
{
beforeEach
(
()
=>
{
loadFixtures
(
'course_experience/fixtures/course-outline-fragment.html'
);
outline
=
new
CourseOutline
(
);
spyOn
(
Logger
,
'log'
);
});
it
(
"sends an event when an outline section is clicked"
,
function
()
{
$
(
'a.focusable:contains("Homework - Labs and Demos")'
).
click
(
);
it
(
'sends an event when an outline section is clicked'
,
()
=>
{
document
.
querySelector
(
outlineIds
.
homeworkLabsAndDemos
).
dispatchEvent
(
new
Event
(
'click'
)
);
expect
(
Logger
.
log
).
toHaveBeenCalledWith
(
"edx.ui.lms.link_clicked"
,
{
target_url
:
(
window
.
location
.
origin
+
"/courses/course-v1:edX+DemoX+Demo_Course/jump_to/block-v1:edX+DemoX+Demo_Course+type"
+
"@sequential+block@graded_simulations"
),
current_url
:
window
.
location
.
toString
()
expect
(
Logger
.
log
).
toHaveBeenCalledWith
(
'edx.ui.lms.link_clicked'
,
{
target_url
:
`
${
window
.
location
.
origin
}
/courses/course-v1:edX+DemoX+Demo_Course/jump_to/block-v1:edX+DemoX+Demo_Course+type@sequential+block@graded_simulations`
,
current_url
:
window
.
location
.
toString
(),
});
});
});
});
openedx/features/course_experience/templates/course_experience/course-outline-fragment.html
View file @
ef4b5cb8
...
...
@@ -161,5 +161,5 @@ from openedx.core.djangolib.markup import HTML, Text
</
%
static:require
_module_async
>
<
%
static:webpack
entry=
"CourseOutline"
>
new CourseOutline(
'.block-tree'
);
new CourseOutline();
</
%
static:webpack>
webpack.config.js
View file @
ef4b5cb8
const
path
=
require
(
'path'
);
const
webpack
=
require
(
'webpack'
);
const
BundleTracker
=
require
(
'webpack-bundle-tracker'
);
const
isProd
=
process
.
env
.
NODE_ENV
===
'production'
;
const
wpconfig
=
{
context
:
__dirname
,
entry
:
{
CourseOutline
:
'./openedx/features/course_experience/static/course_experience/js/CourseOutline.js'
,
},
output
:
{
path
:
path
.
resolve
(
__dirname
,
'common/static/bundles'
),
filename
:
'[name]-[hash].js'
,
libraryTarget
:
'window'
,
},
devtool
:
isProd
?
false
:
'cheap-eval-source-map'
,
plugins
:
[
new
webpack
.
NoEmitOnErrorsPlugin
(),
new
webpack
.
NamedModulesPlugin
(),
new
webpack
.
DefinePlugin
({
'process.env.NODE_ENV'
:
JSON
.
stringify
(
process
.
env
.
NODE_ENV
||
'development'
),
}),
new
webpack
.
LoaderOptionsPlugin
({
debug
:
!
isProd
,
}),
new
BundleTracker
({
filename
:
'./webpack-stats.json'
}),
],
module
:
{
rules
:
[
{
test
:
/
\.
js$/
,
exclude
:
/node_modules/
,
use
:
'babel-loader'
,
},
var
path
=
require
(
'path'
);
var
webpack
=
require
(
'webpack'
);
var
BundleTracker
=
require
(
'webpack-bundle-tracker'
);
var
isProd
=
process
.
env
.
NODE_ENV
===
'production'
;
var
wpconfig
=
{
context
:
__dirname
,
entry
:
{
CourseOutline
:
'./openedx/features/course_experience/static/course_experience/js/CourseOutline.js'
},
output
:
{
path
:
path
.
resolve
(
__dirname
,
'common/static/bundles'
),
filename
:
'[name]-[hash].js'
,
libraryTarget
:
'window'
},
devtool
:
isProd
?
false
:
'eval-source-map'
,
plugins
:
[
new
webpack
.
NoEmitOnErrorsPlugin
(),
new
webpack
.
NamedModulesPlugin
(),
new
webpack
.
DefinePlugin
({
'process.env.NODE_ENV'
:
JSON
.
stringify
(
process
.
env
.
NODE_ENV
||
'development'
)
}),
new
webpack
.
LoaderOptionsPlugin
({
debug
:
!
isProd
}),
new
BundleTracker
({
filename
:
'./webpack-stats.json'
})
],
},
resolve
:
{
extensions
:
[
'.js'
,
'.json'
],
}
module
:
{
rules
:
[
{
test
:
/
\.
js$/
,
exclude
:
/node_modules/
,
use
:
'babel-loader'
}
]
},
resolve
:
{
extensions
:
[
'.js'
,
'.json'
]
}
};
if
(
isProd
)
{
wpconfig
.
plugins
=
[
new
webpack
.
LoaderOptionsPlugin
({
minimize
:
true
,
}),
new
webpack
.
optimize
.
UglifyJsPlugin
(),
...
wpconfig
.
plugins
,
];
wpconfig
.
plugins
=
wpconfig
.
plugins
.
concat
([
new
webpack
.
LoaderOptionsPlugin
({
minimize
:
true
}),
new
webpack
.
optimize
.
UglifyJsPlugin
()
]);
}
module
.
exports
=
wpconfig
;
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment