Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions example.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@
"_debugFile": ""
}

// course.json - _globals._extensions
"_devtools": {
"_navButton": {
"ariaLabel": "Developer tools",
"_navOrder": 9000,
"_showLabel": true,
"navLabel": "Dev Tools"
},
"_navTooltip": {
"_isEnabled": true,
"text": "Developer tools"
}
}

/*
_debugFile example (e.g. dev.json)

Expand Down
83 changes: 52 additions & 31 deletions js/adapt-devtools.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import wait from 'core/js/wait';
import logging from 'core/js/logging';
import location from 'core/js/location';
import AdaptModel from 'core/js/models/adaptModel';
import NavigationButtonModel from 'core/js/models/NavigationButtonModel';
import NavigationButtonView from 'core/js/views/NavigationButtonView';
import navigation from 'core/js/navigation';
import tooltips from 'core/js/tooltips';
import DevtoolsModel from './devtools-model';
import PassHalfFail from './pass-half-fail';
import ToggleBanking from './toggle-banking';
Expand Down Expand Up @@ -377,44 +381,37 @@ class DevtoolsView extends Backbone.View {
}
}

class DevtoolsNavigationView extends Backbone.View {
class DevtoolsNavigationButtonView extends NavigationButtonView {

initialize () {
this.render = this.render.bind(this);
const template = Handlebars.templates.devtoolsNavigation;
this.$el = $(template());
$('html').addClass('devtools-enabled').toggleClass('devtools-extended', Adapt.devtools.get('_extended'));
if (this.$el.is('a') || this.$el.is('button')) this.$el.on('click', this.onDevtoolsClicked.bind(this));
else this.$el.find('a, button').on('click', this.onDevtoolsClicked.bind(this));
this.listenTo(Adapt, 'pageView:postRender menuView:postRender', this.onContentRendered);
// ensure render occurs at least once (_isReady will not change to true on menus that exclude content objects)
this.listenToOnce(Adapt, 'pageView:postRender menuView:postRender', this.render);
}

render () {
$('.nav__inner').append(this.$el);
return this;
events () {
return {
click: 'onDevtoolsClicked'
};
}

remove () {
this.$el.remove();
this.stopListening();
return this;
static get template() {
return 'devtoolsNavigationButton.jsx';
}

deferredRender () {
_.defer(this.render);
attributes () {
return {
...super.attributes(),
'data-tooltip-id': this.model.get('_id'),
'aria-haspopup': 'dialog'
};
}

onContentRendered (view) {
if (view.model.get('_id') === location._currentId) {
this.stopListening(view.model, 'change:_isReady', this.deferredRender);
this.listenToOnce(view.model, 'change:_isReady', this.deferredRender);
}
initialize (options) {
super.initialize(options);
this.listenTo(Adapt, { remove: this.remove });
tooltips.register({
_id: this.model.get('_id'),
...this.model.get('_navTooltip') || {}
});
}

onDevtoolsClicked (event) {
if (event && event.preventDefault) event.preventDefault();
event.preventDefault();
drawer.openCustomView(new DevtoolsView().$el, false);
}

Expand All @@ -426,13 +423,37 @@ Adapt.once('courseModel:dataLoaded', () => {

function initNavigationView() {
if (!Adapt.devtools.get('_isEnabled')) return;
if (navigationView) navigationView.remove();
navigationView = new DevtoolsNavigationView();
if (navigationView) navigation.removeButton(navigationView);
$('html').addClass('devtools-enabled').toggleClass('devtools-extended', Adapt.devtools.get('_extended'));
const devtoolsGlobals = Adapt.course.get('_globals')?._extensions?._devtools ?? {};
const {
ariaLabel = 'Developer tools',
_navOrder = 9000,
_showLabel = true,
navLabel = 'Dev Tools'
} = devtoolsGlobals._navButton ?? {};
const { _navTooltip = {} } = devtoolsGlobals;
const model = new NavigationButtonModel({
_id: 'devtools',
_order: _navOrder,
_showLabel,
_classes: 'nav__devtools-btn devtools__nav-btn',
_iconClasses: 'icon-cog',
_role: 'button',
ariaLabel: ariaLabel || navLabel,
text: navLabel,
_navTooltip
});
navigationView = new DevtoolsNavigationButtonView({ model });
navigation.addButton(navigationView);
}

Adapt.once('adapt:initialize devtools:enable', () => {
Adapt.on({
'router:contentObject': initNavigationView,
'app:languageChanged': initNavigationView
});
initNavigationView();
Adapt.on('app:languageChanged', initNavigationView);
});

data.on('loaded', async () => {
Expand Down
6 changes: 0 additions & 6 deletions less/devtools.less
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
.devtools {
// Nav icons
// --------------------------------------------------
&__nav-btn .icon {
.icon-cog;
}

// Items
// --------------------------------------------------
&__item {
Expand Down
36 changes: 18 additions & 18 deletions properties.schema
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
{
"type":"object",
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"id": "http://jsonschema.net",
"required":false,
"properties":{
"required": false,
"properties": {
"pluginLocations": {
"type":"object",
"required":true,
"properties":{
"type": "object",
"required": true,
"properties": {
"config": {
"type":"object",
"type": "object",
"properties": {
"_devtools": {
"type":"object",
"required":false,
"type": "object",
"required": false,
"legend": "Dev tools",
"properties":{
"properties": {
"_isEnabled": {
"type":"boolean",
"required":false,
"type": "boolean",
"required": false,
"title": "Show dev tools in nav bar",
"inputType": { "type": "Boolean", "options": [false, true]},
"inputType": { "type": "Boolean", "options": [false, true] },
"validators": [],
"help": "Set to true to show 'dev tools' in the navigation bar. Remember to disable/uninstall before going live!"
}
Expand All @@ -29,19 +29,19 @@
}
},
"course": {
"type":"object"
"type": "object"
},
"contentobject": {
"type":"object"
"type": "object"
},
"article": {
"type":"object"
"type": "object"
},
"block": {
"type":"object"
"type": "object"
},
"component": {
"type":"object"
"type": "object"
}
}
}
Expand Down
87 changes: 87 additions & 0 deletions schema/course.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
{
"$anchor": "devtools-course",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"$patch": {
"source": {
"$ref": "course"
},
"with": {
"properties": {
"_globals": {
"type": "object",
"default": {},
"properties": {
"_extensions": {
"type": "object",
"default": {},
"properties": {
"_devtools": {
"type": "object",
"title": "Dev Tools",
"default": {},
"properties": {
"_navButton": {
"type": "object",
"title": "Navigation button",
"default": {},
"properties": {
"ariaLabel": {
"type": "string",
"title": "Navigation button aria label",
"default": "Developer tools",
"_adapt": {
"translatable": true
}
},
"_navOrder": {
"type": "number",
"title": "Navigation bar order",
"description": "Determines the order in which the button is displayed in the navigation bar. Negative numbers (e.g. -100) are left-aligned. Positive numbers (e.g. 100) are right-aligned.",
"default": 9000
},
"_showLabel": {
"type": "boolean",
"title": "Enable navigation bar button label",
"default": true
},
"navLabel": {
"type": "string",
"title": "Navigation bar button label",
"default": "Dev Tools",
"_adapt": {
"translatable": true
}
}
}
},
"_navTooltip": {
"type": "object",
"title": "Navigation tooltip",
"default": {},
"properties": {
"_isEnabled": {
"type": "boolean",
"title": "Enable tooltip for navigation button",
"default": true
},
"text": {
"type": "string",
"title": "Tooltip text",
"default": "Developer tools",
"_adapt": {
"translatable": true
}
}
}
}
}
}
}
}
}
}
}
}
}
}
3 changes: 0 additions & 3 deletions templates/devtoolsNavigation.hbs

This file was deleted.

26 changes: 26 additions & 0 deletions templates/devtoolsNavigationButton.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react';
import { classes, compile } from 'core/js/reactHelpers';

export default function DevtoolsNavigationButton(props) {
const {
text,
_iconClasses
} = props;

return (
<>
<span
className={classes([
'icon',
_iconClasses
])}
aria-hidden="true"
/>
<span
className="nav__btn-label"
aria-hidden="true"
dangerouslySetInnerHTML={{ __html: compile(text, props) }}
/>
</>
);
}