From 376307259c25d0ab7f7653b093377b9b655b1d87 Mon Sep 17 00:00:00 2001 From: Oliver Foster Date: Mon, 26 Oct 2020 15:11:57 +0000 Subject: [PATCH 1/6] issue/2824-react Added react template support --- grunt/config/javascript.js | 22 + grunt/config/watch.js | 2 +- grunt/tasks/javascript.js | 35 +- package.json | 6 + src/core/js/fixes/img.lazyload.js | 79 +-- src/core/js/reactHelpers.js | 148 +++++ src/core/js/views/adaptView.js | 632 ++++++++++++---------- src/core/js/views/contentObjectView.js | 15 +- src/core/templates/partials/component.jsx | 59 ++ src/course/en/course.json | 272 +++++----- 10 files changed, 799 insertions(+), 471 deletions(-) create mode 100644 src/core/js/reactHelpers.js create mode 100644 src/core/templates/partials/component.jsx diff --git a/grunt/config/javascript.js b/grunt/config/javascript.js index 8e5e5b4bf..33b3550d9 100644 --- a/grunt/config/javascript.js +++ b/grunt/config/javascript.js @@ -19,6 +19,17 @@ module.exports = function(grunt, options) { return grunt.config('helpers').includedFilter(filepath); }, umdImports: [ + '../node_modules/object.assign/dist/browser.js', + '../node_modules/react/umd/react.development.js', + '../node_modules/react-dom/umd/react-dom.development.js', + '../node_modules/html-react-parser/dist/html-react-parser.min.js' + ], + reactTemplates: [ + '<%= sourcedir %>core/templates/**/*.jsx', + '<%= sourcedir %>components/*/templates/**/*.jsx', + '<%= sourcedir %>extensions/*/templates/**/*.jsx', + '<%= sourcedir %>menu/*/templates/**/*.jsx', + '<%= sourcedir %>theme/*/templates/**/*.jsx' ], external: { jquery: 'empty:', @@ -74,6 +85,17 @@ module.exports = function(grunt, options) { return grunt.config('helpers').includedFilter(filepath); }, umdImports: [ + '../node_modules/object.assign/dist/browser.js', + '../node_modules/react/umd/react.production.min.js', + '../node_modules/react-dom/umd/react-dom.production.min.js', + '../node_modules/html-react-parser/dist/html-react-parser.min.js' + ], + reactTemplates: [ + '<%= sourcedir %>core/templates/**/*.jsx', + '<%= sourcedir %>components/*/templates/**/*.jsx', + '<%= sourcedir %>extensions/*/templates/**/*.jsx', + '<%= sourcedir %>menu/*/templates/**/*.jsx', + '<%= sourcedir %>theme/*/templates/**/*.jsx' ], external: { jquery: 'empty:', diff --git a/grunt/config/watch.js b/grunt/config/watch.js index db090622e..dd55fd42a 100644 --- a/grunt/config/watch.js +++ b/grunt/config/watch.js @@ -25,7 +25,7 @@ module.exports = { tasks: ['newer:copy:courseAssets'] }, js: { - files: ['<%= sourcedir %>**/*.js'], + files: ['<%= sourcedir %>**/*.js', '<%= sourcedir %>**/*.jsx'], options: { spawn: false }, diff --git a/grunt/tasks/javascript.js b/grunt/tasks/javascript.js index cb2c01e26..41145eec2 100644 --- a/grunt/tasks/javascript.js +++ b/grunt/tasks/javascript.js @@ -16,7 +16,7 @@ module.exports = function(grunt) { const isDisableCache = process.argv.includes('--disable-cache'); let cache; - const extensions = ['.js']; + const extensions = ['.js', '.jsx']; const restoreCache = async (cachePath, basePath) => { if (isDisableCache || cache || !fs.existsSync(cachePath)) return; @@ -157,6 +157,16 @@ module.exports = function(grunt) { }); } + // Collect react templates + const reactTemplatePaths = []; + options.reactTemplates.forEach(pattern => { + grunt.file.expand({ + filter: options.pluginsFilter + }, pattern).forEach(function(templatePath) { + reactTemplatePaths.push(templatePath.replace(convertSlashes, '/')); + }); + }); + // Process remapping and external model configurations const mapParts = Object.keys(options.map); const externalParts = Object.keys(options.external); @@ -253,6 +263,8 @@ module.exports = function(grunt) { // Dynamically construct plugins.js with plugin dependencies code = `define([${pluginPaths.map(filename => { return `"${filename}"`; + }).join(',')}, ${reactTemplatePaths.map(filename => { + return `"${filename}"`; }).join(',')}], function() {});`; return code; } @@ -276,6 +288,12 @@ module.exports = function(grunt) { '**/node_modules/**' ], presets: [ + [ + '@babel/preset-react', + { + runtime: 'classic' + } + ], [ '@babel/preset-env', { @@ -297,7 +315,20 @@ module.exports = function(grunt) { amdDefineES6Modules: true, defineFunctionName: '__AMD', defineModuleId: (moduleId) => moduleId.replace(convertSlashes, '/').replace(basePath, '').replace('.js', ''), - excludes: [] + excludes: [ + '**/templates/**/*.jsx' + ] + } + ], + [ + 'transform-react-templates', + { + includes: [ + '**/templates/**/*.jsx' + ], + importRegisterFunctionFromModule: path.resolve(basePath, 'core/js/reactHelpers.js').replace(convertSlashes, '/'), + registerFunctionName: 'register', + registerTemplateName: (moduleId) => path.parse(moduleId).name } ] ] diff --git a/package.json b/package.json index 4fa70ce86..9e9f35cdb 100644 --- a/package.json +++ b/package.json @@ -16,12 +16,16 @@ }, "dependencies": { "@babel/core": "^7.8.4", + "@babel/plugin-transform-react-jsx": "^7.10.4", "@babel/preset-env": "^7.8.4", + "@babel/preset-react": "^7.10.4", "@rollup/plugin-babel": "^5.0.4", "@types/backbone": "^1.4.1", "@types/jquery": "^3.3.31", "async": "^3.1.1", "babel-plugin-transform-amd-to-es6": "^0.3.0", + "babel-plugin-transform-react-templates": "^0.1.0", + "html-react-parser": "^0.13.0", "chalk": "^2.4.1", "columnify": "^1.5.4", "csv": "^5.0.0", @@ -52,6 +56,8 @@ "load-grunt-config": "^1.0.1", "lodash": "^4.17.19", "nsdeclare": "^0.1.0", + "react": "^16.13.1", + "react-dom": "^16.13.1", "rollup": "^2.18.1", "time-grunt": "^2.0.0", "underscore": "^1.9.1", diff --git a/src/core/js/fixes/img.lazyload.js b/src/core/js/fixes/img.lazyload.js index 4b7677e6f..f7d2f791b 100644 --- a/src/core/js/fixes/img.lazyload.js +++ b/src/core/js/fixes/img.lazyload.js @@ -1,38 +1,51 @@ -define([ - 'core/js/adapt', - '../templates' -], function(Adapt) { +import Adapt from 'core/js/adapt'; +import '../templates'; +import { find, clone } from '../reactHelpers'; - /** - * 27 April 2020 https://github.com/adaptlearning/adapt_framework/issues/2734 - * Chrome on Android defers load events on images when lite mode is enabled - * and as part of a data saving technique. - * - * Add a loading="eager" attribute to all template and partial img tags where - * the loading attribute is missing. - */ - Adapt.on('app:dataReady', function() { - const config = Adapt.config.get('_fixes'); - if (config && config._imgLazyLoad === false) return; - applyImgLoadingFix(); - }); +/** + * 27 April 2020 https://github.com/adaptlearning/adapt_framework/issues/2734 + * Chrome on Android defers load events on images when lite mode is enabled + * and as part of a data saving technique. + * + * Add a loading="eager" attribute to all template and partial img tags where + * the loading attribute is missing. + */ +Adapt.on('app:dataReady', function() { + const config = Adapt.config.get('_fixes'); + if (config && config._imgLazyLoad === false) return; + applyImgLoadingFix(); +}); - function applyImgLoadingFix() { - const findImgTag = /]*)>/gi; - const hasLoadingAttr = / loading=/gi; - Adapt.on('template:postRender partial:postRender', function(event) { - const imgTagsFound = event.value.match(findImgTag); - if (!imgTagsFound) { - return; +function applyImgLoadingFix() { + const findImgTag = /]*)>/gi; + const hasLoadingAttr = / loading=/gi; + Adapt.on('template:postRender partial:postRender', function(event) { + const imgTagsFound = event.value.match(findImgTag); + if (!imgTagsFound) { + return; + } + event.value = imgTagsFound.reduce((value, img) => { + if (hasLoadingAttr.test(img)) { + return value; } - event.value = imgTagsFound.reduce((value, img) => { - if (hasLoadingAttr.test(img)) { - return value; - } - // Add loading="eager" by default - return value.replace(img, img.replace(findImgTag, '')); - }, event.value); + // Add loading="eager" by default + return value.replace(img, img.replace(findImgTag, '')); + }, event.value); + }); + Adapt.on('reactTemplate:postRender', function(event) { + const hasImageTagWithNoLoadingAttr = find(event.value, component => { + if (component.type !== 'img') return; + if (component.props.loading) return; + return true; + }); + if (!hasImageTagWithNoLoadingAttr) return; + // Strip object freeze and write locks by cloning + event.value = clone(event.value, true, component => { + if (component.type !== 'img') return; + if (component.props.loading) return; + component.props.loading = 'eager'; }); - } + }); +} + -}); diff --git a/src/core/js/reactHelpers.js b/src/core/js/reactHelpers.js new file mode 100644 index 000000000..dca13b672 --- /dev/null +++ b/src/core/js/reactHelpers.js @@ -0,0 +1,148 @@ +import Adapt from 'core/js/adapt'; +import TemplateRenderEvent from './templateRenderEvent'; + +/** + * Finds a node in a react node hierarchy + * Return true from the iterator to stop traversal + * @param {object} hierarchy + * @param {function} iterator + */ +export function find(hierarchy, iterator) { + if (iterator(hierarchy)) { + return true; + } + if (!hierarchy.props || !hierarchy.props.children) return; + if (Array.isArray(hierarchy.props.children)) { + return hierarchy.props.children.find(child => { + if (!child) return; + return find(child, iterator); + }); + } + return find(hierarchy.props.children, iterator); +}; + +/** + * Allows clone and modification of a react node hierarchy + * @param {*} value + * @param {boolean} isDeep=false + * @param {function} modifier + * @returns {*} + */ +export function clone(value, isDeep = false, modifier = null) { + if (typeof value !== 'object' || value === null) { + return value; + } + const cloned = Array.isArray(value) ? [] : {}; + const descriptors = Object.getOwnPropertyDescriptors(value); + for (let name in descriptors) { + const descriptor = descriptors[name]; + if (!descriptor.hasOwnProperty('value')) { + Object.defineProperty(cloned, name, descriptor); + continue; + } + let value = descriptor.value; + if (typeof value === 'object' && value !== null) { + if (isDeep) { + value = descriptor.value = clone(value, isDeep, modifier); + } + if (modifier && typeof value.$$typeof === 'symbol') { + modifier(value); + } + } + descriptor.writable = true; + Object.defineProperty(cloned, name, descriptor); + } + if (modifier && typeof cloned.$$typeof === 'symbol') { + modifier(cloned); + } + return cloned; +}; + +/** + * Used by babel plugin babel-plugin-transform-react-templates to inject react templates + */ +export default function register(name, component) { + templates[name] = (...args) => { + // Trap render calls to emit preRender and postRender events + const mode = 'reactTemplate'; + // Send preRender event to allow modification of args + const preRenderEvent = new TemplateRenderEvent(`${mode}:preRender`, name, mode, null, args); + Adapt.trigger(preRenderEvent.type, preRenderEvent); + // Execute template + const value = component(...preRenderEvent.args); + // Send postRender event to allow modification of rendered template + const postRenderEvent = new TemplateRenderEvent(`${mode}:postRender`, name, mode, value, preRenderEvent.args); + Adapt.trigger(postRenderEvent.type, postRenderEvent); + // Return rendered, modified template + return postRenderEvent.value; + }; +}; + +/** + * Storage for react templates + */ +export const templates = {}; + +/** + * Convert html strings to react dom, equivalent to handlebars {{{html}}} + * @param {string} html + */ +export function html(html, ref = null) { + if (!html) return; + let node = html ? window.HTMLReactParser(html) : ''; + if (typeof node === 'object' && ref) { + // Strip object freeze and write locks by cloning + node = clone(node); + node.ref = ref; + } + return node; +} + +/** + * Render the named react component + * @param {string} name React template name + * @param {...any} args React template arguments + */ +export function render(name, ...args) { + const template = templates[name]; + const component = template(...args); + return component; +}; + +/** + * Handlebars compile integration + * @param {string} name Handlebars template + * @param {...any} args Template arguments + */ +export function compile(template, ...args) { + const output = Handlebars.compile(template)(...args); + return output; +}; + +/** + * Handlebars partials integration + * @param {string} name Partial name + * @param {...any} args Partial arguments + */ +export function partial(name, ...args) { + const output = Handlebars.partials[name](...args); + return output; +}; + +/** + * Handlebars helpers integration + * @param {string} name Helper name + * @param {...any} args Helper arguments + */ +export function helper(name, ...args) { + const output = Handlebars.helpers[name].call(args[0]); + return (output && output.string) || output; +}; + +/** + * Helper for a list of classes, filtering out falsies and joining with spaces + * @param {...any} args List or arrays of classes + */ +export function classes(...args) { + return _.flatten(args).filter(Boolean).join(' '); +}; diff --git a/src/core/js/views/adaptView.js b/src/core/js/views/adaptView.js index d8b196469..90836fa52 100644 --- a/src/core/js/views/adaptView.js +++ b/src/core/js/views/adaptView.js @@ -1,355 +1,397 @@ -define([ - 'core/js/adapt', - '../childEvent' -], function(Adapt, ChildEvent) { +import Adapt from 'core/js/adapt'; +import ChildEvent from '../childEvent'; +import { render } from '../reactHelpers'; - class AdaptView extends Backbone.View { +class AdaptView extends Backbone.View { - attributes() { - return { - 'data-adapt-id': this.model.get('_id') - }; - } - - initialize() { - this.listenTo(this.model, { - 'change:_isVisible': this.toggleVisibility, - 'change:_isHidden': this.toggleHidden, - 'change:_isComplete': this.onIsCompleteChange - }); - this.model.set({ - '_globals': Adapt.course.get('_globals'), - '_isReady': false - }); - this._isRemoved = false; - - if (Adapt.location._currentId === this.model.get('_id')) { - Adapt.parentView = this; - } + attributes() { + return { + 'data-adapt-id': this.model.get('_id') + }; + } - this.preRender(); - this.render(); - this.setupOnScreenHandler(); + initialize() { + this.listenTo(this.model, { + 'change:_isVisible': this.toggleVisibility, + 'change:_isHidden': this.toggleHidden, + 'change:_isComplete': this.onIsCompleteChange + }); + this.isReact = (this.constructor.template || '').includes('.jsx'); + if (this.isReact) { + this.listenTo(this.model, 'all', this.changed); + // Facilitate adaptive react views + this.listenTo(Adapt, 'device:changed', this.changed); + } + this.model.set({ + '_globals': Adapt.course.get('_globals'), + '_isReady': false + }); + this._isRemoved = false; + + if (Adapt.location._currentId === this.model.get('_id')) { + Adapt.parentView = this; } - preRender() {} + this.preRender(); + this.render(); + this.setupOnScreenHandler(); + } - postRender() { - this.addChildren(); - } + preRender() {} + + postRender() { + this.addChildren(); + } - render() { - const type = this.constructor.type; - Adapt.trigger(`${type}View:preRender view:preRender`, this); + render() { + const type = this.constructor.type; + Adapt.trigger(`${type}View:preRender view:preRender`, this); + if (this.isReact) { + this.changed(); + } else { const data = this.model.toJSON(); data.view = this; const template = Handlebars.templates[this.constructor.template]; this.$el.html(template(data)); + } - Adapt.trigger(`${type}View:render view:render`, this); + Adapt.trigger(`${type}View:render view:render`, this); - _.defer(() => { - // don't call postRender after remove - if (this._isRemoved) return; + _.defer(() => { + // don't call postRender after remove + if (this._isRemoved) return; - this.postRender(); - Adapt.trigger(`${type}View:postRender view:postRender`, this); - }); + this.postRender(); + Adapt.trigger(`${type}View:postRender view:postRender`, this); + }); + + return this; + } - return this; + /** + * Re-render a react template + * @param {string} eventName=null Backbone change event name + */ + changed(eventName = null) { + if (!this.isReact) { + throw new Error('Cannot call changed on a non-react view'); + } + if (typeof eventName === 'string' && eventName.startsWith('bubble')) { + // Ignore bubbling events as they are outside of this view's scope + return; } + const element = render(this.constructor.template.replace('.jsx', ''), this.model, this); + // eslint-disable-next-line no-undef + ReactDOM.render(element, this.el); + } - setupOnScreenHandler() { - const onscreen = this.model.get('_onScreen'); + setupOnScreenHandler() { + const onscreen = this.model.get('_onScreen'); - if (!onscreen || !onscreen._isEnabled) return; + if (!onscreen || !onscreen._isEnabled) return; - this.$el.addClass(`has-animation ${onscreen._classes}-before`); - this.$el.on('onscreen.adaptView', (e, m) => { - if (!m.onscreen) return; - const minVerticalInview = onscreen._percentInviewVertical || 33; - if (m.percentInviewVertical < minVerticalInview) return; - this.$el.addClass(`${onscreen._classes}-after`).off('onscreen.adaptView'); - }); - } + this.$el.addClass(`has-animation ${onscreen._classes}-before`); + this.$el.on('onscreen.adaptView', (e, m) => { + if (!m.onscreen) return; + const minVerticalInview = onscreen._percentInviewVertical || 33; + if (m.percentInviewVertical < minVerticalInview) return; + this.$el.addClass(`${onscreen._classes}-after`).off('onscreen.adaptView'); + }); + } - /** - * Add children and descendant views, first-child-first. Wait until all possible - * views are added before resolving asynchronously. - * Will trigger 'view:addChild'(ChildEvent), 'view:requestChild'(ChildEvent) - * and 'view:childAdded'(ParentView, ChildView) accordingly. - * @returns {number} Count of views added - */ - async addChildren() { - this.nthChild = this.nthChild || 0; - // Check descendants first - let addedCount = await this.addDescendants(false); - // Iterate through existing available children and/or request new children - // if required and allowed - while (true) { - const models = this.model.getAvailableChildModels(); - const event = this._getAddChildEvent(models[this.nthChild]); - if (!event) { - break; - } - if (event.isForced) { - event.reset(); - } - if (event.isStoppedImmediate || !event.model) { - // If addChild has been stopped before it is added then - // set all subsequent models and their children as not rendered - const subsequentModels = models.slice(this.nthChild); - subsequentModels.forEach(model => model.setOnChildren('_isRendered', false)); - break; - } - // Set model state - const model = event.model; - model.set({ - '_isRendered': true, - '_nthChild': ++this.nthChild - }); - // Create child view - const ChildView = this.constructor.childView || Adapt.getViewClass(model); - if (!ChildView) { - throw new Error(`The component '${model.attributes._id}' ('${model.attributes._component}') has not been installed, and so is not available in your project.`); - } - const childView = new ChildView({ model }); - this.addChildView(childView); - addedCount++; - if (event.isStoppedNext) { - break; - } + /** + * Add children and descendant views, first-child-first. Wait until all possible + * views are added before resolving asynchronously. + * Will trigger 'view:addChild'(ChildEvent), 'view:requestChild'(ChildEvent) + * and 'view:childAdded'(ParentView, ChildView) accordingly. + * @returns {number} Count of views added + */ + async addChildren() { + this.nthChild = this.nthChild || 0; + // Check descendants first + let addedCount = await this.addDescendants(false); + // Iterate through existing available children and/or request new children + // if required and allowed + while (true) { + const models = this.model.getAvailableChildModels(); + const event = this._getAddChildEvent(models[this.nthChild]); + if (!event) { + break; } - - if (!addedCount) { - return addedCount; + if (event.isForced) { + event.reset(); } + if (event.isStoppedImmediate || !event.model) { + // If addChild has been stopped before it is added then + // set all subsequent models and their children as not rendered + const subsequentModels = models.slice(this.nthChild); + subsequentModels.forEach(model => model.setOnChildren('_isRendered', false)); + break; + } + // Set model state + const model = event.model; + model.set({ + '_isRendered': true, + '_nthChild': ++this.nthChild + }); + // Create child view + const ChildView = this.constructor.childView || Adapt.getViewClass(model); + if (!ChildView) { + throw new Error(`The component '${model.attributes._id}' ('${model.attributes._component}') has not been installed, and so is not available in your project.`); + } + const childView = new ChildView({ model }); + this.addChildView(childView); + addedCount++; + if (event.isStoppedNext) { + break; + } + } - // Children were added, unset _isReady - this.model.set('_isReady', false); + if (!addedCount) { return addedCount; } - /** - * Child views can be added with '_renderPosition': 'outer-append' or - * 'inner-append' (default). Each child view will trigger a - * 'view:childAdded'(ParentView, ChildView) event and be added to the - * this.getChildViews() array on this parent. - * @param {AdaptView} childView - * @returns {AdaptView} Returns this childView - */ - addChildView(childView) { - const childViews = this.getChildViews() || []; - childViews.push(childView); - this.setChildViews(childViews); - const $parentContainer = this.$(this.constructor.childContainer); - switch (childView.model.get('_renderPosition')) { - case 'outer-append': - // Useful for trickle buttons, inline feedback etc - this.$el.append(childView.$el); - break; - case 'inner-append': - default: - $parentContainer.append(childView.$el); - break; - } - // Signify that a child has been added to the view to enable updates to status bars - Adapt.trigger('view:childAdded', this, childView); - return childView; + // Children were added, unset _isReady + this.model.set('_isReady', false); + return addedCount; + } + + /** + * Child views can be added with '_renderPosition': 'outer-append' or + * 'inner-append' (default). Each child view will trigger a + * 'view:childAdded'(ParentView, ChildView) event and be added to the + * this.getChildViews() array on this parent. + * @param {AdaptView} childView + * @returns {AdaptView} Returns this childView + */ + addChildView(childView) { + const childViews = this.getChildViews() || []; + childViews.push(childView); + this.setChildViews(childViews); + const $parentContainer = this.$(this.constructor.childContainer); + switch (childView.model.get('_renderPosition')) { + case 'outer-append': + // Useful for trickle buttons, inline feedback etc + this.$el.append(childView.$el); + break; + case 'inner-append': + default: + $parentContainer.append(childView.$el); + break; } + // Signify that a child has been added to the view to enable updates to status bars + Adapt.trigger('view:childAdded', this, childView); + return childView; + } - /** - * Iterates through existing childViews and runs addChildren on them, resolving - * the total count of views added asynchronously. - * @returns {number} Count of views added - */ - async addDescendants() { - let addedDescendantCount = 0; - const childViews = this.getChildViews(); - if (!childViews) { - return addedDescendantCount; - } - for (let i = 0, l = childViews.length; i < l; i++) { - const view = childViews[i]; - addedDescendantCount = view.addChildren ? await view.addChildren() : 0; - if (addedDescendantCount) { - break; - } - } - if (!addedDescendantCount) { - this.model.checkReadyStatus(); - return addedDescendantCount; + /** + * Iterates through existing childViews and runs addChildren on them, resolving + * the total count of views added asynchronously. + * @returns {number} Count of views added + */ + async addDescendants() { + let addedDescendantCount = 0; + const childViews = this.getChildViews(); + if (!childViews) { + return addedDescendantCount; + } + for (let i = 0, l = childViews.length; i < l; i++) { + const view = childViews[i]; + addedDescendantCount = view.addChildren ? await view.addChildren() : 0; + if (addedDescendantCount) { + break; } - // Descendants were added, unset _isReady - this.model.set('_isReady', false); + } + if (!addedDescendantCount) { + this.model.checkReadyStatus(); return addedDescendantCount; } + // Descendants were added, unset _isReady + this.model.set('_isReady', false); + return addedDescendantCount; + } - /** - * Resolves after outstanding asynchronous view additions are finished - * and ready. - */ - async whenReady() { - if (this.model.get('_isReady')) return; - return new Promise(resolve => { - const onReadyChange = (model, value) => { - if (!value) return; - this.stopListening(this.model, 'change:_isReady', onReadyChange); - resolve(); - }; - this.listenTo(this.model, 'change:_isReady', onReadyChange); - this.model.checkReadyStatus(); - }); - } + /** + * Resolves after outstanding asynchronous view additions are finished + * and ready. + */ + async whenReady() { + if (this.model.get('_isReady')) return; + return new Promise(resolve => { + const onReadyChange = (model, value) => { + if (!value) return; + this.stopListening(this.model, 'change:_isReady', onReadyChange); + resolve(); + }; + this.listenTo(this.model, 'change:_isReady', onReadyChange); + this.model.checkReadyStatus(); + }); + } - /** - * Triggers and returns a new ChildEvent object for render control. - * This function is used by addChildren to manage event triggering. - * @param {AdaptModel} model - * @returns {ChildEvent} - */ - _getAddChildEvent(model) { - const isRequestChild = (!model); - let event = new ChildEvent(null, this, model); - if (isRequestChild) { - // No model has been supplied, we are at the end of the available child list - const canRequestChild = this.model.get('_canRequestChild'); - if (!canRequestChild) { - // This model cannot request children - return; - } - event.type = 'requestChild'; - // Send a request asking for a new model - Adapt.trigger('view:requestChild', event); - if (!event.hasRequestChild) { - // No new model was supplied - // Close the event so that the final state can be scrutinized - event.close(); - return; - } - // A new model has been supplied for the end of the list. + /** + * Triggers and returns a new ChildEvent object for render control. + * This function is used by addChildren to manage event triggering. + * @param {AdaptModel} model + * @returns {ChildEvent} + */ + _getAddChildEvent(model) { + const isRequestChild = (!model); + let event = new ChildEvent(null, this, model); + if (isRequestChild) { + // No model has been supplied, we are at the end of the available child list + const canRequestChild = this.model.get('_canRequestChild'); + if (!canRequestChild) { + // This model cannot request children + return; } - // Trigger an event to signify that a new model is to be added - event.type = 'addChild'; - Adapt.trigger('view:addChild', event); - // Close the event so that the final state can be scrutinized - event.close(); - return event; + event.type = 'requestChild'; + // Send a request asking for a new model + Adapt.trigger('view:requestChild', event); + if (!event.hasRequestChild) { + // No new model was supplied + // Close the event so that the final state can be scrutinized + event.close(); + return; + } + // A new model has been supplied for the end of the list. } + // Trigger an event to signify that a new model is to be added + event.type = 'addChild'; + Adapt.trigger('view:addChild', event); + // Close the event so that the final state can be scrutinized + event.close(); + return event; + } - /** - * Return an array of all child and descendant views. - * @param {boolean} [isParentFirst=false] Array returns with parents before children - * @returns {[AdaptView]} - */ - findDescendantViews(isParentFirst) { - const descendants = []; - const childViews = this.getChildViews(); - childViews && childViews.forEach(view => { - if (isParentFirst) descendants.push(view); - const children = view.findDescendantViews && view.findDescendantViews(isParentFirst); - if (children) descendants.push(...children); - if (!isParentFirst) descendants.push(view); - }); - return descendants; - } + /** + * Return an array of all child and descendant views. + * @param {boolean} [isParentFirst=false] Array returns with parents before children + * @returns {[AdaptView]} + */ + findDescendantViews(isParentFirst) { + const descendants = []; + const childViews = this.getChildViews(); + childViews && childViews.forEach(view => { + if (isParentFirst) descendants.push(view); + const children = view.findDescendantViews && view.findDescendantViews(isParentFirst); + if (children) descendants.push(...children); + if (!isParentFirst) descendants.push(view); + }); + return descendants; + } - setReadyStatus() { - this.model.set('_isReady', true); - } + setReadyStatus() { + this.model.set('_isReady', true); + } - setCompletionStatus() { - if (!this.model.get('_isVisible')) return; - this.model.set({ - _isComplete: true, - _isInteractionComplete: true - }); - } + setCompletionStatus() { + if (!this.model.get('_isVisible')) return; + this.model.set({ + _isComplete: true, + _isInteractionComplete: true + }); + } - resetCompletionStatus(type) { - if (!this.model.get('_canReset')) return; + resetCompletionStatus(type) { + if (!this.model.get('_canReset')) return; - const descendantComponents = this.model.findDescendantModels('component'); - if (descendantComponents.length === 0) { - this.model.reset(type); - } else { - descendantComponents.forEach(model => model.reset(type)); - } + const descendantComponents = this.model.findDescendantModels('component'); + if (descendantComponents.length === 0) { + this.model.reset(type); + } else { + descendantComponents.forEach(model => model.reset(type)); } + } - preRemove() { - const type = this.constructor.type; - Adapt.trigger(`${type}View:preRemove view:preRemove`, this); - } + preRemove() { + const type = this.constructor.type; + Adapt.trigger(`${type}View:preRemove view:preRemove`, this); + } - remove() { - const type = this.constructor.type; - this.preRemove(); - Adapt.trigger(`${type}View:remove view:remove`, this); - this._isRemoved = true; - this.stopListening(); - - Adapt.wait.for(end => { - this.$el.off('onscreen.adaptView'); - super.remove(); - _.defer(() => { - Adapt.trigger(`${type}View:postRemove view:postRemove`, this); - }); - end(); + remove() { + const type = this.constructor.type; + this.preRemove(); + Adapt.trigger(`${type}View:remove view:remove`, this); + this._isRemoved = true; + this.stopListening(); + + Adapt.wait.for(end => { + if (this.isReact) { + // eslint-disable-next-line no-undef + ReactDOM.unmountComponentAtNode(this.el); + } + this.$el.off('onscreen.adaptView'); + super.remove(); + _.defer(() => { + Adapt.trigger(`${type}View:postRemove view:postRemove`, this); }); + end(); + }); - return this; - } + return this; + } - setVisibility() { - return this.model.get('_isVisible') ? '' : 'u-visibility-hidden'; - } + setVisibility() { + return this.model.get('_isVisible') ? '' : 'u-visibility-hidden'; + } - toggleVisibility() { - this.$el.toggleClass('u-visibility-hidden', !this.model.get('_isVisible')); - } + toggleVisibility() { + this.$el.toggleClass('u-visibility-hidden', !this.model.get('_isVisible')); + } - setHidden() { - return this.model.get('_isHidden') ? 'u-display-none' : ''; - } + setHidden() { + return this.model.get('_isHidden') ? 'u-display-none' : ''; + } - toggleHidden() { - this.$el.toggleClass('u-display-none', this.model.get('_isHidden')); - } + toggleHidden() { + this.$el.toggleClass('u-display-none', this.model.get('_isHidden')); + } - onIsCompleteChange(model, isComplete) { - this.$el.toggleClass('is-complete', isComplete); - } + onIsCompleteChange(model, isComplete) { + this.$el.toggleClass('is-complete', isComplete); + } - /** - * @returns {[AdaptViews]} - */ - getChildViews() { - return this._childViews; - } + /** + * @returns {[AdaptView]} + */ + getChildViews() { + if (!this._childViews) return this._childViews; + // Allow both a deprecated id/view map or a new array of child views + return Object.entries(this._childViews).map(([key, value]) => value); + } - /** - * @param {[AdaptView]} value - */ - setChildViews(value) { - this._childViews = value; - } + /** + * @param {[AdaptView]} value + */ + setChildViews(value) { + this._childViews = value; + } - /** - * Returns an indexed by id list of child views. - * @deprecated since 0.5.5 - * @returns {{ view.model.get('_id')); + /** + * Returns an indexed by id list of child views. + * @deprecated since 0.5.5 + * @returns {{ view.model.get('_id')); } + return this._childViews; + } + /** + * Sets an indexed by id list of child views. + * @deprecated since 0.5.5 + */ + set childViews(value) { + Adapt.log.deprecated(`view.childViews use view.getChildViews() and view.setChildViews([])`); + this.setChildViews(value); } - AdaptView.className = ''; +} - return AdaptView; +AdaptView.className = ''; -}); +export default AdaptView; diff --git a/src/core/js/views/contentObjectView.js b/src/core/js/views/contentObjectView.js index 7a20f1f10..72456bc47 100644 --- a/src/core/js/views/contentObjectView.js +++ b/src/core/js/views/contentObjectView.js @@ -36,10 +36,14 @@ define([ const type = this.constructor.type; Adapt.trigger(`${type}View:preRender contentObjectView:preRender view:preRender`, this); - const data = this.model.toJSON(); - data.view = this; - const template = Handlebars.templates[this.constructor.template]; - this.$el.html(template(data)); + if (this.isReact) { + this.changed(); + } else { + const data = this.model.toJSON(); + data.view = this; + const template = Handlebars.templates[this.constructor.template]; + this.$el.html(template(data)); + } Adapt.trigger(`${type}View:render contentObjectView:render view:render`, this); @@ -139,6 +143,9 @@ define([ this._isRemoved = true; Adapt.wait.for(end => { + if (this.isReact) { + ReactDOM.unmountComponentAtNode(this.el); + } this.$el.off('onscreen.adaptView'); this.findDescendantViews().reverse().forEach(view => { view.remove(); diff --git a/src/core/templates/partials/component.jsx b/src/core/templates/partials/component.jsx new file mode 100644 index 000000000..5b04187ed --- /dev/null +++ b/src/core/templates/partials/component.jsx @@ -0,0 +1,59 @@ +import Adapt from 'core/js/adapt'; +import { compile, classes, helper, html } from 'core/js/reactHelpers'; + +export default function(model, view) { + const data = model.toJSON(); + data._globals = Adapt.course.get('_globals'); + // Create references to un-controlled view containers + view.jsxHeading = view.jsxHeading || React.createRef(); + view.jsxComponentDescription = view.jsxComponentDescription || React.createRef(); + const { + displayTitle, + body, + instruction, + mobileInstruction, + _component, + _disableAccessibilityState + } = data; + const type = _component.toLowerCase(); + const sizedInstruction = (mobileInstruction && Adapt.device.screenSize !== 'large') ? + mobileInstruction : + instruction; + return (displayTitle || body || sizedInstruction) && +
+
+ {displayTitle && +
+ + {!_disableAccessibilityState && +
+ } + +
+ {`\n${html(compile(displayTitle, data))}\n`} +
+ +
+ } + + {html(helper('component_description', data), view.jsxComponentDescription)} + + {body && +
+
+ {html(compile(body, data))} +
+
+ } + + {sizedInstruction && +
+
+ {html(compile(sizedInstruction, data))} +
+
+ } + +
+
+} diff --git a/src/course/en/course.json b/src/course/en/course.json index 065261615..270191553 100755 --- a/src/course/en/course.json +++ b/src/course/en/course.json @@ -1,145 +1,145 @@ { - "_id": "course", - "_type": "course", - "_classes": "", - "_htmlClasses": "", - "title": "Adapt v5", - "displayTitle": "Adapt Version 5", - "description": "A sample course demonstrating the capabilities of the Adapt Framework", - "body": "Welcome to the demonstration build for version 5 of the Adapt framework.", - "instruction": "", - "_buttons": { - "_submit": { - "buttonText": "Submit", - "ariaLabel": "Submit" - }, - "_reset": { - "buttonText": "Reset", - "ariaLabel": "Reset" - }, - "_showCorrectAnswer": { - "buttonText": "Correct answer", - "ariaLabel": "Show correct answer" - }, - "_hideCorrectAnswer": { - "buttonText": "My answer", - "ariaLabel": "Show my answer" - }, - "_showFeedback": { - "buttonText": "Show feedback", - "ariaLabel": "Show feedback" - }, - "remainingAttemptsText": "attempts remaining", - "remainingAttemptText": "final attempt", - "disabledAriaLabel": "This button is disabled at the moment" + "_id": "course", + "_type": "course", + "_classes": "", + "_htmlClasses": "", + "title": "Adapt v5", + "displayTitle": "Adapt Version 5", + "description": "A sample course demonstrating the capabilities of the Adapt Framework", + "body": "Welcome to the demonstration build for version 5 of the Adapt framework.", + "instruction": "", + "_buttons": { + "_submit": { + "buttonText": "Submit", + "ariaLabel": "Submit" + }, + "_reset": { + "buttonText": "Reset", + "ariaLabel": "Reset" }, - "_globals": { - "_learnerInfo": { - "id": "student.name@example.org", - "name": "Name, Student", - "firstname": "Student", - "lastname": "Name" - }, - "_accessibility": { - "skipNavigationText": "Skip navigation", - "_ariaLabels": { - "answeredIncorrectly": "You answered incorrectly", - "answeredCorrectly": "You answered correctly", - "selectedAnswer": "selected", - "unselectedAnswer": "not selected", - "skipNavigation": "Skip Navigation", - "previous": "Back", - "navigationDrawer": "Open course resources.", - "close": "Close", - "closeDrawer": "Close drawer", - "closeResources": "Close resources", - "drawer": "Top of side drawer", - "closePopup": "Close popup", - "next": "Next", - "done": "Done", - "complete": "Completed", - "incomplete": "Incomplete", - "incorrect": "Incorrect", - "correct": "Correct", - "locked": "Locked", - "visited": "Visited" - } - } + "_showCorrectAnswer": { + "buttonText": "Correct answer", + "ariaLabel": "Show correct answer" }, - "_latestTrackingId": 19, - "_pageLevelProgress": { - "_isEnabled": true, - "_showPageCompletion": false, - "_isCompletionIndicatorEnabled": false, - "_isShownInNavigationBar": true + "_hideCorrectAnswer": { + "buttonText": "My answer", + "ariaLabel": "Show my answer" }, - "_resources": { - "_isEnabled": true, - "title": "Resources", - "description": "View resources for this course by clicking here.", - "_filterButtons": { - "all": "All", - "document": "Document", - "media": "Media", - "link": "Link" - }, - "_filterAria": { - "allAria": "View all resources", - "documentAria": "View document resources", - "mediaAria": "View media resources", - "linkAria": "View resource links" - }, - "_resourcesItems": [ - { - "_type": "document", - "title": "Vanilla Theme Swatch", - "description": "See the swatch for the vanilla theme by clicking here.", - "_link": "course/en/images/vanilla-swatch.jpg" - }, - { - "_type": "media", - "title": "Adapt Learning YouTube Channel", - "description": "Fancy catching up on some Adapt material? Click here.", - "_link": "https://www.youtube.com/channel/UCW8SlSFuCc--B66Gf9fAEcQ" - }, - { - "_type": "link", - "title": "Adapt Project Site", - "description": "View the project's web site by clicking here.", - "_link": "https://www.adaptlearning.org/" - }, - { - "_type": "link", - "title": "Framework chat", - "description": "Join the framework chat room by clicking here.", - "_link": "https://gitter.im/adaptlearning/adapt_framework" - } - ] + "_showFeedback": { + "buttonText": "Show feedback", + "ariaLabel": "Show feedback" }, - "_start": { - "_isEnabled": false, - "_startIds": [ - { - "_id": "co-05", - "_skipIfComplete": true, - "_className": "" - } - ], - "_force": false, - "_isMenuDisabled": false + "remainingAttemptsText": "attempts remaining", + "remainingAttemptText": "final attempt", + "disabledAriaLabel": "This button is disabled at the moment" + }, + "_globals": { + "_learnerInfo": { + "id": "student.name@example.org", + "name": "Name, Student", + "firstname": "Student", + "lastname": "Name" }, - "_assessment": { - "_isPercentageBased": true, - "_scoreToPass": 75 + "_accessibility": { + "skipNavigationText": "Skip navigation", + "_ariaLabels": { + "answeredIncorrectly": "You answered incorrectly", + "answeredCorrectly": "You answered correctly", + "selectedAnswer": "selected", + "unselectedAnswer": "not selected", + "skipNavigation": "Skip Navigation", + "previous": "Back", + "navigationDrawer": "Open course resources.", + "close": "Close", + "closeDrawer": "Close drawer", + "closeResources": "Close resources", + "drawer": "Top of side drawer", + "closePopup": "Close popup", + "next": "Next", + "done": "Done", + "complete": "Completed", + "incomplete": "Incomplete", + "incorrect": "Incorrect", + "correct": "Correct", + "locked": "Locked", + "visited": "Visited" + } + } + }, + "_latestTrackingId": 19, + "_pageLevelProgress": { + "_isEnabled": true, + "_showPageCompletion": false, + "_isCompletionIndicatorEnabled": false, + "_isShownInNavigationBar": true + }, + "_resources": { + "_isEnabled": true, + "title": "Resources", + "description": "View resources for this course by clicking here.", + "_filterButtons": { + "all": "All", + "document": "Document", + "media": "Media", + "link": "Link" }, - "_bookmarking": { - "_isEnabled": true, - "_level": "component", - "title": "Resume?", - "body": "Would you like to resume the course from the location you were at last time?", - "_buttons": { - "yes": "Yes", - "no": "No" - } + "_filterAria": { + "allAria": "View all resources", + "documentAria": "View document resources", + "mediaAria": "View media resources", + "linkAria": "View resource links" + }, + "_resourcesItems": [ + { + "_type": "document", + "title": "Vanilla Theme Swatch", + "description": "See the swatch for the vanilla theme by clicking here.", + "_link": "course/en/images/vanilla-swatch.jpg" + }, + { + "_type": "media", + "title": "Adapt Learning YouTube Channel", + "description": "Fancy catching up on some Adapt material? Click here.", + "_link": "https://www.youtube.com/channel/UCW8SlSFuCc--B66Gf9fAEcQ" + }, + { + "_type": "link", + "title": "Adapt Project Site", + "description": "View the project's web site by clicking here.", + "_link": "https://www.adaptlearning.org/" + }, + { + "_type": "link", + "title": "Framework chat", + "description": "Join the framework chat room by clicking here.", + "_link": "https://gitter.im/adaptlearning/adapt_framework" + } + ] + }, + "_start": { + "_isEnabled": false, + "_startIds": [ + { + "_id": "co-05", + "_skipIfComplete": true, + "_className": "" + } + ], + "_force": false, + "_isMenuDisabled": false + }, + "_assessment": { + "_isPercentageBased": true, + "_scoreToPass": 75 + }, + "_bookmarking": { + "_isEnabled": true, + "_level": "component", + "title": "Resume?", + "body": "Would you like to resume the course from the location you were at last time?", + "_buttons": { + "yes": "Yes", + "no": "No" } + } } From 1e9a930e10897337c90e7833ae7f58e334903b60 Mon Sep 17 00:00:00 2001 From: Oliver Foster Date: Mon, 2 Nov 2020 12:21:38 +0000 Subject: [PATCH 2/6] issue/2824-react Revert course.json changes --- src/course/en/course.json | 272 +++++++++++++++++++------------------- 1 file changed, 136 insertions(+), 136 deletions(-) diff --git a/src/course/en/course.json b/src/course/en/course.json index 270191553..065261615 100755 --- a/src/course/en/course.json +++ b/src/course/en/course.json @@ -1,145 +1,145 @@ { - "_id": "course", - "_type": "course", - "_classes": "", - "_htmlClasses": "", - "title": "Adapt v5", - "displayTitle": "Adapt Version 5", - "description": "A sample course demonstrating the capabilities of the Adapt Framework", - "body": "Welcome to the demonstration build for version 5 of the Adapt framework.", - "instruction": "", - "_buttons": { - "_submit": { - "buttonText": "Submit", - "ariaLabel": "Submit" - }, - "_reset": { - "buttonText": "Reset", - "ariaLabel": "Reset" + "_id": "course", + "_type": "course", + "_classes": "", + "_htmlClasses": "", + "title": "Adapt v5", + "displayTitle": "Adapt Version 5", + "description": "A sample course demonstrating the capabilities of the Adapt Framework", + "body": "Welcome to the demonstration build for version 5 of the Adapt framework.", + "instruction": "", + "_buttons": { + "_submit": { + "buttonText": "Submit", + "ariaLabel": "Submit" + }, + "_reset": { + "buttonText": "Reset", + "ariaLabel": "Reset" + }, + "_showCorrectAnswer": { + "buttonText": "Correct answer", + "ariaLabel": "Show correct answer" + }, + "_hideCorrectAnswer": { + "buttonText": "My answer", + "ariaLabel": "Show my answer" + }, + "_showFeedback": { + "buttonText": "Show feedback", + "ariaLabel": "Show feedback" + }, + "remainingAttemptsText": "attempts remaining", + "remainingAttemptText": "final attempt", + "disabledAriaLabel": "This button is disabled at the moment" }, - "_showCorrectAnswer": { - "buttonText": "Correct answer", - "ariaLabel": "Show correct answer" + "_globals": { + "_learnerInfo": { + "id": "student.name@example.org", + "name": "Name, Student", + "firstname": "Student", + "lastname": "Name" + }, + "_accessibility": { + "skipNavigationText": "Skip navigation", + "_ariaLabels": { + "answeredIncorrectly": "You answered incorrectly", + "answeredCorrectly": "You answered correctly", + "selectedAnswer": "selected", + "unselectedAnswer": "not selected", + "skipNavigation": "Skip Navigation", + "previous": "Back", + "navigationDrawer": "Open course resources.", + "close": "Close", + "closeDrawer": "Close drawer", + "closeResources": "Close resources", + "drawer": "Top of side drawer", + "closePopup": "Close popup", + "next": "Next", + "done": "Done", + "complete": "Completed", + "incomplete": "Incomplete", + "incorrect": "Incorrect", + "correct": "Correct", + "locked": "Locked", + "visited": "Visited" + } + } }, - "_hideCorrectAnswer": { - "buttonText": "My answer", - "ariaLabel": "Show my answer" + "_latestTrackingId": 19, + "_pageLevelProgress": { + "_isEnabled": true, + "_showPageCompletion": false, + "_isCompletionIndicatorEnabled": false, + "_isShownInNavigationBar": true }, - "_showFeedback": { - "buttonText": "Show feedback", - "ariaLabel": "Show feedback" + "_resources": { + "_isEnabled": true, + "title": "Resources", + "description": "View resources for this course by clicking here.", + "_filterButtons": { + "all": "All", + "document": "Document", + "media": "Media", + "link": "Link" + }, + "_filterAria": { + "allAria": "View all resources", + "documentAria": "View document resources", + "mediaAria": "View media resources", + "linkAria": "View resource links" + }, + "_resourcesItems": [ + { + "_type": "document", + "title": "Vanilla Theme Swatch", + "description": "See the swatch for the vanilla theme by clicking here.", + "_link": "course/en/images/vanilla-swatch.jpg" + }, + { + "_type": "media", + "title": "Adapt Learning YouTube Channel", + "description": "Fancy catching up on some Adapt material? Click here.", + "_link": "https://www.youtube.com/channel/UCW8SlSFuCc--B66Gf9fAEcQ" + }, + { + "_type": "link", + "title": "Adapt Project Site", + "description": "View the project's web site by clicking here.", + "_link": "https://www.adaptlearning.org/" + }, + { + "_type": "link", + "title": "Framework chat", + "description": "Join the framework chat room by clicking here.", + "_link": "https://gitter.im/adaptlearning/adapt_framework" + } + ] }, - "remainingAttemptsText": "attempts remaining", - "remainingAttemptText": "final attempt", - "disabledAriaLabel": "This button is disabled at the moment" - }, - "_globals": { - "_learnerInfo": { - "id": "student.name@example.org", - "name": "Name, Student", - "firstname": "Student", - "lastname": "Name" + "_start": { + "_isEnabled": false, + "_startIds": [ + { + "_id": "co-05", + "_skipIfComplete": true, + "_className": "" + } + ], + "_force": false, + "_isMenuDisabled": false }, - "_accessibility": { - "skipNavigationText": "Skip navigation", - "_ariaLabels": { - "answeredIncorrectly": "You answered incorrectly", - "answeredCorrectly": "You answered correctly", - "selectedAnswer": "selected", - "unselectedAnswer": "not selected", - "skipNavigation": "Skip Navigation", - "previous": "Back", - "navigationDrawer": "Open course resources.", - "close": "Close", - "closeDrawer": "Close drawer", - "closeResources": "Close resources", - "drawer": "Top of side drawer", - "closePopup": "Close popup", - "next": "Next", - "done": "Done", - "complete": "Completed", - "incomplete": "Incomplete", - "incorrect": "Incorrect", - "correct": "Correct", - "locked": "Locked", - "visited": "Visited" - } - } - }, - "_latestTrackingId": 19, - "_pageLevelProgress": { - "_isEnabled": true, - "_showPageCompletion": false, - "_isCompletionIndicatorEnabled": false, - "_isShownInNavigationBar": true - }, - "_resources": { - "_isEnabled": true, - "title": "Resources", - "description": "View resources for this course by clicking here.", - "_filterButtons": { - "all": "All", - "document": "Document", - "media": "Media", - "link": "Link" + "_assessment": { + "_isPercentageBased": true, + "_scoreToPass": 75 }, - "_filterAria": { - "allAria": "View all resources", - "documentAria": "View document resources", - "mediaAria": "View media resources", - "linkAria": "View resource links" - }, - "_resourcesItems": [ - { - "_type": "document", - "title": "Vanilla Theme Swatch", - "description": "See the swatch for the vanilla theme by clicking here.", - "_link": "course/en/images/vanilla-swatch.jpg" - }, - { - "_type": "media", - "title": "Adapt Learning YouTube Channel", - "description": "Fancy catching up on some Adapt material? Click here.", - "_link": "https://www.youtube.com/channel/UCW8SlSFuCc--B66Gf9fAEcQ" - }, - { - "_type": "link", - "title": "Adapt Project Site", - "description": "View the project's web site by clicking here.", - "_link": "https://www.adaptlearning.org/" - }, - { - "_type": "link", - "title": "Framework chat", - "description": "Join the framework chat room by clicking here.", - "_link": "https://gitter.im/adaptlearning/adapt_framework" - } - ] - }, - "_start": { - "_isEnabled": false, - "_startIds": [ - { - "_id": "co-05", - "_skipIfComplete": true, - "_className": "" - } - ], - "_force": false, - "_isMenuDisabled": false - }, - "_assessment": { - "_isPercentageBased": true, - "_scoreToPass": 75 - }, - "_bookmarking": { - "_isEnabled": true, - "_level": "component", - "title": "Resume?", - "body": "Would you like to resume the course from the location you were at last time?", - "_buttons": { - "yes": "Yes", - "no": "No" + "_bookmarking": { + "_isEnabled": true, + "_level": "component", + "title": "Resume?", + "body": "Would you like to resume the course from the location you were at last time?", + "_buttons": { + "yes": "Yes", + "no": "No" + } } - } } From befc898ba0e17b58f81cc9ce7aaaf8c770864a87 Mon Sep 17 00:00:00 2001 From: Oliver Foster Date: Tue, 10 Nov 2020 17:03:55 +0000 Subject: [PATCH 3/6] issue/2824-react Recommendations --- grunt/tasks/javascript.js | 4 +- package-lock.json | 487 +++++++++++++++++++++- package.json | 2 +- src/core/js/views/adaptView.js | 4 +- src/core/templates/partials/component.jsx | 3 +- 5 files changed, 483 insertions(+), 17 deletions(-) diff --git a/grunt/tasks/javascript.js b/grunt/tasks/javascript.js index 41145eec2..64386ef5d 100644 --- a/grunt/tasks/javascript.js +++ b/grunt/tasks/javascript.js @@ -162,9 +162,7 @@ module.exports = function(grunt) { options.reactTemplates.forEach(pattern => { grunt.file.expand({ filter: options.pluginsFilter - }, pattern).forEach(function(templatePath) { - reactTemplatePaths.push(templatePath.replace(convertSlashes, '/')); - }); + }, pattern).forEach(templatePath => reactTemplatePaths.push(templatePath.replace(convertSlashes, '/'))); }); // Process remapping and external model configurations diff --git a/package-lock.json b/package-lock.json index 118a0a042..782916ac8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -73,6 +73,83 @@ "@babel/types": "^7.10.1" } }, + "@babel/helper-builder-react-jsx": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.10.4.tgz", + "integrity": "sha512-5nPcIZ7+KKDxT1427oBivl9V9YTal7qk0diccnh7RrcgrT/pGFOjgGw1dgryyx1GvHEpXVfoDF6Ak3rTiWh8Rg==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/types": "^7.10.4" + }, + "dependencies": { + "@babel/helper-annotate-as-pure": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz", + "integrity": "sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA==", + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==" + }, + "@babel/types": { + "version": "7.12.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.6.tgz", + "integrity": "sha512-hwyjw6GvjBLiyy3W0YQf0Z5Zf4NpYejUnKFcfcUhZCSffoBBp30w6wP2Wn6pk31jMYZvcOrB/1b7cGXvEoKogA==", + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + } + } + }, + "@babel/helper-builder-react-jsx-experimental": { + "version": "7.12.4", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-react-jsx-experimental/-/helper-builder-react-jsx-experimental-7.12.4.tgz", + "integrity": "sha512-AjEa0jrQqNk7eDQOo0pTfUOwQBMF+xVqrausQwT9/rTKy0g04ggFNaJpaE09IQMn9yExluigWMJcj0WC7bq+Og==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-module-imports": "^7.12.1", + "@babel/types": "^7.12.1" + }, + "dependencies": { + "@babel/helper-annotate-as-pure": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz", + "integrity": "sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA==", + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-module-imports": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz", + "integrity": "sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA==", + "requires": { + "@babel/types": "^7.12.5" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==" + }, + "@babel/types": { + "version": "7.12.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.6.tgz", + "integrity": "sha512-hwyjw6GvjBLiyy3W0YQf0Z5Zf4NpYejUnKFcfcUhZCSffoBBp30w6wP2Wn6pk31jMYZvcOrB/1b7cGXvEoKogA==", + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + } + } + }, "@babel/helper-compilation-targets": { "version": "7.10.2", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.2.tgz", @@ -418,6 +495,21 @@ "@babel/helper-plugin-utils": "^7.8.0" } }, + "@babel/plugin-syntax-jsx": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz", + "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" + } + } + }, "@babel/plugin-syntax-nullish-coalescing-operator": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", @@ -674,6 +766,125 @@ "@babel/helper-plugin-utils": "^7.10.1" } }, + "@babel/plugin-transform-react-display-name": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.12.1.tgz", + "integrity": "sha512-cAzB+UzBIrekfYxyLlFqf/OagTvHLcVBb5vpouzkYkBclRPraiygVnafvAoipErZLI8ANv8Ecn6E/m5qPXD26w==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" + } + } + }, + "@babel/plugin-transform-react-jsx": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.12.5.tgz", + "integrity": "sha512-2xkcPqqrYiOQgSlM/iwto1paPijjsDbUynN13tI6bosDz/jOW3CRzYguIE8wKX32h+msbBM22Dv5fwrFkUOZjQ==", + "requires": { + "@babel/helper-builder-react-jsx": "^7.10.4", + "@babel/helper-builder-react-jsx-experimental": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-jsx": "^7.12.1" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" + } + } + }, + "@babel/plugin-transform-react-jsx-development": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.12.5.tgz", + "integrity": "sha512-1JJusg3iPgsZDthyWiCr3KQiGs31ikU/mSf2N2dSYEAO0GEImmVUbWf0VoSDGDFTAn5Dj4DUiR6SdIXHY7tELA==", + "requires": { + "@babel/helper-builder-react-jsx-experimental": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-jsx": "^7.12.1" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" + } + } + }, + "@babel/plugin-transform-react-jsx-self": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.12.1.tgz", + "integrity": "sha512-FbpL0ieNWiiBB5tCldX17EtXgmzeEZjFrix72rQYeq9X6nUK38HCaxexzVQrZWXanxKJPKVVIU37gFjEQYkPkA==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" + } + } + }, + "@babel/plugin-transform-react-jsx-source": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.12.1.tgz", + "integrity": "sha512-keQ5kBfjJNRc6zZN1/nVHCd6LLIHq4aUKcVnvE/2l+ZZROSbqoiGFRtT5t3Is89XJxBQaP7NLZX2jgGHdZvvFQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" + } + } + }, + "@babel/plugin-transform-react-pure-annotations": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.12.1.tgz", + "integrity": "sha512-RqeaHiwZtphSIUZ5I85PEH19LOSzxfuEazoY7/pWASCAIBuATQzpSVD+eT6MebeeZT2F4eSL0u4vw6n4Nm0Mjg==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + }, + "dependencies": { + "@babel/helper-annotate-as-pure": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz", + "integrity": "sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA==", + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" + }, + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==" + }, + "@babel/types": { + "version": "7.12.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.6.tgz", + "integrity": "sha512-hwyjw6GvjBLiyy3W0YQf0Z5Zf4NpYejUnKFcfcUhZCSffoBBp30w6wP2Wn6pk31jMYZvcOrB/1b7cGXvEoKogA==", + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + } + } + }, "@babel/plugin-transform-regenerator": { "version": "7.10.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.1.tgz", @@ -832,6 +1043,27 @@ "esutils": "^2.0.2" } }, + "@babel/preset-react": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.12.5.tgz", + "integrity": "sha512-jcs++VPrgyFehkMezHtezS2BpnUlR7tQFAyesJn1vGTO9aTFZrgIQrA5YydlTwxbcjMwkFY6i04flCigRRr3GA==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-transform-react-display-name": "^7.12.1", + "@babel/plugin-transform-react-jsx": "^7.12.5", + "@babel/plugin-transform-react-jsx-development": "^7.12.5", + "@babel/plugin-transform-react-jsx-self": "^7.12.1", + "@babel/plugin-transform-react-jsx-source": "^7.12.1", + "@babel/plugin-transform-react-pure-annotations": "^7.12.1" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" + } + } + }, "@babel/runtime": { "version": "7.10.2", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.10.2.tgz", @@ -899,6 +1131,50 @@ "fastq": "^1.6.0" } }, + "@rollup/plugin-babel": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.2.1.tgz", + "integrity": "sha512-Jd7oqFR2dzZJ3NWANDyBjwTtX/lYbZpVcmkHrfQcpvawHs9E4c0nYk5U2mfZ6I/DZcIvy506KZJi54XK/jxH7A==", + "requires": { + "@babel/helper-module-imports": "^7.10.4", + "@rollup/pluginutils": "^3.1.0" + }, + "dependencies": { + "@babel/helper-module-imports": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz", + "integrity": "sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA==", + "requires": { + "@babel/types": "^7.12.5" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==" + }, + "@babel/types": { + "version": "7.12.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.6.tgz", + "integrity": "sha512-hwyjw6GvjBLiyy3W0YQf0Z5Zf4NpYejUnKFcfcUhZCSffoBBp30w6wP2Wn6pk31jMYZvcOrB/1b7cGXvEoKogA==", + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + } + } + }, + "@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "requires": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + } + }, "@sindresorhus/is": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", @@ -919,6 +1195,24 @@ "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", "dev": true }, + "@types/domhandler": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/domhandler/-/domhandler-2.4.1.tgz", + "integrity": "sha512-cfBw6q6tT5sa1gSPFSRKzF/xxYrrmeiut7E0TxNBObiLSBTuFEHibcfEe3waQPEDbqBsq+ql/TOniw65EyDFMA==" + }, + "@types/domutils": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@types/domutils/-/domutils-1.7.3.tgz", + "integrity": "sha512-EucnS75OnnEdypNt+UpARisSF8eJBq4no+aVOis3Bs5kyABDXm1hEDv6jJxcMJPjR+a2YCrEANaW+BMT2QVG2Q==", + "requires": { + "domhandler": "^2.4.0" + } + }, + "@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==" + }, "@types/glob": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", @@ -928,6 +1222,16 @@ "@types/node": "*" } }, + "@types/htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@types/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-fCxmHS4ryCUCfV9+CJZY1UjkbR+6Al/EQdX5Jh03qBj9gdlPG5q+7uNoDgE/ZNXb3XNWSAQgqKIWnbRCbOyyWA==", + "requires": { + "@types/domhandler": "*", + "@types/domutils": "*", + "@types/node": "*" + } + }, "@types/jquery": { "version": "3.3.38", "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.3.38.tgz", @@ -1211,6 +1515,38 @@ "object.assign": "^4.1.0" } }, + "babel-plugin-transform-amd-to-es6": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-amd-to-es6/-/babel-plugin-transform-amd-to-es6-0.3.0.tgz", + "integrity": "sha512-CIcbgKoYPO1cKdvMP7+Dz1Ag0sd37RpsYU1nrpRouI5snlOIE/A0S5ff2YNoq3TdDgo7mzgT3/HmzOEG73knwA==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "minimatch": "^3.0.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" + } + } + }, + "babel-plugin-transform-react-templates": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-templates/-/babel-plugin-transform-react-templates-0.1.0.tgz", + "integrity": "sha512-mSUzQjCZfx7+DXZSJKE035tbCrRPE5mQxi3ffh2DTyl2NRsjJtcv65o52RjJ+F3dgSJc9SC3lM0o5gHPyWH3Aw==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "minimatch": "^3.0.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" + } + } + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -2197,6 +2533,14 @@ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" }, + "domhandler": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "requires": { + "domelementtype": "1" + } + }, "domutils": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", @@ -2790,6 +3134,11 @@ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true }, + "estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==" + }, "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -3157,6 +3506,12 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "optional": true + }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -3365,11 +3720,6 @@ } } }, - "grunt-babel": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/grunt-babel/-/grunt-babel-8.0.0.tgz", - "integrity": "sha512-WuiZFvGzcyzlEoPIcY1snI234ydDWeWWV5bpnB7PZsOLHcDsxWKnrR1rMWEUsbdVPPjvIirwFNsuo4CbJmsdFQ==" - }, "grunt-concurrent": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/grunt-concurrent/-/grunt-concurrent-2.3.1.tgz", @@ -3716,6 +4066,57 @@ "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz", "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==" }, + "html-dom-parser": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/html-dom-parser/-/html-dom-parser-0.3.0.tgz", + "integrity": "sha512-WDEYpO5gHGKuJbf0rwndGq7yUHJ4xboNj9l9mRGw5RsKFc3jfRozCsGAMu69zXxt4Ol8UkbqubKxu8ys0BLKtA==", + "requires": { + "@types/domhandler": "2.4.1", + "domhandler": "2.4.2", + "htmlparser2": "3.10.1" + } + }, + "html-react-parser": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/html-react-parser/-/html-react-parser-0.13.0.tgz", + "integrity": "sha512-hU94hE2p9xhMM61EOoiY3Kr+DfzH/uY7hGeVXQpGFRjgbYRUeyuSKORDNMIaY8IAcuHQ6Ov9pJ3x94Wvso/OmQ==", + "requires": { + "@types/htmlparser2": "3.10.1", + "html-dom-parser": "0.3.0", + "react-property": "1.0.1", + "style-to-object": "0.3.0" + } + }, + "htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", + "requires": { + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, "http-cache-semantics": { "version": "3.8.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", @@ -3995,6 +4396,11 @@ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" }, + "inline-style-parser": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", + "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" + }, "inquirer": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.2.0.tgz", @@ -5538,6 +5944,16 @@ "asap": "~2.0.3" } }, + "prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + }, "proto-list": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", @@ -5630,6 +6046,37 @@ } } }, + "react": { + "version": "16.14.0", + "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", + "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2" + } + }, + "react-dom": { + "version": "16.14.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz", + "integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "scheduler": "^0.19.1" + } + }, + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "react-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/react-property/-/react-property-1.0.1.tgz", + "integrity": "sha512-1tKOwxFn3dXVomH6pM9IkLkq2Y8oh+fh/lYW3MJ/B03URswUTqttgckOlbxY2XHF3vPG6uanSc4dVsLW/wk3wQ==" + }, "read-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", @@ -5814,11 +6261,6 @@ "editions": "^2.2.0" } }, - "requirejs": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/requirejs/-/requirejs-2.3.6.tgz", - "integrity": "sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg==" - }, "resolve": { "version": "1.17.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", @@ -5871,6 +6313,14 @@ "glob": "^7.1.3" } }, + "rollup": { + "version": "2.33.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.33.1.tgz", + "integrity": "sha512-uY4O/IoL9oNW8MMcbA5hcOaz6tZTMIh7qJHx/tzIJm+n1wLoY38BLn6fuy7DhR57oNFLMbDQtDeJoFURt5933w==", + "requires": { + "fsevents": "~2.1.2" + } + }, "run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -5920,6 +6370,15 @@ "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, + "scheduler": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz", + "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, "seek-bzip": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.6.tgz", @@ -6374,6 +6833,14 @@ "escape-string-regexp": "^1.0.2" } }, + "style-to-object": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz", + "integrity": "sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==", + "requires": { + "inline-style-parser": "0.1.1" + } + }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", diff --git a/package.json b/package.json index 9e9f35cdb..9ec06b19a 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,6 @@ "async": "^3.1.1", "babel-plugin-transform-amd-to-es6": "^0.3.0", "babel-plugin-transform-react-templates": "^0.1.0", - "html-react-parser": "^0.13.0", "chalk": "^2.4.1", "columnify": "^1.5.4", "csv": "^5.0.0", @@ -44,6 +43,7 @@ "grunt-newer": "^1.3.0", "grunt-replace": "^1.0.1", "handlebars": "^4.0.12", + "html-react-parser": "^0.13.0", "iconv-lite": "^0.4.24", "imagemin": "^7.0.1", "imagemin-jpegtran": "^7.0.0", diff --git a/src/core/js/views/adaptView.js b/src/core/js/views/adaptView.js index 90836fa52..43e317acd 100644 --- a/src/core/js/views/adaptView.js +++ b/src/core/js/views/adaptView.js @@ -370,7 +370,7 @@ class AdaptView extends Backbone.View { /** * Returns an indexed by id list of child views. - * @deprecated since 0.5.5 + * @deprecated since 5.7.0 * @returns {{
{displayTitle && @@ -56,4 +56,5 @@ export default function(model, view) {
+ ) } From f013ca9dae3c51fc6c28f03ee4c5e4a8eb13d71d Mon Sep 17 00:00:00 2001 From: Oliver Foster Date: Tue, 5 Jan 2021 16:22:33 +0000 Subject: [PATCH 4/6] issue/2824-react Fixed merge conflicts --- package-lock.json | 56 ----------------------------------------------- package.json | 6 +---- 2 files changed, 1 insertion(+), 61 deletions(-) diff --git a/package-lock.json b/package-lock.json index 861066388..a5ab6cf85 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1132,15 +1132,9 @@ } }, "@rollup/plugin-babel": { -<<<<<<< HEAD - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.2.1.tgz", - "integrity": "sha512-Jd7oqFR2dzZJ3NWANDyBjwTtX/lYbZpVcmkHrfQcpvawHs9E4c0nYk5U2mfZ6I/DZcIvy506KZJi54XK/jxH7A==", -======= "version": "5.2.2", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.2.2.tgz", "integrity": "sha512-MjmH7GvFT4TW8xFdIeFS3wqIX646y5tACdxkTO+khbHvS3ZcVJL6vkAHLw2wqPmkhwCfWHoNsp15VYNwW6JEJA==", ->>>>>>> e91e8911ad36a49389327b2bfd57a9277ee83381 "requires": { "@babel/helper-module-imports": "^7.10.4", "@rollup/pluginutils": "^3.1.0" @@ -1160,15 +1154,9 @@ "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==" }, "@babel/types": { -<<<<<<< HEAD - "version": "7.12.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.6.tgz", - "integrity": "sha512-hwyjw6GvjBLiyy3W0YQf0Z5Zf4NpYejUnKFcfcUhZCSffoBBp30w6wP2Wn6pk31jMYZvcOrB/1b7cGXvEoKogA==", -======= "version": "7.12.7", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz", "integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==", ->>>>>>> e91e8911ad36a49389327b2bfd57a9277ee83381 "requires": { "@babel/helper-validator-identifier": "^7.10.4", "lodash": "^4.17.19", @@ -1207,22 +1195,6 @@ "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", "dev": true }, -<<<<<<< HEAD - "@types/domhandler": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@types/domhandler/-/domhandler-2.4.1.tgz", - "integrity": "sha512-cfBw6q6tT5sa1gSPFSRKzF/xxYrrmeiut7E0TxNBObiLSBTuFEHibcfEe3waQPEDbqBsq+ql/TOniw65EyDFMA==" - }, - "@types/domutils": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@types/domutils/-/domutils-1.7.3.tgz", - "integrity": "sha512-EucnS75OnnEdypNt+UpARisSF8eJBq4no+aVOis3Bs5kyABDXm1hEDv6jJxcMJPjR+a2YCrEANaW+BMT2QVG2Q==", - "requires": { - "domhandler": "^2.4.0" - } - }, -======= ->>>>>>> e91e8911ad36a49389327b2bfd57a9277ee83381 "@types/estree": { "version": "0.0.39", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", @@ -1531,31 +1503,9 @@ } }, "babel-plugin-transform-amd-to-es6": { -<<<<<<< HEAD - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-amd-to-es6/-/babel-plugin-transform-amd-to-es6-0.3.0.tgz", - "integrity": "sha512-CIcbgKoYPO1cKdvMP7+Dz1Ag0sd37RpsYU1nrpRouI5snlOIE/A0S5ff2YNoq3TdDgo7mzgT3/HmzOEG73knwA==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "minimatch": "^3.0.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" - } - } - }, - "babel-plugin-transform-react-templates": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-templates/-/babel-plugin-transform-react-templates-0.1.0.tgz", - "integrity": "sha512-mSUzQjCZfx7+DXZSJKE035tbCrRPE5mQxi3ffh2DTyl2NRsjJtcv65o52RjJ+F3dgSJc9SC3lM0o5gHPyWH3Aw==", -======= "version": "0.4.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-amd-to-es6/-/babel-plugin-transform-amd-to-es6-0.4.1.tgz", "integrity": "sha512-KFwxBISDTujitT5ik5E0hrvqoTZwNksgNNPRSEOFC+natNFnuLWYkx8Ggk9gUn6JIhtm6ShTXVCuhYOkQnIC8Q==", ->>>>>>> e91e8911ad36a49389327b2bfd57a9277ee83381 "requires": { "@babel/helper-plugin-utils": "^7.10.4", "minimatch": "^3.0.4" @@ -6335,15 +6285,9 @@ } }, "rollup": { -<<<<<<< HEAD - "version": "2.33.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.33.1.tgz", - "integrity": "sha512-uY4O/IoL9oNW8MMcbA5hcOaz6tZTMIh7qJHx/tzIJm+n1wLoY38BLn6fuy7DhR57oNFLMbDQtDeJoFURt5933w==", -======= "version": "2.34.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.34.1.tgz", "integrity": "sha512-tGveB6NU5x4MS/iXaIsjfUkEv4hxzJJ4o0FRy5LO62Ndx3R2cmE1qsLYlSfRkvHUUPqWiFoxEm8pRftzh1a5HA==", ->>>>>>> e91e8911ad36a49389327b2bfd57a9277ee83381 "requires": { "fsevents": "~2.1.2" } diff --git a/package.json b/package.json index 81c50d075..a968d9ad7 100644 --- a/package.json +++ b/package.json @@ -23,12 +23,8 @@ "@types/backbone": "^1.4.1", "@types/jquery": "^3.3.31", "async": "^3.1.1", -<<<<<<< HEAD - "babel-plugin-transform-amd-to-es6": "^0.3.0", - "babel-plugin-transform-react-templates": "^0.1.0", -======= "babel-plugin-transform-amd-to-es6": "^0.4.0", ->>>>>>> e91e8911ad36a49389327b2bfd57a9277ee83381 + "babel-plugin-transform-react-templates": "^0.1.0", "chalk": "^2.4.1", "columnify": "^1.5.4", "csv": "^5.0.0", From 637ead82f77cf01eb5bff6e92686e136985303ab Mon Sep 17 00:00:00 2001 From: Oliver Foster Date: Mon, 18 Jan 2021 12:42:17 +0000 Subject: [PATCH 5/6] issue/2824-react Formatting --- src/core/js/views/adaptView.js | 2 -- src/core/templates/partials/component.jsx | 7 ++++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/core/js/views/adaptView.js b/src/core/js/views/adaptView.js index 32fd970f2..d33d80b0b 100644 --- a/src/core/js/views/adaptView.js +++ b/src/core/js/views/adaptView.js @@ -82,7 +82,6 @@ class AdaptView extends Backbone.View { return; } const element = render(this.constructor.template.replace('.jsx', ''), this.model, this); - // eslint-disable-next-line no-undef ReactDOM.render(element, this.el); } @@ -318,7 +317,6 @@ class AdaptView extends Backbone.View { Adapt.wait.for(end => { if (this.isReact) { - // eslint-disable-next-line no-undef ReactDOM.unmountComponentAtNode(this.el); } this.$el.off('onscreen.adaptView'); diff --git a/src/core/templates/partials/component.jsx b/src/core/templates/partials/component.jsx index 673351597..c89ef1dc7 100644 --- a/src/core/templates/partials/component.jsx +++ b/src/core/templates/partials/component.jsx @@ -1,5 +1,10 @@ import Adapt from 'core/js/adapt'; -import { compile, classes, helper, html } from 'core/js/reactHelpers'; +import { + compile, + classes, + helper, + html +} from 'core/js/reactHelpers'; export default function(model, view) { const data = model.toJSON(); From aa238580ca75d4d6bde2249049e65d5d637e4f9e Mon Sep 17 00:00:00 2001 From: tomgreenfield Date: Tue, 2 Mar 2021 11:06:11 +0000 Subject: [PATCH 6/6] issue/3050 Update view properties on model change --- .eslintrc.json | 2 +- src/core/js/views/adaptView.js | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/.eslintrc.json b/.eslintrc.json index 1d4c694f8..c431511c0 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -2,7 +2,7 @@ "env": { "browser": true, "commonjs": false, - "es6": false, + "es2020": true, "amd": true }, "extends": [ diff --git a/src/core/js/views/adaptView.js b/src/core/js/views/adaptView.js index d33d80b0b..ae77f165e 100644 --- a/src/core/js/views/adaptView.js +++ b/src/core/js/views/adaptView.js @@ -18,6 +18,7 @@ class AdaptView extends Backbone.View { }); this.isReact = (this.constructor.template || '').includes('.jsx'); if (this.isReact) { + this._classSet = new Set(_.result(this, 'className').trim().split(/\s+/)); this.listenTo(this.model, 'all', this.changed); // Facilitate adaptive react views this.listenTo(Adapt, 'device:changed', this.changed); @@ -82,9 +83,19 @@ class AdaptView extends Backbone.View { return; } const element = render(this.constructor.template.replace('.jsx', ''), this.model, this); + this.updateViewProperties(); ReactDOM.render(element, this.el); } + updateViewProperties() { + const classesToAdd = _.result(this, 'className').trim().split(/\s+/); + classesToAdd.forEach(i => this._classSet.add(i)); + const classesToRemove = [ ...this._classSet ].filter(i => !classesToAdd.includes(i)); + classesToRemove.forEach(i => this._classSet.delete(i)); + this._setAttributes({ ..._.result(this, 'attributes'), id: _.result(this, 'id') }); + this.$el.removeClass(classesToRemove).addClass(classesToAdd); + } + setupOnScreenHandler() { const onscreen = this.model.get('_onScreen');