Your Community is getting an upgrade!
Read about our partnership with Higher Logic and how we will build the next generation of the Instructure Community.
Found this content helpful? Log in or sign up to leave a like!
Hi Developers,
The July 17 deploy changed the UI for the publish/unpublish options on a course home page and in course settings to a dropdown box. I'm looking for a way to disable the "unpublish" option with this new UI. I had code working for the old UI, but I'm having trouble figuring out how to do this with the new one. We want teachers to be able to publish (so we can't lock this out with permissions), but we don't want them to be able to unpublish a course that's already been published. Do any of you experts in here see a way to accomplish this with the new/current UI? I'd appreciate any assistance I can get!
-Chris
Solved! Go to Solution.
You can try the following. It will look for the course status button wrapper. If it is found, then it will watch for the published icon to show as the selected state. Once the published icon is found as the selected state, it will replace the button with a modified version of the button content that no longer triggers the menu to change the course state.
(function () {
"use strict";
if (
/\/courses\/[0-9]+\/?$/.test(window.location.pathname) ||
/\/courses\/[0-9]+\/(settings|details)\/?$/.test(window.location.pathname)
) {
watchForCoursePublishButtonWrapper();
}
function watchForCoursePublishButtonWrapper() {
const cssSelector = `#course_publish_button`;
watchForAddedElement(cssSelector, watchForPublishedState);
}
function watchForAddedElement(
cssSelector,
handlerFunction,
elementToObserve = document.body,
options = { childList: true, subtree: true },
shouldContinueObservingWhenFound = false
) {
const element = elementToObserve?.querySelector(cssSelector);
if (element) {
handlerFunction(element);
if (!shouldContinueObservingWhenFound) {
return;
}
}
const observer = new MutationObserver((mutations) => {
if (
!mutations.some((mutation) => mutation?.addedNodes?.length ?? 0 > 0)
) {
return;
}
const foundElement = elementToObserve?.querySelector(cssSelector);
if (foundElement) {
handlerFunction(foundElement);
if (!shouldContinueObservingWhenFound) {
observer.disconnect();
}
}
});
observer.observe(elementToObserve, options);
}
function watchForPublishedState(buttonWrapper) {
const cssSelector = `svg[name=IconPublish]`;
watchForAddedElement(
cssSelector,
() => replacePublishButton(buttonWrapper),
buttonWrapper
);
}
function replacePublishButton(buttonWrapper) {
console.log("replace publish");
const button = buttonWrapper.querySelector("button");
const buttonContent = buttonWrapper?.querySelector("button > span");
if (button && buttonContent) {
// Remove drop-down arrow
const arrowSvg = buttonContent?.querySelector("svg[name^=IconArrow]");
arrowSvg?.remove();
// Cloning to remove event listeners
const clonedButtonContent = buttonContent.cloneNode(true);
// Adjusting justify content style to keep left-aligned
const childrenLayoutWrapper = clonedButtonContent?.querySelector(
":scope > span[class$=childrenLayout]"
);
if (childrenLayoutWrapper) {
childrenLayoutWrapper.style.justifyContent = "left";
}
// Replace the current button with the cloned and updated button content
button.replaceWith(clonedButtonContent);
}
}
})();
You can try the following. It will look for the course status button wrapper. If it is found, then it will watch for the published icon to show as the selected state. Once the published icon is found as the selected state, it will replace the button with a modified version of the button content that no longer triggers the menu to change the course state.
(function () {
"use strict";
if (
/\/courses\/[0-9]+\/?$/.test(window.location.pathname) ||
/\/courses\/[0-9]+\/(settings|details)\/?$/.test(window.location.pathname)
) {
watchForCoursePublishButtonWrapper();
}
function watchForCoursePublishButtonWrapper() {
const cssSelector = `#course_publish_button`;
watchForAddedElement(cssSelector, watchForPublishedState);
}
function watchForAddedElement(
cssSelector,
handlerFunction,
elementToObserve = document.body,
options = { childList: true, subtree: true },
shouldContinueObservingWhenFound = false
) {
const element = elementToObserve?.querySelector(cssSelector);
if (element) {
handlerFunction(element);
if (!shouldContinueObservingWhenFound) {
return;
}
}
const observer = new MutationObserver((mutations) => {
if (
!mutations.some((mutation) => mutation?.addedNodes?.length ?? 0 > 0)
) {
return;
}
const foundElement = elementToObserve?.querySelector(cssSelector);
if (foundElement) {
handlerFunction(foundElement);
if (!shouldContinueObservingWhenFound) {
observer.disconnect();
}
}
});
observer.observe(elementToObserve, options);
}
function watchForPublishedState(buttonWrapper) {
const cssSelector = `svg[name=IconPublish]`;
watchForAddedElement(
cssSelector,
() => replacePublishButton(buttonWrapper),
buttonWrapper
);
}
function replacePublishButton(buttonWrapper) {
console.log("replace publish");
const button = buttonWrapper.querySelector("button");
const buttonContent = buttonWrapper?.querySelector("button > span");
if (button && buttonContent) {
// Remove drop-down arrow
const arrowSvg = buttonContent?.querySelector("svg[name^=IconArrow]");
arrowSvg?.remove();
// Cloning to remove event listeners
const clonedButtonContent = buttonContent.cloneNode(true);
// Adjusting justify content style to keep left-aligned
const childrenLayoutWrapper = clonedButtonContent?.querySelector(
":scope > span[class$=childrenLayout]"
);
if (childrenLayoutWrapper) {
childrenLayoutWrapper.style.justifyContent = "left";
}
// Replace the current button with the cloned and updated button content
button.replaceWith(clonedButtonContent);
}
}
})();
Thanks @Code-with-Ski,
This appears to be working beautifully right now! I hope Instructure won't modify that UI element any time soon. I also created a feature idea to separate publish from unpublish in course role permissions. This might be a very unique need for the processes we have in place at my institution, but any extra permission granularity is always a win in my book!
-Chris
I'm glad to hear it is working for you!
I agree that more granular permissions would be really helpful. As the UI is being updated to use more React components it is becoming more challenging to create theme modifications hide/modify native components.
To interact with Panda Bot, our automated chatbot, you need to sign up or log in:
Sign InTo interact with Panda Bot, our automated chatbot, you need to sign up or log in:
Sign In