Last active
May 12, 2021 22:12
-
-
Save robert-carroll/12717270d15c885f2908371e7bfab838 to your computer and use it in GitHub Desktop.
CanvasLMS module mashup - incomplete
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
odd behvior on student view of modules | |
expand/collapse button: | |
expand collapse works as expected | |
-- but save state of student view doesn't seem to hold on refresh sometimes? | |
-- on page load, clicking the collapse button collapses, and on refresh the state of each module is collapsed | |
-- but expanding, and refreshing does not result in open modules... am I clicking the right selectors for the POST? | |
-- if we start the page with some modules expanded, and some collapsed, the toolbar button indicates all are expanded | |
, must check the count and set the state | |
-- toggle states aren't working correctly. | |
-- what if we need to detect the change on load... ie the state is being edited with ajax or onload. | |
*/ | |
const mm = { | |
toolbar: controls => { | |
var filters = controls.filters.map(f => `<li><button class="btn filter active" id="${f['id']}" aria-pressed="true" title="${f['label']}"><i class="${f['icon']}"></i></button></li>`).join(' '), | |
divider = `<li class="separator"></li>`, | |
toggles = controls.toggles.map(f => `<li><button class="btn toggle active" id="${f['id']}" aria-pressed="true" title="${f['label']}"><i class="${f['icon']}"></i></button></li>`).join(' '), | |
html = `<div><ul id="module_filters">${filters+divider+toggles}</ul></div>` | |
// document.getElementById('module_filters').remove(); | |
document.querySelector('div.header-bar').insertAdjacentHTML('beforeend', html) | |
}, | |
filters: () => { | |
return document.querySelectorAll('#module_filters button.filter'); | |
}, | |
toggles: () => { | |
return document.querySelectorAll('#module_filters button.toggle'); | |
}, | |
lyons: { | |
toggle: (btn, state) => { | |
console.log(state) | |
// if a state is not specified, we'll switch it by default | |
state = state || btn.getAttribute('aria-pressed') == 'true' ? 'false' : 'true' | |
btn.setAttribute('aria-pressed', state) | |
if (btn.getAttribute('aria-pressed') == 'true') { | |
btn.classList.add('active') | |
} else if (btn.classList.contains('active')) { | |
btn.classList.remove('active') | |
} | |
// if (state == 'true') { | |
// btn.classList.add('active') | |
// } else { | |
// btn.classList.remove('active') | |
// } | |
// let flip = btn.getAttribute('aria-pressed') == 'true' ? 'false' : 'true'; | |
// btn.setAttribute('aria-pressed', flip) | |
// if (btn.getAttribute('aria-pressed') == 'true') { | |
// btn.classList.add('active') | |
// } else if (btn.classList.contains('active')) { | |
// btn.classList.remove('active') | |
// }, | |
}, | |
hide: items => { | |
console.log('hide') | |
items.forEach(item => { | |
item.classList.add('module_filters_hide') | |
}) | |
}, | |
show: items => { | |
console.log('show') | |
items.forEach(item => { | |
item.classList.remove('module_filters_hide') | |
}) | |
}, | |
}, | |
cowan: { | |
callback: () => { | |
console.log('cowan: callback') | |
switch (mm.cowan.button.state) { | |
case 'true': | |
mm.cowan.collapse([]) | |
break; | |
case 'false': | |
mm.cowan.expand([]) | |
break; | |
} | |
}, | |
modules: { | |
get state() { | |
// if any modules are collapsed return collapsed | |
let collapsed_count = document.querySelectorAll('#context_modules .collapsed_module') | |
if (collapsed_count.length >= 1) { | |
return 'collapsed' | |
} else { | |
return 'expanded' | |
} | |
}, | |
set state(s) { | |
console.log('match module states') | |
if(s == 'collapsed') { | |
mm.cowan.button.state = 'collapse' | |
} else if(s == 'expanded') { | |
mm.cowan.button.state = 'expand' | |
} | |
} | |
}, | |
click: targets => { | |
targets.forEach(i => i.click()) | |
}, | |
collapse: items => { | |
console.log('collapse') | |
var collapse_btns = document.querySelectorAll('#context_modules span.collapse_module_link'); | |
mm.cowan.click(collapse_btns) | |
mm.cowan.button.state = 'collapse' | |
// if collapse is clicked, and all items are collapsed, set the filter buttons to inactive | |
// toggle buttons off | |
mm.filters().forEach(off => { | |
off.setAttribute('aria-pressed', 'false') | |
off.classList.remove('active') | |
}) | |
}, | |
expand: items => { | |
console.log('expand') | |
// on expand/collapse reset, we need to unhide anything that's hidden | |
document.querySelectorAll('.module_filters_hide').forEach(item => { | |
item.classList.remove('module_filters_hide') | |
}) | |
// all these expand the modules when clicked or .clicked(), none of them save, even though the POST is successful | |
//var expand_btns = document.querySelectorAll('#context_modules .collapsed_module span.collapse_module_link'); | |
//var expand_btns = document.querySelectorAll(`#context_modules .expand_module_link:not([style='display: none;'])`); | |
//var expand_btns = document.querySelectorAll(`#context_modules .expand_module_link[aria-expanded="false"`); | |
var expand_btns = document.querySelectorAll('#context_modules span.expand_module_link') | |
mm.cowan.click(expand_btns) | |
mm.cowan.button.state = 'expand' | |
// also need to reset the filter buttons to active | |
mm.filters().forEach(on => { | |
on.setAttribute('aria-pressed', 'true') | |
on.classList.add('active') | |
}) | |
}, | |
button: { | |
get state() { | |
return document.getElementById('expand_collapse').getAttribute('aria-pressed') | |
}, | |
set state(s) { | |
// set button state | |
switch(s) { | |
case 'expand': | |
document.getElementById('expand_collapse').classList.add('active') | |
document.getElementById('expand_collapse').setAttribute('aria-pressed', 'true') | |
document.getElementById('expand_collapse').setAttribute('title', 'Collapse All Modules') | |
mm.filters().forEach(btn => mm.lyons.toggle(btn), 'true') | |
break; | |
case 'collapse': | |
document.getElementById('expand_collapse').classList.remove('active') | |
document.getElementById('expand_collapse').setAttribute('aria-pressed', 'false') | |
document.getElementById('expand_collapse').setAttribute('title', 'Expand All Modules') | |
mm.filters().forEach(btn => mm.lyons.toggle(btn), 'false') | |
break; | |
} | |
} | |
} | |
} | |
} | |
var controls = { | |
filters: [ | |
{ id: 'wiki_page', label: 'Pages', icon: 'icon-document' }, | |
{ id: 'assignment', label: 'Assignments', icon: 'icon-assignment' }, | |
{ id: 'quiz', label: 'Quizzes', icon: 'icon-quiz' }, | |
{ id: 'discussion_topic', label: 'Discussion Topics', icon: 'icon-discussion' }, | |
{ id: 'external_url', label: 'Links', icon: 'icon-link' }, | |
{ id: 'attachment', label: 'Files', icon: 'icon-paperclip' }, | |
{ id: 'context_external_tool', label: 'External Tools', icon: 'icon-integrations' }, | |
{ id: 'completed_item', label: 'Completed Items', icon: 'icon-check' }, | |
{ id: '_requirement', label: 'Prerequisites', icon: 'icon-prerequisite' }, | |
], | |
toggles: [ | |
{ id: 'expand_collapse', label: 'Collapse All Modules', icon: 'icon-collapse', callback: mm.cowan.callback }, | |
{ id: 'module_progress', label: 'Module Progress', icon: 'icon-complete', callback: mp } | |
] | |
}; | |
// toolbar html | |
mm.toolbar(controls) | |
mm.filters().forEach(btn => { | |
console.log('filters: init') | |
// double click, toggle filter | |
btn.addEventListener('click', function (e) { | |
var is_pressed = btn.getAttribute('aria-pressed') | |
//console.log(`${e.type} - ${btn.id}: ${is_pressed}`) | |
// toggle state | |
switch (is_pressed) { | |
case 'true': | |
mm.lyons.hide(document.querySelectorAll(`li.${btn.id}`)) | |
// student view sees .lti-quiz | |
if (btn.id == 'quiz') { | |
mm.lyons.hide(document.querySelectorAll(`li.lti-${btn.id}`)) | |
} | |
mm.lyons.toggle(btn, 'true') | |
break; | |
case 'false': | |
mm.lyons.show(document.querySelectorAll(`li.${btn.id}`)) | |
// student view sees .lti-quiz | |
if (btn.id == 'quiz') { | |
mm.lyons.show(document.querySelectorAll(`li.lti-${btn.id}`)) | |
} | |
mm.lyons.toggle(btn, 'false') | |
break; | |
} | |
// switch the state of the expand/collapse button | |
// if any filters are active, show the collapse button | |
var active = document.querySelectorAll('#module_filters button[aria-pressed="false"]') | |
if (active.length > 0 && document.getElementById('expand_collapse')) { | |
mm.cowan.button.state = 'collapse' | |
} | |
// if a filter item is clicked, that we expand all modules with that content type for visibility | |
var modules_collapsed_with_filtered_content = document.querySelectorAll(`#context_modules .collapsed_module li[id^="context_module_item_"].${btn.id}`) | |
if (modules_collapsed_with_filtered_content.length > 0) { | |
for (let i = 0; i < modules_collapsed_with_filtered_content.length; i++) { | |
var module_id = modules_collapsed_with_filtered_content[i].parentNode.parentNode.parentNode.getAttribute('data-module-id') | |
document.querySelector(`.expand_module_link[aria-controls="context_module_content_${module_id}"]`).click() | |
} | |
} | |
}); | |
// double click toggle, disable all filters and enable clicked filter | |
btn.addEventListener('dblclick', function (e) { | |
console.log(`${e.type} - ${btn.id}`) | |
// can't do 2 things here, need to know what the state of the button is and do the right action | |
console.log(btn.getAttribute('aria-pressed')) | |
// toggle buttons off | |
mm.filters().forEach(off => { | |
off.setAttribute('aria-pressed', 'false') | |
off.classList.remove('active') | |
}) | |
// wish this would work | |
// var hide_leg = Array.from(document.querySelectorAll(`li[id^="context_module_item_"]:not(.${btn.id})`)) | |
// var hide_lti = Array.from(document.querySelectorAll(`li[id^="context_module_item_"]:not(.lti-${btn.id})`)) | |
// // what to hide | |
// const hide_items = [...new Set(hide_leg.concat(hide_lti).map(item => item.id))]; | |
// mm.lyons.hide(hide_items) | |
// var show_leg = Array.from(document.querySelectorAll(`li.${btn.id}.module_filters_hide`)) | |
// var show_lti = Array.from(document.querySelectorAll(`li[id^="context_module_item_"]:not(.lti-${btn.id})`)) | |
// // what to hide | |
// const show_items = [...new Set(show_leg.concat(show_lti).map(item => item.id))]; | |
// mm.lyons.show(show_items) | |
// items to hide | |
mm.lyons.hide(document.querySelectorAll(`li[id^="context_module_item_"]:not(.${btn.id})`)) | |
// student view sees .lti-quiz too | |
if (btn.id == 'quiz') { | |
mm.lyons.hide(document.querySelectorAll(`li[id^="context_module_item_"]:not(.lti-${btn.id})`)) | |
} | |
// items to show | |
mm.lyons.show(document.querySelectorAll(`li.${btn.id}.module_filters_hide`)) | |
// student view sees .lti-quiz too | |
if (btn.id == 'quiz') { | |
mm.lyons.show(document.querySelectorAll(`li.lti-${btn.id}.module_filters_hide`)) | |
} | |
// active button | |
btn.classList.add('active') | |
btn.setAttribute('aria-pressed', 'true') | |
}); | |
}) | |
function mp(btn) { | |
console.log('mp') | |
console.log(btn.getAttribute('aria-pressed')) | |
} | |
function cb(callback, btn) { | |
callback(btn) | |
} | |
mm.toggles().forEach(btn => { | |
console.log('filters: toggles') | |
btn.addEventListener('click', e => { | |
cb(controls.toggles.filter(t => t.id == btn.id)[0].callback, btn) | |
}); | |
}); | |
//} | |
// physical click collapse | |
// collapse=1&_method=POST | |
// physical click expand | |
// collapse=0&_method=POST | |
// when the tool bar is loaded with collapsed modules | |
// // expand button | |
// collapse=1&_method=POST | |
// // collapse button | |
// collapse=0&_method=POST | |
// ?? test and update the filters and toggles if the page loads collapsed | |
// this matches the button state with the modules state (any closed module) | |
// mm.cowan.modules.state = mm.cowan.modules.state |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#module_filters { | |
list-style-type: none; | |
display: inline; | |
margin: 0; | |
} | |
#module_filters li { | |
padding: 0 .5em 0 0; | |
display: inline-block; | |
} | |
#module_filters li.separator::after { | |
content: " "; | |
border-left: 1px dashed grey; | |
padding: -1px; | |
} | |
#module_filters button { | |
background: none; | |
border: none; | |
border-color: transparent; | |
box-shadow: none; | |
margin: 0; | |
outline-style: none; | |
padding: 0 0 4px 0; | |
} | |
#module_filters button.active { | |
color: #00AC18; | |
} | |
.module_filters_hide { | |
display: none; | |
}#module_filters { | |
list-style-type: none; | |
display: inline; | |
margin: 0; | |
} | |
#module_filters li { | |
padding: 0 .5em 0 0; | |
display: inline-block; | |
} | |
#module_filters li.separator::after { | |
content: " "; | |
border-left: 1px dashed grey; | |
padding: -1px; | |
} | |
#module_filters button { | |
background: none; | |
border: none; | |
border-color: transparent; | |
box-shadow: none; | |
margin: 0; | |
outline-style: none; | |
padding: 0 0 4px 0; | |
} | |
#module_filters button.active { | |
color: #00AC18; | |
} | |
.module_filters_hide { | |
display: none; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment