Merge pull request #944 from AngelFQC/7705

Fix Hotspot question edition - refs 7705
1.10.x
Angel Fernando Quiroz Campos 9 years ago
commit cf7ce472e0
  1. 2
      main/exercice/admin.php
  2. 43
      main/exercice/exercise.class.php
  3. 2
      main/exercice/exercise_result.php
  4. 55
      main/exercice/exercise_show.php
  5. 1
      main/exercice/exercise_submit.php
  6. 68
      main/exercice/hotspot_actionscript.as.php
  7. 44
      main/exercice/hotspot_actionscript_admin.as.php
  8. 72
      main/exercice/hotspot_admin.inc.php
  9. 92
      main/exercice/hotspot_answers.as.php
  10. 2
      main/exercice/result.php
  11. 24
      main/inc/lib/events.lib.php
  12. 170
      main/inc/lib/exercise.lib.php
  13. 15
      main/plugin/hotspot2/css/hotspot.css
  14. 506
      main/plugin/hotspot2/js/hotspot.js
  15. 231
      main/plugin/hotspot2/js/hotspot_solution.js
  16. 269
      main/plugin/hotspot2/js/hotspot_user.js
  17. 92
      src/Chamilo/CoreBundle/Component/Editor/CkEditor/Toolbar/TestProposedAnswer.php

@ -344,6 +344,8 @@ $template = new Template();
$htmlHeadXtra[] = $template->fetch('default/exercise/submit.js.tpl');
$htmlHeadXtra[] = api_get_js('d3/jquery.xcolor.js');
$htmlHeadXtra[] = '<script src="../plugin/hotspot2/js/hotspot.js"></script>';
$htmlHeadXtra[] = "<script type=\"text/javascript\" src=\"../plugin/hotspot/JavaScriptFlashGateway.js\"></script>
<script src=\"../plugin/hotspot/hotspot.js\" type=\"text/javascript\"></script>
<script language=\"JavaScript\" type=\"text/javascript\">

