To Our Amazing Educators Everywhere,
Happy Teacher Appreciation Week!
Found this content helpful? Log in or sign up to leave a like!
We are wanting hide the "Copy To.." option from faculty and non root-admins anywhere it is seen on a kebab (modules, individual content items in the module, pages, quizzes, assignments and discussions).
What JavaScript could I use to do this?
Thank so much in advance!
Solved! Go to Solution.
Mutations will work best.
I have absolutely no idea if this hits every instance of these.
Does not work in c4e.
// https://community.canvaslms.com/t5/Canvas-Developers-Group/JavaScript-to-Hide-quot-Copy-To-quot-in-Kebabs/m-p/586911#M9855
(function () {
'use strict';
// course context
if (!/\/courses\/\d+\/?/.test(window.location.pathname)) return;
// remove option for roles not listed
if (['root_admin', 'consortium_admin'].some(a => ENV.current_user_roles.includes(a))) return;
// be super cool if the dependency chain made this consistent
// selectors for most
var targets = [
'a.direct-share-copy-to-menu-item', // direct share found in most (single use cases) course home, page, discussion, assignment, module
'a.copy_assignment_to', // assignments
'a.copy-wiki-page-to', // pages
'a.module_copy_to', // module group
'a.module_item_copy_to', // module (covers kyle-menu for discussions on /modules)
'a.quiz-copy-to', // quizzes
// files has no specific class, needs decent non-language target, using innerText fails to include someone
// discussions has different structure with spans, no kyle menu... requires separate observer targeting
'a.unset-as-front-page-menu-item', // remove the remove as front page option
'a.use-as-front-page-menu-item', // remove the ability to set another
];
// selectors for discussions
var topic_targets = [
'#copyTo-discussion-menu-option', // copy to for discussions
];
// strings for files
// break accessbility by being language specific
var strings_for_files = [
'Copy To...',
];
var watch_kyle_menus = (_mtx, observer) => {
// watch most kyle menus
let active_kyle_menu = document.querySelector('ul.ui-kyle-menu[aria-expanded="true"]');
// watch discussion_topic content control menus
// only on discussion_topics, but not a discussion_topics/:id
// maintains the kyle menu at the top of discussions - Commons Favorites, would have to account for that if necessary
if (!/\/courses\/\d+\/discussion_topics\/\d+\/?/.test(window.location.pathname)) {
active_kyle_menu = document.querySelector('span[class$="view--inlineBlock-contextView"][data-position-content^="Menu_"]');
}
if (!active_kyle_menu) {
if (typeof observer === 'undefined') {
var obs = new MutationObserver(watch_kyle_menus);
obs.observe(document.body, {
attributes: true,
childList: true,
subtree: true
});
}
return;
}
// class added to menu instance when changes are complete
let complete = [...active_kyle_menu.classList].includes('modified-kyle-menu');
// remove content control options
if (active_kyle_menu && !complete) {
let menu_opts = [];
// only on discussion_topics, but not a discussion_topics/:id
if (!/\/courses\/\d+\/discussion_topics\/\d+\/?/.test(window.location.pathname)) {
// discussion topics
menu_opts = Array.from(document.querySelectorAll(`span[class$="view--inlineBlock-contextView"][data-position-content^="Menu_"] ${topic_targets.join(', ')}`));
} else if (/\/courses\/\d+\/files/.test(window.location.pathname)) {
// files
menu_opts = Array.from(document.querySelectorAll(`ul.ui-kyle-menu[aria-expanded="true"] li a`))
.filter(o => strings_for_files.includes(o.innerText));
} else {
// all others
menu_opts = Array.from(document.querySelectorAll(`ul.ui-kyle-menu[aria-expanded="true"] li ${targets.join(', ')}`));
}
menu_opts.forEach((mo, i, a) => {
mo.closest('li').remove();
// update menu instance with complete class, after last removable item
if (i === a.length - 1 && mo.closest('ul') !== null && !complete) {
mo.closest('ul').classList.add('modified-kyle-menu');
}
});
}
};
watch_kyle_menus();
})();
Mutations will work best.
I have absolutely no idea if this hits every instance of these.
Does not work in c4e.
// https://community.canvaslms.com/t5/Canvas-Developers-Group/JavaScript-to-Hide-quot-Copy-To-quot-in-Kebabs/m-p/586911#M9855
(function () {
'use strict';
// course context
if (!/\/courses\/\d+\/?/.test(window.location.pathname)) return;
// remove option for roles not listed
if (['root_admin', 'consortium_admin'].some(a => ENV.current_user_roles.includes(a))) return;
// be super cool if the dependency chain made this consistent
// selectors for most
var targets = [
'a.direct-share-copy-to-menu-item', // direct share found in most (single use cases) course home, page, discussion, assignment, module
'a.copy_assignment_to', // assignments
'a.copy-wiki-page-to', // pages
'a.module_copy_to', // module group
'a.module_item_copy_to', // module (covers kyle-menu for discussions on /modules)
'a.quiz-copy-to', // quizzes
// files has no specific class, needs decent non-language target, using innerText fails to include someone
// discussions has different structure with spans, no kyle menu... requires separate observer targeting
'a.unset-as-front-page-menu-item', // remove the remove as front page option
'a.use-as-front-page-menu-item', // remove the ability to set another
];
// selectors for discussions
var topic_targets = [
'#copyTo-discussion-menu-option', // copy to for discussions
];
// strings for files
// break accessbility by being language specific
var strings_for_files = [
'Copy To...',
];
var watch_kyle_menus = (_mtx, observer) => {
// watch most kyle menus
let active_kyle_menu = document.querySelector('ul.ui-kyle-menu[aria-expanded="true"]');
// watch discussion_topic content control menus
// only on discussion_topics, but not a discussion_topics/:id
// maintains the kyle menu at the top of discussions - Commons Favorites, would have to account for that if necessary
if (!/\/courses\/\d+\/discussion_topics\/\d+\/?/.test(window.location.pathname)) {
active_kyle_menu = document.querySelector('span[class$="view--inlineBlock-contextView"][data-position-content^="Menu_"]');
}
if (!active_kyle_menu) {
if (typeof observer === 'undefined') {
var obs = new MutationObserver(watch_kyle_menus);
obs.observe(document.body, {
attributes: true,
childList: true,
subtree: true
});
}
return;
}
// class added to menu instance when changes are complete
let complete = [...active_kyle_menu.classList].includes('modified-kyle-menu');
// remove content control options
if (active_kyle_menu && !complete) {
let menu_opts = [];
// only on discussion_topics, but not a discussion_topics/:id
if (!/\/courses\/\d+\/discussion_topics\/\d+\/?/.test(window.location.pathname)) {
// discussion topics
menu_opts = Array.from(document.querySelectorAll(`span[class$="view--inlineBlock-contextView"][data-position-content^="Menu_"] ${topic_targets.join(', ')}`));
} else if (/\/courses\/\d+\/files/.test(window.location.pathname)) {
// files
menu_opts = Array.from(document.querySelectorAll(`ul.ui-kyle-menu[aria-expanded="true"] li a`))
.filter(o => strings_for_files.includes(o.innerText));
} else {
// all others
menu_opts = Array.from(document.querySelectorAll(`ul.ui-kyle-menu[aria-expanded="true"] li ${targets.join(', ')}`));
}
menu_opts.forEach((mo, i, a) => {
mo.closest('li').remove();
// update menu instance with complete class, after last removable item
if (i === a.length - 1 && mo.closest('ul') !== null && !complete) {
mo.closest('ul').classList.add('modified-kyle-menu');
}
});
}
};
watch_kyle_menus();
})();
@robotcars I did see that discussions still have the "Copy to..." option.
Is that what you meant by this comment?
// discussions has different structure with spans, no kyle menu... requires separate observer targeting
Thanks so much!
Yes. I will need a little time to tinker with discussions piece. Did appreciate the challenge on many mutating menus.
Thank you so much for all of your help!!!
Also in the pages area, we want to make it so faculty cannot remove the default page as the Front Page and set another page as the Front Page.
Do you know if the same JavaScript would work for that?
That's included now. Essentially allows any option to be removed now. Discussions still unsupported.
Thank you again so much! This worked great! You are awesome!!!!!
This worked perfectly! Thank you so much!
Discussion Topics is supported on its own route. // discussion_topic/:id uses ui-kyle-menu
As is the overall ability to target any of the options within those menus.
Diligence would be wise in ensuring each instance of these menus is covered and not missed on a page or new feature/view.
Again, thanks for the use case.
To participate in the Instructure Community, you need to sign up or log in:
Sign In