Custom Components - CMUCTAT/CTAT GitHub Wiki

How to build a custom CTAT component

This is a guide for creating a new CTAT component based on the architecture of CTAT 4.0.0 or later. This guide is meant for authors who are familiar with creating CTAT tutors as outlined elsewhere in this wiki and are comfortable writing JavaScript, CSS, and HTML5.

Preliminaries

It will probably be best to start with a basic CTAT html tutor as outlined in the Quick Start guide. Alternatively, using one of our templates or examples as a base will provide a nice starting point.

Here is a minimal template with some comments about where to hook in your code:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>My CTAT Component</title>
<link rel="stylesheet" href="https://cdn.ctat.cs.cmu.edu/releases/current/CTAT.css"/>
<link rel="stylesheet" href="css/ctat_example.css"/>
<script src="https://cdn.ctat.cs.cmu.edu/releases/current/jquery.min.js"></script>
<script src="https://cdn.ctat.cs.cmu.edu/releases/current/ctat.min.js"></script>
<!-- Add script tag pointing to your custom component code here -->
<!-- For example: <script src="js/MyComponent.js"></script> -->
<script src="https://cdn.ctat.cs.cmu.edu/releases/current/ctatloader.js"></script>
<script>
function ctatOnload() {
      initTutor({"question_file":'MyBehaviorGraph.brd'});
};
</script>
</head>
<body>
    <!-- Put your tutor here -->
    <!-- An instance of your custom component should be a div
         with a class attribute that includes the name of
         your custom component with the prefix "CTAT" -->
    <!-- For example: <div class="CTATNewComponent"></div> -->
</body>
</html>

Here is a basic outline of the JavaScript that can be used as a base for your custom component.

/**
 * My custom component
 */
var CustomComponent = function() {
    CTAT.Component.Base.Tutorable.call(this, "CTATNewComponent", "myComponent");  // 2nd argument is class name

    /**
     * This function is called when CTAT initialized the tutor.
     * Its should initialize the component and add any entities or
     * custom event handlers needed to construct and use the component.
     */
    this.init = function() {
	var div = this.getDivWrap();
	// if there are any attributes to check, here is a good place to
	// check them.

	// construct your component here
	// For example, this is where we add the textarea to the div
	// for CTATTextArea.
	this.setComponent(div); // this should be the div used to define the
	// component in the interface or the entity added to make the
	// component. This decision often depends on if only a single entity
	// is added and it is a form like entity that responds to the
	// "disabled" attribute.

	// finish any initialization here.
	this.setInitialized(true);
	this.addComponentReference(this, div);
    };

    /**
     * This function is required to get a CTATSubmitButton to work
     * with your custom compontent.
     */
    this.updateSAI = function() {
	// you will replace 'Action' and 'Input' with the action
	// and input that will be sent to the tutor.
	this.setActionInput('Action','Input');
    };

    /**
     * 'Action': There needs to be a function with the same name
     * as any of the actions that the component emits. Each of
     * these functions should update the state of the component
     * to as if the action with the given input was just performed.
     * For example in CTATTextInput, it has the action "setText" which
     * has an input of a text string. Its "setText" method updates
     * the text in the input entity that was inserted in init.
     * @param Input - this function should be able to process the
     *  inputs that are emitted with the action
     */
    this.action = function(input) {
	// perform action with input
    };

    // Add additional code such as event listeners that get the component to
    // work.

    /**
     * my_event_listener: some student action
     * Every gradable action should update the current SAI by calling
     * <instance>.setActionInput('Action',input); and
     * <instance>.processAction();
     */
    
};

// Set up inheritance.
CustomComponent.prototype = Object.create(CTAT.Component.Base.Tutorable.prototype);
CustomComponent.prototype.constructor = CustomComponent;

// Register the component: the first argument is the string used in the
// class attribute of the div to indicate the type of component, the
// second argument is the function defined above.
CTAT.ComponentRegistry.addComponentType('CustomComponent', CustomComponent);

Writing a custom component

Your custom component should inherit from CTAT.Component.Base.Tutorable in most cases. Inheriting from it will provide most of the basic functionality for interfacing with the rest of the CTAT component architecture.

The first step will be to add code to init that generates your component within the div that authors add to their interface. You will also want to generate methods for each of the Actions that students or the tutor can perform on the component. These methods should modify the component based on the input provided.

The next step will to add event listeners and configuration actions that emit these Actions. In an event listener, the current SAI (Selection-Action-Input) should be updated using methods such as setActionInput(action,input) followed by a call to processAction() which will submit the action to the tutor. Note, the Selection is automatically updated based on the id attribute of the <div>.

In order for a CTATSubmitButton to work with your component, updateSAI() should be defined and it should update the current SAI using setActionInput(action,input).

Styling Components

Much of the look and feel of the components is handled with CSS, including how grading looks. In general, when a component is graded, one of the following classes is added to the entity set with setComponent(...) in init(): CTAT--correct, CTAT--incorrect, or CTAT--hint. By default, these classes adds a halo effect to the component which is either green, red, or yellow. For some components, this may need to be overwritten to look better, for example, for CTATCheckBox, label.CTAT--correct { box-shadow:none; text-shadow: 0px 0px 5px limegreen; } was added to remove the halo and turn the text green instead.

⚠️ **GitHub.com Fallback** ⚠️