@ -3128,7 +3128,7 @@ class Exercise
WHERE
hotspot_exe_id = '".$exeId."' AND
hotspot_question_id= '".$questionId."' AND
hotspot_answer_id = ".intval($answerId)."";
hotspot_answer_id = ".intval($answerAutoId)."";
$result = Database::query($sql);
$studentChoice = Database::result($result, 0, "hotspot_correct");
@ -3137,7 +3137,7 @@ class Exercise
$totalScore += $answerWeighting;
}
} else {
$studentChoice = $choice[$answerId];
$studentChoice = $choice[$answerAutoId];
if ($studentChoice) {
$questionScore += $answerWeighting;
$totalScore += $answerWeighting;
@ -4036,25 +4036,24 @@ class Exercise
if ($show_result) {
// if ($origin != 'learnpath') {
echo '</table></td></tr>';
echo '<tr>
<td colspan="2">';
echo '<i>'.get_lang('HotSpot').'</i><br /><br />';
echo '<object type="application/x-shockwave-flash" data="'
. api_get_path(WEB_CODE_PATH)
. 'plugin/hotspot/hotspot_solution.swf?modifyAnswers='
. Security::remove_XSS($questionId)
. '&exe_id='
. $exeId
. '&from_db=1" width="552" height="352">
<param name="movie" value="../plugin/hotspot/hotspot_solution.swf?modifyAnswers='
. Security::remove_XSS($questionId)
. '&exe_id='
. $exeId
. '&from_db=1" />
</object>';
echo '</td>
</tr>';
echo "
<tr>
<td colspan=\"2\">
<p><em>" . get_lang('HotSpot') . "</em></p>
<div id=\"hotspot-solution\"></div>
<script>
$(document).on('ready', function () {
HotSpotSolution.init({
questionId: $questionId,
exerciseId: $exeId,
selector: '#hotspot-solution'
});
});
</script>
</td>
</tr>
";
// }
}
}
@ -4143,7 +4142,7 @@ class Exercise
Event::saveQuestionAttempt($questionScore, $answer, $quesId, $exeId, 0, $this->id);
if (isset($exerciseResultCoordinates[$questionId]) && !empty($exerciseResultCoordinates[$questionId])) {
foreach ($exerciseResultCoordinates[$questionId] as $idx => $val) {
Event::saveExerciseAttemptHotspot($exeId, $quesId, $idx, $choice[$idx], $val, $this->id);
Event::saveExerciseAttemptHotspot($exeId, $quesId, $idx, $choice[$idx], $val, false, $this->id);
}
}
} else {

@ -75,6 +75,8 @@ $interbreadcrumb[] = array(
"name" => get_lang('Exercises'),
);
$htmlHeadXtra[] = '<script src="' . api_get_path(WEB_CODE_PATH) . 'plugin/hotspot2/js/hotspot_solution.js"></script>';
if ($origin != 'learnpath') {
// So we are not in learnpath tool
Display::display_header($nameTools, get_lang('Exercise'));

@ -120,6 +120,8 @@ $interbreadcrumb[]= array("url" => "#","name" => get_lang('Result'));
$this_section = SECTION_COURSES;
$htmlHeadXtra[] = '<script src="' . api_get_path(WEB_CODE_PATH) . 'plugin/hotspot2/js/hotspot_solution.js"></script>';
if ($origin != 'learnpath') {
Display::display_header('');
} else {
@ -367,14 +369,25 @@ foreach ($questionList as $questionId) {
if ($show_results) {
echo '</table></td></tr>';
echo '<tr>
<td colspan="2">'.
'<object type="application/x-shockwave-flash" data="'.api_get_path(WEB_CODE_PATH).'plugin/hotspot/hotspot_solution.swf?modifyAnswers='.Security::remove_XSS($questionId).'&exe_id='.$id.'&from_db=1" width="552" height="352">
<param name="movie" value="../plugin/hotspot/hotspot_solution.swf?modifyAnswers='.Security::remove_XSS($questionId).'&exe_id='.$id.'&from_db=1" />
</object>
</td>
</tr>
</table><br/>';
echo "
<tr>
<td colspan=\"2\">
<div id=\"hotspot-solution\"></div>
<script>
$(document).on('ready', function () {
HotSpotSolution.init({
questionId: $questionId,
exerciseId: $id,
selector: '#hotspot-solution'
});
});
</script>
</td>
</tr>
</table>
<br>
";
}
} else if($answerType == HOT_SPOT_DELINEATION) {
@ -497,14 +510,24 @@ foreach ($questionList as $questionId) {
$questionScore= Database::result($resfree,0,"marks");
$totalScore+=$questionScore;
echo '</table></td></tr>';
echo '<tr>
<td colspan="2">
<object type="application/x-shockwave-flash" data="../plugin/hotspot/hotspot_solution.swf?modifyAnswers='.$questionId.'&exe_id='.$id.'&from_db=1" width="556" height="350">
<param name="movie" value="../plugin/hotspot/hotspot_solution.swf?modifyAnswers='.$questionId.'&exe_id='.$id.'&from_db=1" />
</object>
</td>
</tr>
</table>';
echo "
<tr>
<td colspan=\"2\">
<div id=\"hotspot-solution\"></div>
<script>
$(document).on('ready', function () {
HotSpotSolution.init({
questionId: $questionId,
exerciseId: $id,
selector: '#hotspot-solution'
});
});
</script>
</td>
</tr>
</table>
";
}
}

@ -60,6 +60,7 @@ $htmlHeadXtra[] = api_get_css(api_get_path(WEB_LIBRARY_PATH).'javascript/epicloc
$htmlHeadXtra[] = api_get_js('epiclock/javascript/jquery.dateformat.min.js');
$htmlHeadXtra[] = api_get_js('epiclock/javascript/jquery.epiclock.min.js');
$htmlHeadXtra[] = api_get_js('epiclock/renderers/minute/epiclock.minute.js');
$htmlHeadXtra[] = '<script src="../plugin/hotspot2/js/hotspot_user.js"></script>';
$template = new Template();

@ -24,11 +24,6 @@ $pictureSize = getimagesize($picturePath.'/'.$objQuestion->selectPicture());
$pictureWidth = $pictureSize[0];
$pictureHeight = $pictureSize[1];
$courseLang = $_course['language'];
$courseCode = $_course['sysCode'];
$coursePath = $_course['path'];
$course_id = api_get_course_int_id();
// Query db for answers
@ -40,39 +35,63 @@ if ($answer_type==HOT_SPOT_DELINEATION) {
WHERE c_id = $course_id AND question_id = ".intval($questionId)." ORDER BY id";
}
$result = Database::query($sql);
// Init
$output = "hotspot_lang=$courseLang&hotspot_image=$pictureName&hotspot_image_width=$pictureWidth&hotspot_image_height=$pictureHeight&courseCode=$coursePath";
$i = 0;
$data = [];
$data['lang'] = [
'Square' => get_lang('Square'),
'Circle' => get_lang('Circle'),
'Poly' => get_lang('Poly'),
'HotspotStatus1' => get_lang('HotspotStatus1'),
'HotspotStatus2Polygon' => get_lang('HotspotStatus2Polygon'),
'HotspotStatus2Other' => get_lang('HotspotStatus2Other'),
'HotspotStatus3' => get_lang('HotspotStatus3'),
'HotspotShowUserPoints' => get_lang('HotspotShowUserPoints'),
'ShowHotspots' => get_lang('ShowHotspots'),
'Triesleft' => get_lang('Triesleft'),
'ExerciseFinished' => get_lang('ExerciseFinished'),
'NextAnswer' => get_lang('NextAnswer'),
'Delineation' => get_lang('Delineation'),
'CloseDelineation' => get_lang('CloseDelineation'),
'Oar' => get_lang('oar')
];
$data['image'] = $objQuestion->selectPicturePath();
$data['image_width'] = $pictureWidth;
$data['image_height'] = $pictureHeight;
$data['courseCode'] = $_course['path'];
$data['hotspots'] = [];
$nmbrTries = 0;
while ($hotspot = Database::fetch_assoc($result))
{
$output .= "&hotspot_".$hotspot['id']."=true";
$output .= "&hotspot_".$hotspot['id']."_answer=".str_replace('&','{amp}',$hotspot['answer']);
$hotSpot = [];
$hotSpot['id'] = $hotspot['id'];
$hotSpot['answer'] = $hotspot['answer'];
// Square or rectancle
if ($hotspot['hotspot_type'] == 'square' )
{
$output .= "&hotspot_".$hotspot['id']."_type=square";
$hotSpot['type'] = 'square';
}
// Circle or ovale
if ($hotspot['hotspot_type'] == 'circle')
{
$output .= "&hotspot_".$hotspot['id']."_type=circle";
$hotSpot['type'] = 'circle';
}
// Polygon
if ($hotspot['hotspot_type'] == 'poly')
{
$output .= "&hotspot_".$hotspot['id']."_type=poly";
$hotSpot['type'] = 'poly';
}
// Delineation
if ($hotspot['hotspot_type'] == 'delineation')
{
$output .= "&hotspot_".$hotspot['id']."_type=delineation";
$hotSpot['type'] = 'delineation';
}
// No error
if ($hotspot['hotspot_type'] == 'noerror')
{
$output .= "&hotspot_".$hotspot['id']."_type=noerror";
$hotSpot['type'] = 'noerror';
}
// This is a good answer, count + 1 for nmbr of clicks
@ -80,14 +99,15 @@ while ($hotspot = Database::fetch_assoc($result))
{
$nmbrTries++;
}
$output .= "&hotspot_".$hotspot['id']."_coord=".$hotspot['hotspot_coordinates']."";
$i++;
}
// Generate empty
$i++;
for ($i; $i <= 12; $i++) {
$output .= "&hotspot_".$i."=false";
$hotSpot['coord'] = $hotspot['hotspot_coordinates'];
$data['hotspots'][] = $hotSpot;
}
// Output
echo $output."&nmbrTries=".$nmbrTries."&done=done";
$data['nmbrTries'] = $nmbrTries;
$data['done'] = 'done';
header('Content-Type: application/json');
echo json_encode($data);

@ -21,12 +21,15 @@ $pictureSize = getimagesize($picturePath.'/'.$objQuestion->selectPicture());
$pictureWidth = $pictureSize[0];
$pictureHeight = $pictureSize[1];
$courseLang = $_course['language'];
$courseCode = $_course['code'];
$coursePath = $_course['path'];
$data = [];
$data['hotspot_lang'] = $_course['language'];
$data['hotspot_image'] = $pictureName;
$data['hotspot_image_width'] = $pictureWidth;
$data['hotspot_image_height'] = $pictureHeight;
$data['courseCode'] = $_course['path'];
$data['hotspots'] = [];
// Init
$output = "hotspot_lang=$courseLang&hotspot_image=$pictureName&hotspot_image_width=$pictureWidth&hotspot_image_height=$pictureHeight&courseCode=$coursePath";
$i = 0;
$nmbrTries = 0;
$answer_type = $objQuestion->type;
@ -35,28 +38,29 @@ $answers = $_SESSION['tmp_answers'];
$nbrAnswers = count($answers['answer']);
for ($i=1;$i <= $nbrAnswers; $i++) {
$output .= "&hotspot_".$i."=true";
$output .= "&hotspot_".$i."_answer=".$answers['answer'][$i];
$hotSpot = [];
$hotSpot['answer']= $answers['answer'][$i];
if ($answer_type == HOT_SPOT_DELINEATION) {
if ($i==1) {
$output .= "&hotspot_".$i."_type=delineation";
} else
{$output .= "&hotspot_".$i."_type=oar";}
$hotSpot['type'] = 'delineation';
} else {
$hotSpot['type'] = 'oar';
}
} else {
// Square or rectancle
if ($answers['hotspot_type'][$i] == 'square') {
$output .= "&hotspot_".$i."_type=square";
$hotSpot['type'] = 'square';
}
// Circle or ovale
if ($answers['hotspot_type'][$i] == 'circle') {
$output .= "&hotspot_".$i."_type=circle";
$hotSpot['type'] = 'circle';
}
// Polygon
if ($answers['hotspot_type'][$i] == 'poly') {
$output .= "&hotspot_".$i."_type=poly";
$hotSpot['type'] = 'poly';
}
/*// Delineation
if ($answers['hotspot_type'][$i] == 'delineation')
@ -70,14 +74,14 @@ for ($i=1;$i <= $nbrAnswers; $i++) {
$nmbrTries++;
}
$output .= "&hotspot_".$i."_coord=".$answers['hotspot_coordinates'][$i]."";
}
// Generate empty
$i++;
for ($i; $i <= 12; $i++) {
$output .= "&hotspot_".$i."=false";
$hotSpot['coord'] = $answers['hotspot_coordinates'][$i];
$data['hotspots'][] = $hotSpot;
}
// Output
echo $output."&nmbrTries=".$nmbrTries."&done=done";
$data['nmbrTries'] = $nmbrTries;
$data['done'] = 'done';
header('Content-Type: application/json');
echo json_encode($data);

@ -585,12 +585,11 @@ if ($modifyAnswers) {
</button>
</div>
</div>
<table border="0" cellpadding="0" cellspacing="2" width="100%">
<tr>
<td>
<input type="hidden" name="formSent" value="1" />
<input type="hidden" name="nbrAnswers" value="<?php echo $nbrAnswers; ?>" />
<input type="hidden" name="formSent" value="1" />
<input type="hidden" name="nbrAnswers" value="<?php echo $nbrAnswers; ?>" />
<div class="table-responsive">
<table class="table table-striped table-hover">
<thead>
<tr>
<th width="5">&nbsp;</th>
<th> <?php echo get_lang('HotspotDescription'); ?> *</th>
@ -614,6 +613,8 @@ if ($modifyAnswers) {
<?php } ?>
<th><?php echo get_lang('QuestionWeighting'); ?> *</th>
</tr>
</thead>
<tbody>
<?php
$list = new LearnpathList(api_get_user_id());
// Loading list of LPs
@ -818,7 +819,7 @@ if ($modifyAnswers) {
<div style="height: 15px; width: 15px; background-color: <?php echo $hotspot_colors[$i]; ?>"> </div>
</td>
<td>
<input type="text" name="reponse[<?php echo $i; ?>]" value="<?php echo Security::remove_XSS($reponse[$i]); ?>" size="20" />
<input class="form-control" type="text" name="reponse[<?php echo $i; ?>]" value="<?php echo Security::remove_XSS($reponse[$i]); ?>" />
</td>
<td colspan="2" align="left">
@ -864,15 +865,16 @@ if ($modifyAnswers) {
?>
<tr>
<td>
<div style="height: 15px; width: 15px; background-color: <?php echo $hotspot_colors[$i]; ?>"> </div>
<span class="fa fa-square fa-2x" style="color: <?php echo $hotspot_colors[$i]; ?>" aria-hidden="true"></span>
</td>
<td>
<input type="text" name="reponse[<?php echo $i; ?>]" value="<?php echo Security::remove_XSS($responseValue); ?>" size="45" />
<input class="form-control" type="text" name="reponse[<?php echo $i; ?>]" value="<?php echo Security::remove_XSS($responseValue); ?>" />
</td>
<?php
$form = new FormValidator('form_' . $i);
$config = array(
'ToolbarSet' => 'TestProposedAnswer'
'ToolbarSet' => 'TestProposedAnswer',
'cols-size' => [0, 12, 0]
);
$form->addHtmlEditor('comment[' . $i . ']', null, false, false, $config);
$renderer = $form->defaultRenderer();
@ -886,8 +888,7 @@ if ($modifyAnswers) {
$form->setDefaults(array('comment[' . $i . ']' => $commentValue));
$return = $form->return_form();
?>
<td>&nbsp;</td>
<td align="left" ><?php echo $return; ?></td>
<td colspan="2" align="left" ><?php echo $return; ?></td>
<?php } ?>
<td>
<?php
@ -896,13 +897,13 @@ if ($modifyAnswers) {
?>
<input type="hidden" name="weighting[<?php echo $i; ?>]" class="span3" value="0" />
<?php } else { ?>
<input type="text" name="weighting[<?php echo $i; ?>]" class="span3" value="<?php echo (isset($weighting[$i]) ? $weighting[$i] : 10); ?>" />
<input class="form-control" type="text" name="weighting[<?php echo $i; ?>]" value="<?php echo (isset($weighting[$i]) ? $weighting[$i] : 10); ?>" />
<?php
}
}
if ($answerType == HOT_SPOT) {
?>
<input type="text" name="weighting[<?php echo $i; ?>]" class="span3" value="<?php echo (isset($weighting[$i]) ? $weighting[$i] : 10); ?>" />
<input class="form-control" type="text" name="weighting[<?php echo $i; ?>]" value="<?php echo (isset($weighting[$i]) ? $weighting[$i] : 10); ?>" />
<input type="hidden" name="hotspot_coordinates[<?php echo $i; ?>]" value="<?php echo (empty($hotspot_coordinates[$i]) ? '0;0|0|0' : $hotspot_coordinates[$i]); ?>" />
<input type="hidden" name="hotspot_type[<?php echo $i; ?>]" value="<?php echo (empty($hotspot_type[$i]) ? 'square' : $hotspot_type[$i]); ?>" />
<?php } ?>
@ -1004,38 +1005,31 @@ if ($modifyAnswers) {
<?php } ?>
</tr>
<?php } ?>
</tbody>
</table>
</td>
</tr>
<tr>
<td>
<script>
<!--
// Version check based upon the values entered above in "Globals"
var hasReqestedVersion = DetectFlashVer(requiredMajorVersion, requiredMinorVersion, requiredRevision);
</div>
<div class="row">
<div class="col-xs-12" id="hotspot-selectors"></div>
</div>
<div class="row">
<div class="col-xs-12">
<?php
$swf_loaded = $answerType == HOT_SPOT_DELINEATION ? 'hotspot_delineation_admin' : 'hotspot_admin';
$height = 450;
?>
// Check to see if the version meets the requirements for playback
if (hasReqestedVersion) { // if we've detected an acceptable version
var oeTags = '<object type="application/x-shockwave-flash" data="../plugin/hotspot/<?php echo $swf_loaded ?>.swf?modifyAnswers=<?php echo $modifyAnswers ?>" width="600" height="<?php echo $height ?>">'
+ '<param name="movie" value="../plugin/hotspot/<?php echo $swf_loaded ?>.swf?modifyAnswers=<?php echo $modifyAnswers ?>" />'
+ '<param name="test" value="OOoowww fo shooww" />'
+ '</object>';
document.write(oeTags); // embed the Flash Content SWF when all tests are passed
} else { // flash is too old or we can't detect the plugin
var alternateContent = 'Error<br \/>'
+ 'This content requires the Macromedia Flash Player.<br \/>'
+ '<a href=http://www.macromedia.com/go/getflash/>Get Flash<\/a>';
document.write(alternateContent); // insert non-flash content
}
// -->
</script>
</td>
</tr>
</table>
<div id="hotspot-container" class="center-block">
<div id="hotspot-alert"></div>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 0 0">
</svg>
</div>
</div>
</div>
</form>
<script>
$(document).on('ready', function () {
HotSpotAdmin.init(<?php echo $modifyAnswers ?>, '<?php echo $objQuestion->selectPicturePath(); ?>');
});
</script>
<?php
if ($debug > 0) {
echo str_repeat('&nbsp;', 0) . '$modifyAnswers was set - end' . "<br />\n";

@ -13,7 +13,6 @@ include('../inc/global.inc.php');
// Set vars
$questionId = intval($_GET['modifyAnswers']);
$exe_id = intval($_GET['exe_id']);
$from_db = isset($_GET['from_db']) ? $_GET['from_db'] : 0;
$objQuestion = Question :: read($questionId);
$TBL_ANSWERS = Database::get_course_table(TABLE_QUIZ_ANSWER);
$documentPath = api_get_path(SYS_COURSE_PATH).$_course['path'].'/document';
@ -24,10 +23,6 @@ $pictureSize = getimagesize($picturePath.'/'.$objQuestion->selectPicture());
$pictureWidth = $pictureSize[0];
$pictureHeight = $pictureSize[1];
$courseLang = $_course['language'];
$course_code = Database::escape_string($_course['id']);
$coursePath = $_course['path'];
$answer_type = $objQuestion->selectType();
$course_id = api_get_course_int_id();
@ -42,64 +37,79 @@ if ($answer_type == HOT_SPOT_DELINEATION) {
}
$result = Database::query($sql);
// Init
$output = "hotspot_lang=$courseLang&hotspot_image=$pictureName&hotspot_image_width=$pictureWidth&hotspot_image_height=$pictureHeight&courseCode=$coursePath";
$i = 0;
$data['lang'] = [
'Square' => get_lang('Square'),
'Circle' => get_lang('Circle'),
'Poly' => get_lang('Poly'),
'HotspotStatus1' => get_lang('HotspotStatus1'),
'HotspotStatus2Polygon' => get_lang('HotspotStatus2Polygon'),
'HotspotStatus2Other' => get_lang('HotspotStatus2Other'),
'HotspotStatus3' => get_lang('HotspotStatus3'),
'HotspotShowUserPoints' => get_lang('HotspotShowUserPoints'),
'ShowHotspots' => get_lang('ShowHotspots'),
'Triesleft' => get_lang('Triesleft'),
'ExerciseFinished' => get_lang('ExerciseFinished'),
'NextAnswer' => get_lang('NextAnswer'),
'Delineation' => get_lang('Delineation'),
'CloseDelineation' => get_lang('CloseDelineation'),
'Oar' => get_lang('oar')
];
$data['image'] = $objQuestion->selectPicturePath();
$data['image_width'] = $pictureWidth;
$data['image_height'] = $pictureHeight;
$data['courseCode'] = $_course['path'];
$data['hotspots'] = [];
while ($hotspot = Database::fetch_array($result)) {
$output .= "&hotspot_".$hotspot['id']."=true";
$hotSpot = [];
$hotSpot['id'] = $hotspot['id'];
// Square or rectancle
if ($hotspot['hotspot_type'] == 'square' ) {
$output .= "&hotspot_".$hotspot['id']."_type=square";
$hotSpot['type'] = 'square';
}
// Circle or ovale
if ($hotspot['hotspot_type'] == 'circle') {
$output .= "&hotspot_".$hotspot['id']."_type=circle";
$hotSpot['type'] = 'circle';
}
// Polygon
if ($hotspot['hotspot_type'] == 'poly') {
$output .= "&hotspot_".$hotspot['id']."_type=poly";
$hotSpot['type'] = 'poly';
}
// Delineation
if ($hotspot['hotspot_type'] == 'delineation') {
$output .= "&hotspot_".$hotspot['id']."_type=delineation";
$hotSpot['type'] = 'delineation';
}
// oar
if ($hotspot['hotspot_type'] == 'oar') {
$output .= "&hotspot_".$hotspot['id']."_type=delineation";
$hotSpot['type'] = 'delineation';
}
$output .= "&hotspot_".$hotspot['id']."_coord=".$hotspot['hotspot_coordinates']."";
$i++;
}
// Generate empty (the maximum number of points is 12 - it is said so in the user interface)
$i++;
for ($i; $i <= 12; $i++) {
$output .= "&hotspot_".$i."=false";
$hotSpot['coord'] = $hotspot['hotspot_coordinates'];
$data['hotspots'][] = $hotSpot;
}
$data['answers'] = [];
// Get clicks
if(isset($_SESSION['exerciseResultCoordinates']) && $from_db==0) {
foreach ($_SESSION['exerciseResultCoordinates'][$questionId] as $coordinate) {
$output2 .= $coordinate."|";
}
} else {
// get it from db
$tbl_track_e_hotspot = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTSPOT);
$sql = "SELECT hotspot_coordinate
FROM $tbl_track_e_hotspot
WHERE hotspot_question_id = $questionId AND
c_id = $course_id AND
hotspot_exe_id = $exe_id
ORDER by hotspot_id";
$rs = @Database::query($sql); // don't output error because we are in Flash execution.
while($row = Database :: fetch_array($rs)) {
$output2 .= $row['hotspot_coordinate']."|";
}
$tbl_track_e_hotspot = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTSPOT);
$sql = "SELECT hotspot_coordinate
FROM $tbl_track_e_hotspot
WHERE hotspot_question_id = $questionId AND
c_id = $course_id AND
hotspot_exe_id = $exe_id
ORDER by hotspot_id";
$rs = Database::query($sql); // don't output error because we are in Flash execution.
while($row = Database :: fetch_array($rs, 'ASSOC')) {
$data['answers'][] = $row['hotspot_coordinate'];
}
$output .= "&p_hotspot_answers=".api_substr($output2,0,-1)."&done=done";
$explode = explode('&', $output);
echo $output;
$data['done'] = 'done';
header('Content-Type: application/json');
echo json_encode($data);

@ -53,6 +53,8 @@ if (!$is_allowedToEdit) {
}
}
$htmlHeadXtra[] = '<script src="' . api_get_path(WEB_CODE_PATH) . 'plugin/hotspot2/js/hotspot_solution.js"></script>';
if ($show_headers) {
$interbreadcrumb[] = array(
"url" => "exercise.php?".api_get_cidreq(),

@ -613,17 +613,19 @@ class Event
)));
} else {
$sql = "INSERT INTO $tbl_track_e_hotspot (hotspot_course_code, hotspot_user_id, c_id, hotspot_exe_id, hotspot_question_id, hotspot_answer_id, hotspot_correct, hotspot_coordinate)
VALUES (
'".api_get_course_id()."',
".api_get_user_id()."',".
" ".api_get_course_int_id().", ".
" '".Database :: escape_string($exe_id)."', ".
" '".Database :: escape_string($question_id)."',".
" '".Database :: escape_string($answer_id)."',".
" '".Database :: escape_string($correct)."',".
" '".Database :: escape_string($coords)."')";
return $result = Database::query($sql);
return Database::insert(
$tbl_track_e_hotspot,
[
'hotspot_course_code' => api_get_course_id(),
'hotspot_user_id' => api_get_user_id(),
'c_id' => api_get_course_int_id(),
'hotspot_exe_id' => $exe_id,
'hotspot_question_id' => $question_id,
'hotspot_answer_id' => $answer_id,
'hotspot_correct' => $correct,
'hotspot_coordinate' => $coords
]
);
}
}

@ -1156,153 +1156,37 @@ HTML;
echo '<div class="question_title">' . $current_item . '. ' . $questionName . '</div>';
}
//@todo I need to the get the feedback type
echo '<input type="hidden" name="hidden_hotspot_id" value="' . $questionId . '" />';
echo '<table class="exercise_questions" >
<tr>
<td valign="top" colspan="2">';
echo $questionDescription;
echo '</td></tr>';
echo <<<HOTSPOT
<input type="hidden" name="hidden_hotspot_id" value="$questionId" />
<div class="exercise_questions">
$questionDescription
<div class="row">
HOTSPOT;
}
$canClick = isset($_GET['editQuestion']) ? '0' : (isset($_GET['modifyAnswers']) ? '0' : '1');
$s .= '<script type="text/javascript" src="../plugin/hotspot/JavaScriptFlashGateway.js"></script>
<script src="../plugin/hotspot/hotspot.js" type="text/javascript" ></script>
<script type="text/javascript">
<!--
// Globals
// Major version of Flash required
var requiredMajorVersion = 7;
// Minor version of Flash required
var requiredMinorVersion = 0;
// Minor version of Flash required
var requiredRevision = 0;
// the version of javascript supported
var jsVersion = 1.0;
// -->
</script>
<script language="VBScript" type="text/vbscript">
<!-- // Visual basic helper required to detect Flash Player ActiveX control version information
Function VBGetSwfVer(i)
on error resume next
Dim swControl, swVersion
swVersion = 0
set swControl = CreateObject("ShockwaveFlash.ShockwaveFlash." + CStr(i))
if (IsObject(swControl)) then
swVersion = swControl.GetVariable("$version")
end if
VBGetSwfVer = swVersion
End Function
// -->
</script>
<script language="JavaScript1.1" type="text/javascript">
<!-- // Detect Client Browser type
var isIE = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false;
var isWin = (navigator.appVersion.toLowerCase().indexOf("win") != -1) ? true : false;
var isOpera = (navigator.userAgent.indexOf("Opera") != -1) ? true : false;
jsVersion = 1.1;
// JavaScript helper required to detect Flash Player PlugIn version information
function JSGetSwfVer(i) {
// NS/Opera version >= 3 check for Flash plugin in plugin array
if (navigator.plugins != null && navigator.plugins.length > 0) {
if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) {
var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : "";
var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description;
descArray = flashDescription.split(" ");
tempArrayMajor = descArray[2].split(".");
versionMajor = tempArrayMajor[0];
versionMinor = tempArrayMajor[1];
if ( descArray[3] != "" ) {
tempArrayMinor = descArray[3].split("r");
} else {
tempArrayMinor = descArray[4].split("r");
}
versionRevision = tempArrayMinor[1] > 0 ? tempArrayMinor[1] : 0;
flashVer = versionMajor + "." + versionMinor + "." + versionRevision;
} else {
flashVer = -1;
}
}
// MSN/WebTV 2.6 supports Flash 4
else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4;
// WebTV 2.5 supports Flash 3
else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3;
// older WebTV supports Flash 2
else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2;
// Can\'t detect in all other cases
else
{
flashVer = -1;
}
return flashVer;
}
// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available
function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) {
reqVer = parseFloat(reqMajorVer + "." + reqRevision);
// loop backwards through the versions until we find the newest version
for (i=25;i>0;i--) {
if (isIE && isWin && !isOpera) {
versionStr = VBGetSwfVer(i);
} else {
versionStr = JSGetSwfVer(i);
}
if (versionStr == -1 ) {
return false;
} else if (versionStr != 0) {
if(isIE && isWin && !isOpera) {
tempArray = versionStr.split(" ");
tempString = tempArray[1];
versionArray = tempString .split(",");
} else {
versionArray = versionStr.split(".");
}
versionMajor = versionArray[0];
versionMinor = versionArray[1];
versionRevision = versionArray[2];
versionString = versionMajor + "." + versionRevision; // 7.0r24 == 7.24
versionNum = parseFloat(versionString);
// is the major.revision >= requested major.revision AND the minor version >= requested minor
if ( (versionMajor > reqMajorVer) && (versionNum >= reqVer) ) {
return true;
} else {
return ((versionNum >= reqVer && versionMinor >= reqMinorVer) ? true : false );
}
}
}
}
// -->
</script>';
$s .= '<tr><td valign="top" colspan="2" width="520"><table><tr><td width="520">
<script>
<!--
// Version check based upon the values entered above in "Globals"
var hasReqestedVersion = DetectFlashVer(requiredMajorVersion, requiredMinorVersion, requiredRevision);
// Check to see if the version meets the requirements for playback
if (hasReqestedVersion) { // if we\'ve detected an acceptable version
var oeTags = \'<object type="application/x-shockwave-flash" data="../plugin/hotspot/' . $swf_file . '.swf?modifyAnswers=' . $questionId . '&canClick:' . $canClick . '" width="600" height="' . $swf_height . '">\'
+ \'<param name="wmode" value="transparent">\'
+ \'<param name="movie" value="../plugin/hotspot/' . $swf_file . '.swf?modifyAnswers=' . $questionId . '&canClick:' . $canClick . '" />\'
+ \'<\/object>\';
document.write(oeTags); // embed the Flash Content SWF when all tests are passed
} else { // flash is too old or we can\'t detect the plugin
var alternateContent = "Error<br \/>"
+ "Hotspots requires Macromedia Flash 7.<br \/>"
+ "<a href=\"http://www.macromedia.com/go/getflash/\">Get Flash<\/a>";
document.write(alternateContent); // insert non-flash content
}
// -->
</script>
</td>
<td valign="top" align="left">' . $answer_list . '</td></tr>
</table>
</td></tr>';
echo $s;
echo '</table>';
$s .= <<<HOTSPOT
<div class="col-sm-8 col-md-9">
<div class="hotspot-image"></div>
<script>
$(document).on('ready', function () {
HotSpotUser.init({
questionId: $questionId,
selector: '#question_div_' + $questionId + ' .hotspot-image'
});
});
</script>
</div>
<div class="col-sm-4 col-md-3">
$answer_list
</div>
HOTSPOT;
echo <<<HOTSPOT
$s
</div>
</div>
HOTSPOT;
}
return $nbrAnswers;
}

@ -0,0 +1,15 @@
#hotspot-container {
line-height: 0;
/*position: relative;
width: 100%;
vertical-align: middle;
padding-bottom: 408px;
margin: 0;
overflow: hidden;*/
}
#hotspot-container svg {
/*display: inline-block;
position: absolute;
top: 0;
left: 0;*/
}

@ -0,0 +1,506 @@
var HotSpotAdmin = (function () {
var HotSpotSquare = function () {
this.x = 0;
this.y = 0;
this.width = 0;
this.height = 0;
};
HotSpotSquare.prototype.setStartPoint = function (x, y) {
this.x = parseInt(x);
this.y = parseInt(y);
};
HotSpotSquare.prototype.setEndPoint = function (x, y) {
var x2, y2;
x = parseInt(x);
y = parseInt(y);
if (x < this.x) {
x2 = this.x;
this.x = x;
} else {
x2 = x;
}
if (y < this.y) {
y2 = this.y;
this.y = y;
} else {
y2 = y;
}
this.width = Math.round(x2 - this.x);
this.height = Math.round(y2 - this.y);
};
HotSpotSquare.prototype.encode = function () {
var encodedPosition = [this.x, this.y].join(';');
return [
encodedPosition,
this.width,
this.height
].join('|');
}
var HotSpotEllipse = function () {
this.centerX = 0;
this.centerY = 0;
this.radiusX = 0;
this.radiusY = 0;
};
HotSpotEllipse.prototype.setStartPoint = function (x, y) {
this.centerX = parseInt(x);
this.centerY = parseInt(y);
};
HotSpotEllipse.prototype.setEndPoint = function (x, y) {
var startX = this.centerX,
startY = this.centerY,
endX = 0,
endY = 0;
x = parseInt(x);
y = parseInt(y);
if (x < startX) {
endX = startX;
startX = x;
} else {
endX = x;
}
if (y < startY) {
endY = startY;
startY = y;
} else {
endY = y;
}
var width = Math.round(endX - startX);
var height = Math.round(endY - startY);
this.radiusX = Math.round(width / 2);
this.radiusY = Math.round(height / 2);
this.centerX = startX + this.radiusX;
this.centerY = startY + this.radiusY;
};
HotSpotEllipse.prototype.encode = function () {
var encodedCenter = [this.centerX, this.centerY].join(';');
return [
encodedCenter,
this.radiusX,
this.radiusY
].join('|');
};
var HotSpotPolygon = function () {
this.points = [];
};
HotSpotPolygon.prototype.addPoint = function (x, y) {
this.points.push([
parseInt(x),
parseInt(y)
]);
};
HotSpotPolygon.prototype.encode = function () {
var encodedPoints = [];
this.points.forEach(function (point) {
encodedPoints.push(point.join(';'));
});
return encodedPoints.join('|');
};
var HotSpotEl = function (hotspot, color) {
this.hotspot = hotspot;
this.element = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
this.elStroke = 'rgb(' + color + ')';
this.elFill = 'rgba(' + color + ', 0.5)';
};
HotSpotEl.prototype.render = function () {
return this;
};
HotSpotEl.prototype.remove = function () {
if (!this.element) {
return;
}
this.element.parentNode.removeChild(this.element);
this.hotspot = null;
};
var SquareEl = function (hotspot, color) {
HotSpotEl.call(this, hotspot, color);
this.element = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
this.element.setAttribute('stroke-width', 2);
this.element.setAttribute('stroke', this.elStroke);
this.element.setAttribute('fill', this.elFill);
};
SquareEl.prototype = Object.create(HotSpotEl.prototype);
SquareEl.prototype.render = function () {
this.element.setAttribute('x', this.hotspot.x);
this.element.setAttribute('y', this.hotspot.y);
this.element.setAttribute('width', this.hotspot.width);
this.element.setAttribute('height', this.hotspot.height);
return this.element;
};
var EllipseEl = function (hotspot, color) {
HotSpotEl.call(this, hotspot, color);
this.element = document.createElementNS('http://www.w3.org/2000/svg', 'ellipse');
this.element.setAttribute('stroke-width', 2);
this.element.setAttribute('stroke', this.elStroke);
this.element.setAttribute('fill', this.elFill);
};
EllipseEl.prototype = Object.create(HotSpotEl.prototype);
EllipseEl.prototype.render = function () {
this.element.setAttribute('cx', this.hotspot.centerX);
this.element.setAttribute('cy', this.hotspot.centerY);
this.element.setAttribute('rx', this.hotspot.radiusX);
this.element.setAttribute('ry', this.hotspot.radiusY);
return this.element;
};
var PolygonEl = function (hotspot, color) {
HotSpotEl.call(this, hotspot, color);
this.element = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
this.element.setAttribute('stroke-width', 2);
this.element.setAttribute('stroke', this.elStroke);
this.element.setAttribute('fill', this.elFill);
};
PolygonEl.prototype = Object.create(HotSpotEl.prototype);
PolygonEl.prototype.render = function () {
var pointsPaired = [];
this.hotspot.points.forEach(function (point) {
pointsPaired.push(point.join(','));
});
this.element.setAttribute(
'points',
pointsPaired.join(' ')
);
return this.element;
};
var HotSpotSelectorEl = function (color, index, selectedValue) {
this.hotSpotIndex = parseInt(index);
this.elStroke = 'rgb(' + color + ')';
this.elFill = 'rgba(' + color + ', 0.5)';
switch (selectedValue) {
case 'square':
default:
this.selectedValue = 'square';
break;
case 'circle':
this.selectedValue = 'ellipse';
break;
case 'poly':
this.selectedValue = 'polygon';
break;
}
};
HotSpotSelectorEl.prototype.render = function () {
var self = this;
this.el = document.createElement('div');
this.el.className = 'col-xs-6 col-sm-3 col-md-2';
this.el.innerHTML = '\n\
<div class="input-group">\n\
<span class="input-group-addon" id="hotspot-' + this.hotSpotIndex + '">\n\
<span class="fa fa-square fa-fw" data-hidden="true" style="color: ' + this.elStroke + '"></span>\n\
</span>\n\
<select class="form-control" aria-describedby="hotspot-' + this.hotSpotIndex + '">\n\
<option value="">Select</option>\n\
<option value="square">Square</option>\n\
<option value="ellipse">Ellipse</option>\n\
<option value="polygon">Polygon</option>\n\
</select>\n\
</div>\n\
';
$(this.el).find('select').val(this.selectedValue);
var selectShapeEvent = function (e) {
switch (this.value) {
case 'square':
//no break
case 'ellipse':
//no break
case 'polygon':
currentShapeType = this.value;
currentHotSpotIndex = self.hotSpotIndex;
break;
default:
break;
}
};
$(this.el).on('click', selectShapeEvent);
$(this.el).find('select').on('change', selectShapeEvent);
return this.el;
};
var colors = [
'66, 113, 181',
'254, 142, 22',
'69, 199, 240',
'188, 214, 49',
'214, 49, 115',
'215, 215, 215',
'144, 175, 221',
'174, 134, 64',
'79, 146, 66',
'244, 235, 36',
'237, 32, 36',
'59, 59, 59',
'247, 189, 226'
];
var getPointOnImage = function (x, y) {
var pointerPosition = {
left: x + window.scrollX,
top: y + window.scrollY
},
canvasOffset = {
x: canvas.getBoundingClientRect().x + window.scrollX,
y: canvas.getBoundingClientRect().y + window.scrollY
};
return {
x: Math.round(pointerPosition.left - canvasOffset.x),
y: Math.round(pointerPosition.top - canvasOffset.y)
};
};
var startCanvas = function () {
var newHotSpotEl = null,
pressingShift = false;
document.addEventListener('keydown', function (e) {
if (e.keyCode === 16) {
pressingShift = true;
}
}, false);
document.addEventListener('keyup', function (e) {
if (e.keyCode === 16) {
pressingShift = false;
}
}, false);
canvas.addEventListener('click', function (e) {
e.preventDefault();
}, false);
container.addEventListener('dragstart', function (e) {
e.preventDefault();
}, false);
container.addEventListener('click', function (e) {
if (shapes.length >= colors.length) {
return;
}
newHotSpotEl = draw(newHotSpotEl, e.clientX, e.clientY, pressingShift);
if (!newHotSpotEl) {
updateValues();
}
}, false);
};
var draw = function (hotSpotEl, x, y, isPressingShift) {
var pointerPosition = getPointOnImage(x, y),
hotSpot = null;
if (!hotSpotEl) {
switch (currentShapeType) {
case 'square':
//no break
case 'ellipse':
if (currentShapeType === 'ellipse') {
hotSpot = new HotSpotEllipse();
hotSpotEl = new EllipseEl(hotSpot, colors[currentHotSpotIndex]);
} else {
hotSpot = new HotSpotSquare();
hotSpotEl = new SquareEl(hotSpot, colors[currentHotSpotIndex]);
}
hotSpot.setStartPoint(pointerPosition.x, pointerPosition.y);
break;
case 'polygon':
hotSpot = new HotSpotPolygon();
hotSpotEl = new PolygonEl(hotSpot, colors[currentHotSpotIndex]);
hotSpot.addPoint(pointerPosition.x, pointerPosition.y);
break;
}
shapes[currentHotSpotIndex].remove();
shapes.splice(currentHotSpotIndex, 1, hotSpotEl);
canvas.appendChild(hotSpotEl.render());
return hotSpotEl;
}
switch (currentShapeType) {
case 'square':
//no break
case 'ellipse':
hotSpotEl.hotspot.setEndPoint(pointerPosition.x, pointerPosition.y);
hotSpotEl.render();
hotSpotEl = null;
break;
case 'polygon':
$(container).find('#hotspot-alert').text('Keed pressed the SHIFT key and click the image to close the polygon');
hotSpotEl.hotspot.addPoint(pointerPosition.x, pointerPosition.y);
hotSpotEl.render();
if (isPressingShift) {
hotSpotEl = null;
$(container).find('#hotspot-alert').text('');
}
break;
}
return hotSpotEl;
};
var updateValues = function () {
var currentHotSpotEl = shapes[currentHotSpotIndex];
if (currentHotSpotIndex === undefined) {
return;
}
if (currentHotSpotEl.hotspot instanceof HotSpotSquare) {
$('[name="hotspot_type[' + (currentHotSpotIndex + 1) + ']"]').val('square');
} else if (currentHotSpotEl.hotspot instanceof HotSpotEllipse) {
$('[name="hotspot_type[' + (currentHotSpotIndex + 1) + ']"]').val('circle');
} else if (currentHotSpotEl.hotspot instanceof HotSpotPolygon) {
$('[name="hotspot_type[' + (currentHotSpotIndex + 1) + ']"]').val('poly');
}
$('[name="hotspot_coordinates[' + (currentHotSpotIndex + 1) + ']"]').val(
currentHotSpotEl.hotspot.encode()
);
};
var loadHotSpots = function (hotSpotList) {
hotSpotList.forEach(function (hotSpotData, index) {
var hotSpot = null,
hotSpotEl = null,
color = colors[shapes.length];
switch (hotSpotData.type) {
case 'square':
hotSpot = new HotSpotSquare();
hotSpotEl = new SquareEl(hotSpot, color);
var coords = hotSpotData.coord.split('|'),
position = coords[0].split(';'),
x = parseInt(position[0]),
y = parseInt(position[1]),
width = parseInt(coords[1]),
height = parseInt(coords[2]);
hotSpot.setStartPoint(x, y);
hotSpot.setEndPoint(x + width, y + height);
break;
case 'circle':
hotSpot = new HotSpotEllipse();
hotSpotEl = new EllipseEl(hotSpot, color);
var coords = hotSpotData.coord.split('|'),
position = coords[0].split(';'),
x = parseInt(position[0] - coords[1]),
y = parseInt(position[1] - coords[2]),
width = parseInt(coords[1]) * 2,
height = parseInt(coords[2]) * 2;
hotSpot.setStartPoint(x, y);
hotSpot.setEndPoint(x + width, y + height);
break;
case 'poly':
hotSpot = new HotSpotPolygon();
hotSpotEl = new PolygonEl(hotSpot, color);
hotSpotData.coord.split('|').forEach(function (point) {
var exis = point.split(';');
hotSpot.addPoint(exis[0], exis[1]);
});
break;
}
if (hotSpotEl) {
var hotSpotSelector = new HotSpotSelectorEl(color, index, hotSpotData.type);
selectors.appendChild(hotSpotSelector.render());
canvas.appendChild(hotSpotEl.render());
shapes.push(hotSpotEl);
}
});
};
var container, canvas, selectors, currentShapeType, currentHotSpotIndex, shapes = [];
return {
init: function (questionId, imageSrc) {
if (!questionId || !imageSrc) {
return;
}
selectors = document.querySelector('#hotspot-selectors');
container = document.querySelector('#hotspot-container');
canvas = document.querySelector('#hotspot-container svg');
currentShapeType = 'square';
var xhrImage = new $.Deferred();
var image = new Image();
image.onload = function () {
xhrImage.resolve(this);
};
image.onerror = function () {
xhrImage.reject();
};
image.src = imageSrc;
var xhrHotSpots = $.get('/main/exercice/hotspot_actionscript_admin.as.php', {
modifyAnswers: parseInt(questionId)
});
$.when.apply($, [xhrImage, xhrHotSpots]).done(function (imageRequest, hotSpotsRequest) {
var imageSvg = document.createElementNS('http://www.w3.org/2000/svg', 'image');
imageSvg.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', imageRequest.src);
imageSvg.setAttribute('width', imageRequest.width);
imageSvg.setAttribute('height', imageRequest.height);
container.style.width = imageRequest.width + 'px';
canvas.setAttribute('viewBox', '0 0 ' + imageRequest.width + ' ' + imageRequest.height);
canvas.appendChild(imageSvg);
loadHotSpots(hotSpotsRequest[0].hotspots);
startCanvas();
});
}
};
})();

@ -0,0 +1,231 @@
var HotSpotSolution = (function () {
var Answer = function () {
this.x = 0;
this.y = 0;
};
var HotSpot = function () {
this.id = 0;
this.name = '';
};
var Square = function () {
HotSpot.call(this);
this.x = 0,
this.y = 0,
this.width = 0,
this.height = 0;
};
Square.prototype = Object.create(HotSpot.prototype);
var Ellipse = function () {
HotSpot.call(this);
this.centerX = 0;
this.centerY = 0;
this.radiusX = 0;
this.radiusY = 0;
};
Ellipse.prototype = Object.create(HotSpot.prototype);
var Polygon = function () {
HotSpot.call(this);
this.points = [];
};
Polygon.prototype = Object.create(HotSpot.prototype);
var config, lang, hotSpots = [], answers = [];
var CanvasSVG = function (image) {
var imageSvg = document.createElementNS('http://www.w3.org/2000/svg', 'image');
imageSvg.setAttributeNS('http://www.w3.org/1999/xlink', 'href', image.src);
imageSvg.setAttribute('width', image.width);
imageSvg.setAttribute('height', image.height);
this.el = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
this.el.setAttribute('version', '1.1');
this.el.setAttribute('viewBox', '0 0 ' + image.width + ' ' + image.height);
this.el.appendChild(imageSvg);
};
CanvasSVG.prototype.addHotSpot = function (hotSpot) {
var hotSpotSVG = null;
if (hotSpot instanceof Square) {
hotSpotSVG = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
hotSpotSVG.setAttribute('x', hotSpot.x);
hotSpotSVG.setAttribute('y', hotSpot.y);
hotSpotSVG.setAttribute('width', hotSpot.width);
hotSpotSVG.setAttribute('height', hotSpot.height);
} else if (hotSpot instanceof Ellipse) {
hotSpotSVG = document.createElementNS('http://www.w3.org/2000/svg', 'ellipse');
hotSpotSVG.setAttribute('cx', hotSpot.centerX);
hotSpotSVG.setAttribute('cy', hotSpot.centerY);
hotSpotSVG.setAttribute('rx', hotSpot.radiusX);
hotSpotSVG.setAttribute('ry', hotSpot.radiusY);
} else if (hotSpot instanceof Polygon) {
var pointsPaired = [];
hotSpot.points.forEach(function (point) {
pointsPaired.push(point.join(','));
});
hotSpotSVG = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
hotSpotSVG.setAttribute(
'points',
pointsPaired.join(' ')
);
}
if (!hotSpotSVG) {
return;
}
var color = colors[hotSpots.length - 1];
hotSpotSVG.setAttribute('stroke-width', 2);
hotSpotSVG.setAttribute('stroke', 'rgb(' + color + ')');
hotSpotSVG.setAttribute('fill', 'rgba(' + color + ', 0.75)');
this.el.appendChild(hotSpotSVG);
};
CanvasSVG.prototype.addAnswer = function (answer) {
var pointSVG = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
pointSVG.setAttribute('cx', answer.x);
pointSVG.setAttribute('cy', answer.y);
pointSVG.setAttribute('r', 15);
pointSVG.setAttribute('fill', '#00677C');
var textSVG = document.createElementNS('http://www.w3.org/2000/svg', 'text');
textSVG.setAttribute('x', answer.x);
textSVG.setAttribute('y', answer.y);
textSVG.setAttribute('dy', 5);
textSVG.setAttribute('font-family', 'sans-serif');
textSVG.setAttribute('text-anchor', 'middle');
textSVG.setAttribute('fill', 'white');
textSVG.textContent = answers.length;
this.el.appendChild(pointSVG);
this.el.appendChild(textSVG);
};
var decodeHotSpot = function (hotSpotInfo) {
var hotSpot = null,
coords = hotSpotInfo.coord.split('|');
switch (hotSpotInfo.type) {
case 'square':
var position = coords[0].split(';');
hotSpot = new Square();
hotSpot.x = parseInt(position[0]);
hotSpot.y = parseInt(position[1]);
hotSpot.width = parseInt(coords[1]);
hotSpot.height = parseInt(coords[2]);
break;
case 'circle':
var center = coords[0].split(';');
hotSpot = new Ellipse();
hotSpot.centerX = parseInt(center[0]);
hotSpot.centerY = parseInt(center[1]);
hotSpot.radiusX = parseInt(coords[1]);
hotSpot.radiusY = parseInt(coords[2]);
break;
case 'poly':
hotSpot = new Polygon();
coords.forEach(function (pairedCoord) {
var coord = pairedCoord.split(';');
hotSpot.points.push([
parseInt(coord[0]),
parseInt(coord[1])
]);
});
break;
}
return hotSpot;
};
var decodeAnswer = function (answerInfo) {
var answer = null,
coords = answerInfo.split(';');
answer = new Answer();
answer.x = coords[0];
answer.y = coords[1];
return answer;
};
var colors = [
'66, 113, 181',
'254, 142, 22',
'69, 199, 240',
'188, 214, 49',
'214, 49, 115',
'215, 215, 215',
'144, 175, 221',
'174, 134, 64',
'79, 146, 66',
'244, 235, 36',
'237, 32, 36',
'59, 59, 59'
];
var startAnswer = function (hotSpotAnswerInfo) {
var image = new Image();
image.onload = function () {
var canvasSVG = new CanvasSVG(this);
hotSpotAnswerInfo.hotspots.forEach(function (hotSpotInfo) {
var hotSpot = decodeHotSpot(hotSpotInfo);
if (!hotSpot) {
return;
}
hotSpots.push(hotSpot);
canvasSVG.addHotSpot(hotSpot);
});
hotSpotAnswerInfo.answers.forEach(function (answerInfo) {
var answer = decodeAnswer(answerInfo);
answers.push(answer);
canvasSVG.addAnswer(answer);
});
$(config.selector)
.css('width', this.width)
.append(canvasSVG.el);
};
image.src = hotSpotAnswerInfo.image;
lang = hotSpotAnswerInfo.lang;
};
return {
init: function (settings) {
config = $.extend({
questionId: 0,
exerciseId: 0,
selector: ''
}, settings);
if (!config.questionId || !config.selector) {
return;
}
var xhrHotSpotAnswers = $.getJSON('/main/exercice/hotspot_answers.as.php', {
modifyAnswers: parseInt(config.questionId),
exe_id: parseInt(config.exerciseId)
});
$.when(xhrHotSpotAnswers).done(startAnswer);
}
};
})();

@ -0,0 +1,269 @@
var HotSpotUser = (function () {
var Answer = function () {
this.x = 0;
this.y = 0;
};
var HotSpot = function () {
this.id = 0;
this.name = '';
};
HotSpot.prototype.checkPoint = function (x, y) {
return false;
};
var Square = function () {
HotSpot.call(this);
this.x = 0,
this.y = 0,
this.width = 0,
this.height = 0;
};
Square.prototype = Object.create(HotSpot.prototype);
Square.prototype.checkPoint = function (x, y) {
var left = this.x,
right = this.x + this.width,
top = this.y,
bottom = this.y + this.height;
var xIsValid = x >= left && x <= right,
yIsValid = y >= top && y <= bottom;
return xIsValid && yIsValid;
};
var Ellipse = function () {
HotSpot.call(this);
this.centerX = 0;
this.centerY = 0;
this.radiusX = 0;
this.radiusY = 0;
};
Ellipse.prototype = Object.create(HotSpot.prototype);
Ellipse.prototype.checkPoint = function (x, y) {
var dX = x - this.centerX,
dY = y - this.centerY;
return Math.pow(dX, 2) / Math.pow(this.radiusX, 2) + Math.pow(dY, 2) / Math.pow(this.radiusY, 2) <= 1;
};
var Polygon = function () {
HotSpot.call(this);
this.points = [];
};
Polygon.prototype = Object.create(HotSpot.prototype);
Polygon.prototype.checkPoint = function (x, y) {
var isInside = false;
for (var i = 0, j = this.points.length - 1; i < this.points.length; j = i++) {
var xi = this.points[i][0],
yi = this.points[i][1],
xj = this.points[j][0],
yj = this.points[j][1];
var intersect = ((yi > y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
if (intersect) {
isInside = !isInside;
}
}
return isInside;
};
var CanvasSVG = function (image) {
var imageSvg = document.createElementNS('http://www.w3.org/2000/svg', 'image');
imageSvg.setAttributeNS('http://www.w3.org/1999/xlink', 'href', image.src);
imageSvg.setAttribute('width', image.width);
imageSvg.setAttribute('height', image.height);
this.el = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
this.el.setAttribute('version', '1.1');
this.el.setAttribute('viewBox', '0 0 ' + image.width + ' ' + image.height);
this.el.appendChild(imageSvg);
this.messagesEl = document.createElement('div');
};
CanvasSVG.prototype.setEvents = function () {
var self = this;
var getPointOnImage = function (x, y) {
var pointerPosition = {
left: x + window.scrollX,
top: y + window.scrollY
},
canvasOffset = {
x: self.el.getBoundingClientRect().x + window.scrollX,
y: self.el.getBoundingClientRect().y + window.scrollY
};
return {
x: Math.round(pointerPosition.left - canvasOffset.x),
y: Math.round(pointerPosition.top - canvasOffset.y)
};
};
this.el.addEventListener('dragstart', function (e) {
e.preventDefault();
}, false);
this.el.addEventListener('click', function (e) {
e.preventDefault();
if (answers.length >= hotSpots.length) {
return;
}
var point = getPointOnImage(e.clientX, e.clientY);
var answer = new Answer();
answer.x = point.x;
answer.y = point.y;
answers.push(answer);
self.addAnswer(answer);
if (answers.length === hotSpots.length) {
self.messagesEl.textContent = lang.ExeFinished;
return;
}
self.messagesEl.textContent = lang.NextAnswer + ' ' + hotSpots[answers.length].name;
});
};
CanvasSVG.prototype.addAnswer = function (answer) {
var pointSVG = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
pointSVG.setAttribute('cx', answer.x);
pointSVG.setAttribute('cy', answer.y);
pointSVG.setAttribute('r', 15);
pointSVG.setAttribute('fill', '#00677C');
var textSVG = document.createElementNS('http://www.w3.org/2000/svg', 'text');
textSVG.setAttribute('x', answer.x);
textSVG.setAttribute('y', answer.y);
textSVG.setAttribute('dy', 5);
textSVG.setAttribute('font-family', 'sans-serif');
textSVG.setAttribute('text-anchor', 'middle');
textSVG.setAttribute('fill', 'white');
textSVG.textContent = answers.length;
this.el.appendChild(pointSVG);
this.el.appendChild(textSVG);
var hotSpot = hotSpots[answers.length - 1];
var hotspotTxt = document.createElement('input');
hotspotTxt.type = 'hidden';
hotspotTxt.name = 'hotspot[' + config.questionId + '][' + hotSpot.id + ']';
hotspotTxt.value = [answer.x, answer.y].join(';');
var choiceTxt = document.createElement('input');
choiceTxt.type = 'hidden';
choiceTxt.name = 'choice[' + config.questionId + '][' + hotSpot.id + ']';
choiceTxt.value = hotSpot.checkPoint(answer.x, answer.y) ? 1 : 0;
this.el.parentNode.appendChild(hotspotTxt);
this.el.parentNode.appendChild(choiceTxt);
};
CanvasSVG.prototype.startMessagesPanel = function () {
this.messagesEl.textContent = lang.NextAnswer + ' ' + hotSpots[0].name;
this.el.parentNode.parentNode.appendChild(this.messagesEl);
};
var decodeHotSpot = function (hotSpotInfo) {
var hotSpot = null,
coords = hotSpotInfo.coord.split('|');
switch (hotSpotInfo.type) {
case 'square':
var position = coords[0].split(';');
hotSpot = new Square();
hotSpot.x = parseInt(position[0]);
hotSpot.y = parseInt(position[1]);
hotSpot.width = parseInt(coords[1]);
hotSpot.height = parseInt(coords[2]);
break;
case 'circle':
var center = coords[0].split(';');
hotSpot = new Ellipse();
hotSpot.centerX = parseInt(center[0]);
hotSpot.centerY = parseInt(center[1]);
hotSpot.radiusX = parseInt(coords[1]);
hotSpot.radiusY = parseInt(coords[2]);
break;
case 'poly':
hotSpot = new Polygon();
coords.forEach(function (pairedCoord) {
var coord = pairedCoord.split(';');
hotSpot.points.push([
parseInt(coord[0]),
parseInt(coord[1])
]);
});
break;
}
if (hotSpot) {
hotSpot.id = parseInt(hotSpotInfo.id);
hotSpot.name = hotSpotInfo.answer;
}
return hotSpot;
};
var config, lang, hotSpots = [], answers = [];
var startQuestion = function (hotSpotQuestionInfo) {
var image = new Image();
image.onload = function () {
var canvasSVG = new CanvasSVG(this);
hotSpotQuestionInfo.hotspots.forEach(function (hotSpotInfo) {
var hotSpot = decodeHotSpot(hotSpotInfo);
if (!hotSpot) {
return;
}
hotSpots.push(hotSpot);
});
$(config.selector)
.css('width', this.width)
.append(canvasSVG.el);
canvasSVG.setEvents();
canvasSVG.startMessagesPanel();
};
image.src = hotSpotQuestionInfo.image;
lang = hotSpotQuestionInfo.lang;
};
return {
init: function (settings) {
config = $.extend({
questionId: 0,
selector: ''
}, settings);
if (!config.questionId || !config.selector) {
return;
}
var xhrHotSpotQuestion = $.getJSON('/main/exercice/hotspot_actionscript.as.php', {
modifyAnswers: parseInt(config.questionId)
});
$.when(xhrHotSpotQuestion).done(startQuestion);
}
};
})();

@ -16,32 +16,8 @@ class TestProposedAnswer extends Basic
*/
public function getConfig()
{
$config['toolbarGroups'] = array(
array('name' => 'document'),
array(
'name' => 'clipboard',
'groups' => array('clipboard', 'undo',)
),
array(
'name' => 'basicstyles',
'groups' => array('basicstyles', 'cleanup',)
),
array(
'name' => 'paragraph',
'groups' => array('list', 'indent', 'blocks', 'align')
),
array('name' => 'links'),
array('name' => 'insert'),
'/',
array('name' => 'styles'),
array('name' => 'colors'),
array('name' => 'mode'),
array('name' => 'others')
);
$config['toolbarCanCollapse'] = true;
$config['toolbarStartupExpanded'] = false;
$config['extraPlugins'] = $this->getPluginsToString();
//$config['width'] = '100';
//$config['height'] = '200';
if (api_get_setting('more_buttons_maximized_mode') != 'true') {
@ -54,54 +30,13 @@ class TestProposedAnswer extends Basic
return $config;
}
/**
* @return array
*/
public function getConditionalPlugins()
{
$plugins = array();
if (api_get_setting('show_glossary_in_documents') == 'ismanual') {
$plugins[] = 'glossary';
}
return $plugins;
}
/**
* Get the toolbar configuration when CKEditor is maximized
* @return array
*/
protected function getMaximizedToolbar()
{
return [
['NewPage', 'Templates', '-', 'Preview', 'Print'],
['Cut', 'Copy', 'Paste', 'PasteText', 'PasteFromWord'],
['Undo', 'Redo', '-', 'SelectAll', 'Find', '-', 'RemoveFormat'],
['Link', 'Unlink', 'Anchor', 'Glossary'],
[
'Image',
'Mapping',
'Video',
'Flash',
'Youtube',
'Oembed',
'Audio',
'leaflet',
'Smiley',
'SpecialChar',
'Asciimath',
'Asciisvg'
],
'/',
['Table', '-', 'CreateDiv'],
['BulletedList', 'NumberedList', 'HorizontalRule', '-', 'Outdent', 'Indent', 'Blockquote'],
['JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock'],
['Bold', 'Italic', 'Underline', 'Strike', '-', 'Subscript', 'Superscript', '-', 'TextColor', 'BGColor'],
[api_get_setting('allow_spellcheck') == 'true' ? 'Scayt' : ''],
['Styles', 'Format', 'Font', 'FontSize'],
['PageBreak', 'ShowBlocks', 'Source'],
['Toolbarswitch'],
];
return $this->getNormalToolbar();
}
/**
@ -111,18 +46,9 @@ class TestProposedAnswer extends Basic
protected function getNormalToolbar()
{
return [
[
'Maximize',
'Bold',
'Image',
'Link',
'PasteFromWord',
'Audio',
'Table',
'Subscript',
'Superscript',
'Source'
]
['Bold', 'Subscript', 'Superscript'],
['Image', 'Link', 'Audio', 'Table', 'PasteFromWord'],
['Maximize', 'Source'],
];
}
@ -132,14 +58,6 @@ class TestProposedAnswer extends Basic
*/
protected function getMinimizedToolbar()
{
return [
['Templates'],
['PasteFromWord'],
['Link'],
['Image', 'Video', 'Flash', 'Audio', 'Asciimath', 'Asciisvg'],
['Table'],
['Bold'],
['Source', 'Toolbarswitch']
];
return $this->getNormalToolbar();
}
}

Loading…
Cancel
Save