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
8b59c6d5
Unverified
Commit
8b59c6d5
authored
Dec 06, 2017
by
Ari Rizzitano
Committed by
GitHub
Dec 06, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #16639 from edx/ari/react-renderer
mako/react bridge code
parents
9b92a3b7
8ca0fe9d
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
123 additions
and
32 deletions
+123
-32
cms/templates/index.html
+1
-0
common/djangoapps/pipeline_mako/templates/static_content.html
+43
-30
common/static/js/src/ReactRenderer.jsx
+66
-0
conftest.py
+9
-1
webpack.common.config.js
+4
-1
No files found.
cms/templates/index.html
View file @
8b59c6d5
...
@@ -552,6 +552,7 @@ from openedx.core.djangolib.js_utils import (
...
@@ -552,6 +552,7 @@ from openedx.core.djangolib.js_utils import (
%endif
%endif
</div>
</div>
<
%
static:webpack
entry=
"StudioIndex"
>
<
%
static:webpack
entry=
"StudioIndex"
>
var enableReruns = ${allow_course_reruns and rerun_creator_status and course_creator_status=='granted' | n, dump_js_escaped_json};
var enableReruns = ${allow_course_reruns and rerun_creator_status and course_creator_status=='granted' | n, dump_js_escaped_json};
new StudioCourseIndex(
new StudioCourseIndex(
...
...
common/djangoapps/pipeline_mako/templates/static_content.html
View file @
8b59c6d5
<
%
page
expression_filter=
"h"
/>
<
%
page
expression_filter=
"h"
/>
<
%!
<
%!
import
logging
import
logging
import
json
from
django
.
contrib
.
staticfiles
.
storage
import
staticfiles_storage
from
django
.
contrib
.
staticfiles
.
storage
import
staticfiles_storage
from
pipeline_mako
import
compressed_css
,
compressed_js
from
pipeline_mako
import
compressed_css
,
compressed_js
from
django
.
utils
.
translation
import
get_language_bidi
from
django
.
utils
.
translation
import
get_language_bidi
from
mako
.
exceptions
import
TemplateLookupException
from
mako
.
exceptions
import
TemplateLookupException
from
edxmako
.
shortcuts
import
marketing_link
from
edxmako
.
shortcuts
import
marketing_link
from
openedx
.
core
.
djangolib
.
js_utils
import
js_escaped_string
from
openedx
.
core
.
djangolib
.
js_utils
import
js_escaped_string
,
dump_js_escaped_json
from
openedx
.
core
.
djangolib
.
markup
import
HTML
from
openedx
.
core
.
djangoapps
.
site_configuration
.
helpers
import
(
from
openedx
.
core
.
djangoapps
.
site_configuration
.
helpers
import
(
page_title_breadcrumbs
,
page_title_breadcrumbs
,
get_value
,
get_value
,
...
@@ -18,6 +20,7 @@ from openedx.core.djangoapps.theming.helpers import (
...
@@ -18,6 +20,7 @@ from openedx.core.djangoapps.theming.helpers import (
is_request_in_themed_site
,
is_request_in_themed_site
,
)
)
from
certificates
.
api
import
get_asset_url_by_slug
from
certificates
.
api
import
get_asset_url_by_slug
from
webpack_loader
.
templatetags
.
webpack_loader
import
render_bundle
logger =
logging.getLogger(__name__)
logger =
logging.getLogger(__name__)
%
>
%
>
...
@@ -97,25 +100,15 @@ source, template_path = Loader(engine).load_template_source(path)
...
@@ -97,25 +100,15 @@ source, template_path = Loader(engine).load_template_source(path)
-include it as the first script in this block
-include it as the first script in this block
</
%
doc>
</
%
doc>
<
%
<
%
from
django
.
template
import
Template
,
Context
from
webpack_loader
.
exceptions
import
WebpackLoaderBadStatsError
import
json
body =
capture(caller.body)
body =
capture(caller.body)
body_dict =
json.loads(body)
body_dict =
json.loads(body)
body_dict
['
lang
']
=
lang
body_dict
['
lang
']
=
lang
return
Template
("""
<
script
type=
"text/javascript"
id=
'studioContext'
>
var studioContext = {% autoescape off %}{{ body }}{% endautoescape %};
</script>
<div
id=
"root"
></div>
{% load render_bundle from webpack_loader %}
{% render_bundle page %}
""").render(Context({
'body': json.dumps(body_dict),
'page': page
}))
%
>
%
>
<script
type=
"text/javascript"
id=
'courseContext'
>
var
studioContext
=
$
{
body
|
n
,
decode
.
utf8
};
</script>
<div
id=
"root"
></div>
${HTML(render_bundle(page))}
</
%
def>
</
%
def>
<
%
def
name=
"webpack(entry)"
>
<
%
def
name=
"webpack(entry)"
>
...
@@ -124,21 +117,41 @@ source, template_path = Loader(engine).load_template_source(path)
...
@@ -124,21 +117,41 @@ source, template_path = Loader(engine).load_template_source(path)
Uses the Django template engine because our webpack loader only provides template tags for Jinja and Django.
Uses the Django template engine because our webpack loader only provides template tags for Jinja and Django.
</
%
doc>
</
%
doc>
<
%
<
%
from
django
.
template
import
Template
,
Context
body =
capture(caller.body)
from
webpack_loader
.
exceptions
import
WebpackLoaderBadStatsError
return
Template
("""
{%
load
render_bundle
from
webpack_loader
%}
{%
render_bundle
entry
%}
{%
if
body
%}
<
script
type=
"text/javascript"
>
{% autoescape off %}{{ body }}{% endautoescape %}
</script>
{% endif %}
""").render(Context({
'entry': entry,
'body': capture(caller.body)
}))
%
>
%
>
${HTML(render_bundle(entry))}
% if body:
<script
type=
"text/javascript"
>
$
{
body
|
n
,
decode
.
utf8
}
</script>
% endif
</
%
def>
<
%
def
name=
"renderReact(component, id, props={})"
>
<
%
doc
>
Wrapper function to load a React component via webpack() and render
it onto the page, passing an optional context object via props.
component: (string) The component to render, as specified by the name
of its Webpack entry point.
id: (string) A unique id to apply to the component's container div.
props: (dict, optional) An object containing data to pass into the
component as props.
</
%
doc>
${HTML(render_bundle(component))}
${HTML(render_bundle('ReactRenderer'))}
<div
id=
"${id}"
></div>
<script
type=
"text/javascript"
>
var
c
;
try
{
c
=
$
{
component
|
n
,
decode
.
utf8
};
}
catch
(
e
)
{
c
=
null
;
}
new
ReactRenderer
({
component
:
c
,
selector
:
'#${id | n, decode.utf8}'
,
componentName
:
'${component | n, js_escaped_string}'
,
props
:
$
{
props
|
n
,
dump_js_escaped_json
}
});
</script>
</
%
def>
</
%
def>
<
%
def
name=
"require_module(module_name, class_name)"
>
<
%
def
name=
"require_module(module_name, class_name)"
>
...
...
common/static/js/src/ReactRenderer.jsx
0 → 100644
View file @
8b59c6d5
import
React
from
'react'
;
import
ReactDOM
from
'react-dom'
;
class
ReactRendererException
extends
Error
{
constructor
(
message
)
{
super
(
`ReactRendererException:
${
message
}
`
);
Error
.
captureStackTrace
(
this
,
ReactRendererException
);
}
}
export
class
ReactRenderer
{
constructor
({
component
,
selector
,
componentName
,
props
=
{}
})
{
Object
.
assign
(
this
,
{
component
,
selector
,
componentName
,
props
,
});
this
.
handleArgumentErrors
();
this
.
targetElement
=
this
.
getTargetElement
();
this
.
renderComponent
();
}
handleArgumentErrors
()
{
if
(
this
.
component
===
null
)
{
throw
new
ReactRendererException
(
`Component
${
this
.
componentName
}
is not defined. Make sure you're `
+
`using a non-default export statement for the
${
this
.
componentName
}
`
+
`class, that
${
this
.
componentName
}
has an entry point defined `
+
'within the
\'
entry
\'
section of webpack.common.config.js, and that the '
+
'entry point is pointing at the correct file path.'
,
);
}
if
(
!
(
this
.
props
instanceof
Object
&&
this
.
props
.
constructor
===
Object
))
{
let
propsType
=
typeof
this
.
props
;
if
(
Array
.
isArray
(
this
.
props
))
{
propsType
=
'array'
;
}
else
if
(
this
.
props
===
null
)
{
propsType
=
'null'
;
}
throw
new
ReactRendererException
(
`Invalid props passed to component
${
this
.
componentName
}
. Expected `
+
`an object, but received a
${
propsType
}
.`
,
);
}
}
getTargetElement
()
{
const
elementList
=
document
.
querySelectorAll
(
this
.
selector
);
if
(
elementList
.
length
!==
1
)
{
throw
new
ReactRendererException
(
`Expected 1 element match for selector "
${
this
.
selector
}
" `
+
`but received
${
elementList
.
length
}
matches.`
,
);
}
else
{
return
elementList
[
0
];
}
}
renderComponent
()
{
ReactDOM
.
render
(
React
.
createElement
(
this
.
component
,
this
.
props
,
null
),
this
.
targetElement
,
);
}
}
conftest.py
View file @
8b59c6d5
"""
"""
Default unit test configuration and fixtures.
Default unit test configuration and fixtures.
"""
"""
from
__future__
import
absolute_import
,
unicode_literals
from
__future__
import
absolute_import
,
unicode_literals
import
pytest
# Import hooks and fixture overrides from the cms package to
# Import hooks and fixture overrides from the cms package to
# avoid duplicating the implementation
# avoid duplicating the implementation
from
cms.conftest
import
_django_clear_site_cache
,
pytest_configure
# pylint: disable=unused-import
from
cms.conftest
import
_django_clear_site_cache
,
pytest_configure
# pylint: disable=unused-import
@pytest.fixture
(
autouse
=
True
)
def
no_webpack_loader
(
monkeypatch
):
monkeypatch
.
setattr
(
"webpack_loader.templatetags.webpack_loader.render_bundle"
,
lambda
x
:
''
)
webpack.common.config.js
View file @
8b59c6d5
...
@@ -35,7 +35,10 @@ module.exports = {
...
@@ -35,7 +35,10 @@ module.exports = {
Currency
:
'./openedx/features/course_experience/static/course_experience/js/currency.js'
,
Currency
:
'./openedx/features/course_experience/static/course_experience/js/currency.js'
,
Enrollment
:
'./openedx/features/course_experience/static/course_experience/js/Enrollment.js'
,
Enrollment
:
'./openedx/features/course_experience/static/course_experience/js/Enrollment.js'
,
LatestUpdate
:
'./openedx/features/course_experience/static/course_experience/js/LatestUpdate.js'
,
LatestUpdate
:
'./openedx/features/course_experience/static/course_experience/js/LatestUpdate.js'
,
WelcomeMessage
:
'./openedx/features/course_experience/static/course_experience/js/WelcomeMessage.js'
WelcomeMessage
:
'./openedx/features/course_experience/static/course_experience/js/WelcomeMessage.js'
,
// Common
ReactRenderer
:
'./common/static/js/src/ReactRenderer.jsx'
},
},
output
:
{
output
:
{
...
...
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