Con este script vamos a realizar un simulacro de examen on-line.
La Planilla
Vamos a tener una planilla de cálculo con 2 hojas, en una vamos a registrar las preguntas y en la otra las respuestas de los alumnos.
La idea es que podamos hacer un examen con todas las preguntas que querramos y registrar las correspondientes respuestas de cada alumno para luego poder validarlas y en tal caso, emitir un reporte con la calificación automática de cada alumno, y hasta inclusive se podría hacer un reporte por cada alumno, realizando las correspondientes correcciones.
Para empezar, creamos la planilla con dos hojas llamadas Cuestionario y Respuestas.
En la hoja Cuestionario indicamos dos columnas: Pregunta y Respuesta y en la hoja Respuesta Fecha de Inicio, Fecha de Fin, Nombre y Respuestas.
Completamos las preguntas con las respuestas en la página correspondiente y listo.
El Script
El script que vamos a crear es del tipo UI (Interfaz de usuario, o sea, una pantalla independiente de la planilla). Creamos un script en la planilla y generamos la primer función doGet que es la que se va a ejecutar cuando accedamos a través de la url generada mas tarde.
En esta función vamos a crear el primer paso, que es identificar el usuario:
function doGet() {
var app = UiApp.createApplication();
var form = app.createFormPanel();
var flow = app.createFlowPanel();
flow.add( app.createHidden().setName("step").setValue( 0 ) );
flow.add( app.createLabel("Ingrese su nombre: ") );
flow.add( app.createTextBox().setName("student") );
flow.add( app.createSubmitButton("Siguiente") );
form.add( flow );
app.add( form );
return app;
}
Como se puede ver, creamos un formulario y dentro de él pusimos 4 elementos, pero sólo nos interesan 3 de ellos:
- el hidden, que es un campo oculto que no se muestra en la interfaz pero lo necesitamos para setear valores de nuestro script.
- el textBox, que es el campo donde el usuario va a escribir su nombre.
- y el submitButton, que es donde el botón que el usuario va a presionar para llamar al la función doPost.
function doPost(eventInfo) {
var app = UiApp.getActiveApplication();
if(eventInfo.parameter.step=="0"){
var st = initTest(eventInfo.parameter.student);
app = updateFields(app, 1, st);
}else{
setAnswer(eventInfo);
app = updateFields(app, Number(eventInfo.parameter.step), eventInfo.parameter.student);
}
return app;
}
En la función doPost lo primero que vamos a hacer es identificar en que paso estamos. Si estamos en el paso 0, tenemos que "registrar" el nuevo examen en la hoja de Respuestas.
Ese paso lo hacemos con la función initTest
function initTest(studentName){
var sheet = SpreadsheetApp.openById(ID_DOC).getSheetByName("Respuestas");
var row = sheet.getLastRow() + 1;
sheet.getRange("A"+row).setValue(new Date());
sheet.getRange("C"+row).setValue(studentName);
return row;
}
En esta función tomamos la última fila con valor y en la siguiente guardamos el nombre del alumno y la fecha actual para tener el registro de cuando se inició el examen. Y devuelvo el número de linea en la cual estoy registrando las respuestas de ese alumno. Esto me permite mantener los exámenes en forma independiente por mas que dos alumnos ingresen el mismo nombre, además es muy optimo, ya que no tengo que buscar al alumno en cada respuesta que ingrese.
Una vez inicializado esto, voy a preparar la pantalla para la primer pregunta llamando a la función updateFields con el parametro step en 1.
function updateFields(app, step, st){
var form = app.createFormPanel();
var flow = app.createFlowPanel();
flow.add( app.createHidden().setName("step").setValue( step+1 ) );
flow.add( app.createHidden().setName("student").setValue( st ) );
flow.add( app.createTextBox().setName("question").setValue( getQuestion( step ) ).setEnabled( false ) );
flow.add( app.createListBox().setName("answer").addItem("Seleccione").addItem("Verdadero").addItem("Falso") );
flow.add( app.createSubmitButton("Siguiente") );
form.add( flow );
app.add( form );
return app;
}
Esta función crea un nuevo formulario con dos campos, uno con la pregunta y otro con la respuesta del alumno. Además hay 2 campos ocultos (hidden), uno con el número de la siguietne pregunta y el otro con el número de linea en la que se almacenan las respuestas del usuario.
Para obtener la pregunta actual utilizo la función getQuestion a la cual debo pasar como parámetro el número de pregunta que quiero obtener, esto lo resuelvo de la siguiente manera:
function getQuestion( step ){
return SpreadsheetApp.openById(ID_DOC).getSheetByName("Cuestionario").getRange("A"+(step+1)).getValue();
}
Una vez que el alumno responde la pregunta, vuelve a presionar el botón de submit (el botón "Siguiente"), con esta acción se vuelve a llamar a la misma función doPost, pero en este caso, el parámetro step ya no será "0" (esta condición se dará únicamente cuando se comience el examen).
Así que, lo que queremos hacer aqui es registrar la respuesta y cargar la pregunta siguiente. Para cargar la pregunta siguiente utilizamos la función analizada anteriormente updateFields. Para registrar la respuesta utilizamos la función setAnswer.
function setAnswer( eventInfo ){
var range = SpreadsheetApp.openById(ID_DOC).getSheetByName("Respuestas").getRange("D"+eventInfo.parameter.student);
range.setValue( range.getValue()+eventInfo.parameter.step+":"+eventInfo.parameter.answer+"," );
}
En esta función lo que se hace es agregar a la lista de respuestas la última respuesta separada por coma.
Queda por resolver la validación de la respuesta si es necesario y cerrar el examen cuando se llegue a la última pregunta. Esto último se puede hacer muy fácilmente agregando una condición adicional en la función doPost.
Luego de generar el script, debes publicarlo. Para ello, ve al menu: Publicar->Implementar como aplicación web y sigue los pasos. Toma la url y enviala a los alumnos. No te olvides de habilitar el script para que lo puedan ejecutar.
Aqui, el script completo:
var ID_DOC = "0Asc5B6RPrg-_dHl0UXhVVnZiMXEzS3dCMGgzMjZBTFE";
function doGet() {
var app = UiApp.createApplication();
var form = app.createFormPanel();
var flow = app.createFlowPanel();
flow.add( app.createHidden().setName("step").setValue( 0 ) );
flow.add( app.createLabel("Ingrese su nombre: ") );
flow.add( app.createTextBox().setName("student") );
flow.add( app.createSubmitButton("Siguiente") );
form.add( flow );
app.add( form );
return app;
}
function doPost(eventInfo) {
var app = UiApp.getActiveApplication();
if(eventInfo.parameter.step=="0"){
var st = initTest(eventInfo.parameter.student);
app = updateFields(app, 1, st);
}else{
setAnswer(eventInfo);
app = updateFields(app, Number(eventInfo.parameter.step), eventInfo.parameter.student);
}
return app;
}
function initTest(studentName){
var sheet = SpreadsheetApp.openById(ID_DOC).getSheetByName("Respuestas");
var row = sheet.getLastRow() + 1;
sheet.getRange("A"+row).setValue(new Date());
sheet.getRange("C"+row).setValue(studentName);
return row;
}
function updateFields(app, step, st){
var form = app.createFormPanel();
var flow = app.createFlowPanel();
flow.add( app.createHidden().setName("step").setValue( step+1 ) );
flow.add( app.createHidden().setName("student").setValue( st ) );
flow.add( app.createTextBox().setName("question").setValue( getQuestion( step ) ).setEnabled( false ) );
flow.add( app.createListBox().setName("answer").addItem("Seleccione").addItem("Verdadero").addItem("Falso") );
flow.add( app.createSubmitButton("Siguiente") );
form.add( flow );
app.add( form );
return app;
}
function getQuestion( step ){
return SpreadsheetApp.openById(ID_DOC).getSheetByName("Cuestionario").getRange("A"+(step+1)).getValue();
}
function setAnswer( eventInfo ){
var range = SpreadsheetApp.openById(ID_DOC).getSheetByName("Respuestas").getRange("D"+eventInfo.parameter.student);
range.setValue( range.getValue()+eventInfo.parameter.step+":"+eventInfo.parameter.answer+"," );
}