diff --git a/.prettierignore b/.prettierignore
index 7ff383e36..57bd1ea7b 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -1,3 +1,4 @@
*.md
**/build/*
docs/web/static/python_api/*
+wrap_crowd_source.js
\ No newline at end of file
diff --git a/mephisto/abstractions/blueprints/static_html_task/source/dev/app.jsx b/mephisto/abstractions/blueprints/static_html_task/source/dev/app.jsx
index f6acd4cb9..64a65630b 100644
--- a/mephisto/abstractions/blueprints/static_html_task/source/dev/app.jsx
+++ b/mephisto/abstractions/blueprints/static_html_task/source/dev/app.jsx
@@ -10,6 +10,7 @@ import React from "react";
import ReactDOM from "react-dom";
import { Button } from "react-bootstrap";
import { useMephistoTask, postData } from "mephisto-task";
+import { useMephistoGlobalConfig } from "./hooks";
const axios = require("axios");
/* global
@@ -110,6 +111,14 @@ function MainApp() {
function SubmitFrame({ children, onSubmit, currentTask }) {
const [submitting, setSubmitting] = React.useState(false);
+ const [
+ isSubmitButtonHidden,
+ setIsSubmitButtonHidden,
+ ] = useMephistoGlobalConfig(
+ "HIDE_SUBMIT_BUTTON",
+ false,
+ (val) => typeof val === "boolean"
+ );
React.useEffect(() => {
// Reset submitting when switching from onboarding
@@ -133,13 +142,20 @@ function SubmitFrame({ children, onSubmit, currentTask }) {
{children}
-
+ {!isSubmitButtonHidden && (
+
+ )}
diff --git a/mephisto/abstractions/blueprints/static_html_task/source/dev/hooks.js b/mephisto/abstractions/blueprints/static_html_task/source/dev/hooks.js
new file mode 100644
index 000000000..ff335a324
--- /dev/null
+++ b/mephisto/abstractions/blueprints/static_html_task/source/dev/hooks.js
@@ -0,0 +1,33 @@
+import { useState, useCallback, useEffect } from "react";
+
+/**
+ * This hook is to be used with events that are supposed to update state when they are consumed.
+ * @param {string} configName
+ * @param {any} defaultValue
+ * @param {function} validatorFunction
+ * @returns [any any]
+ */
+export function useMephistoGlobalConfig(
+ configName,
+ defaultValue,
+ validatorFunction
+) {
+ const [configState, setConfigState] = useState(defaultValue ?? false);
+
+ const handleEvent = useCallback(
+ (eventValue) => {
+ if (validatorFunction) {
+ if (validatorFunction(eventValue)) {
+ setConfigState(eventValue);
+ }
+ } else setConfigState(eventValue);
+ },
+ [setConfigState]
+ );
+
+ useEffect(() => {
+ window._MEPHISTO_CONFIG_.EVENT_EMITTER.on(configName, handleEvent);
+ }, [setConfigState]);
+
+ return [configState, setConfigState];
+}
diff --git a/mephisto/abstractions/providers/mock/wrap_crowd_source.js b/mephisto/abstractions/providers/mock/wrap_crowd_source.js
index 58b978559..3bade928b 100644
--- a/mephisto/abstractions/providers/mock/wrap_crowd_source.js
+++ b/mephisto/abstractions/providers/mock/wrap_crowd_source.js
@@ -15,6 +15,11 @@ Returning None for the assignment_id means that the task is being
previewed by the given worker.
\------------------------------------------*/
+// The following is the nanoevents npm library (https://github.com/ai/nanoevents/blob/main/index.js) manually processed as such:
+// 1. transpiled to support more browser targets using the Babel transpiler (https://babeljs.io/repl#?browsers=defaults&build=&builtIns=false&corejs=false&spec=false&loose=false), and
+// 2. minified using a JS minifier (https://www.toptal.com/developers/javascript-minifier)
+var eventEmitter=function(){return{events:{},emit:function(f){for(var b=this.events[f]||[],c=arguments.length,e=new Array(c>1?c-1:0),a=1;a {
+ if (!(property in window._MEPHISTO_CONFIG_))
+ throw new Error(`${property} does not exist in window.MEPHISTO_CONFIG`);
+ else return window._MEPHISTO_CONFIG_[property];
+};
+
+window._MEPHISTO_CONFIG_.set = (property, value) => {
+ window._MEPHISTO_CONFIG_[property] = value;
+ events.emit(property, value);
+};
+
+/* === UI error handling code ======= */
window._MEPHISTO_CONFIG_.AUTO_SUBMIT_ERRORS = false;
window._MEPHISTO_CONFIG_.ADD_ERROR_HANDLING = false;
window._MEPHISTO_CONFIG_.ERROR_REPORT_TO_EMAIL = null;
diff --git a/mephisto/abstractions/providers/mturk/wrap_crowd_source.js b/mephisto/abstractions/providers/mturk/wrap_crowd_source.js
index ed5dc7355..d953f1cd4 100644
--- a/mephisto/abstractions/providers/mturk/wrap_crowd_source.js
+++ b/mephisto/abstractions/providers/mturk/wrap_crowd_source.js
@@ -15,6 +15,11 @@ Returning None for the assignment_id means that the task is being
previewed by the given worker.
\------------------------------------------*/
+// The following is the nanoevents npm library (https://github.com/ai/nanoevents/blob/main/index.js) manually processed as such:
+// 1. transpiled to support more browser targets using the Babel transpiler (https://babeljs.io/repl#?browsers=defaults&build=&builtIns=false&corejs=false&spec=false&loose=false), and
+// 2. minified using a JS minifier (https://www.toptal.com/developers/javascript-minifier)
+var eventEmitter=function(){return{events:{},emit:function(f){for(var b=this.events[f]||[],c=arguments.length,e=new Array(c>1?c-1:0),a=1;a {
+ if (!(property in window._MEPHISTO_CONFIG_))
+ throw new Error(`${property} does not exist in window.MEPHISTO_CONFIG`);
+ else return window._MEPHISTO_CONFIG_[property];
+};
+
+window._MEPHISTO_CONFIG_.set = (property, value) => {
+ window._MEPHISTO_CONFIG_[property] = value;
+ events.emit(property, value);
+};
+
+/* === UI error handling code ======= */
window._MEPHISTO_CONFIG_.AUTO_SUBMIT_ERRORS = false;
window._MEPHISTO_CONFIG_.ADD_ERROR_HANDLING = false;
window._MEPHISTO_CONFIG_.ERROR_REPORT_TO_EMAIL = null;
@@ -73,6 +91,7 @@ window._MEPHISTO_CONFIG_.ERROR_REPORT_TO_EMAIL = null;
let numErrorsCaught = 0;
let numErrorsReported = 0;
let userDisabledErrorPrompts = false;
+
// Adding event listener instead of using window.onerror prevents the error to be caught twice
window.addEventListener("error", function (event) {
if (event.error.hasBeenCaught === true) {