Index: lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/MonitoringAction.java =================================================================== diff -u -r509d15bcc570bff483a13152ef8c45cbae767e78 -r927cd8d0d3f34e4efbfdcaa36779240244a041b1 --- lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/MonitoringAction.java (.../MonitoringAction.java) (revision 509d15bcc570bff483a13152ef8c45cbae767e78) +++ lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/MonitoringAction.java (.../MonitoringAction.java) (revision 927cd8d0d3f34e4efbfdcaa36779240244a041b1) @@ -665,21 +665,22 @@ */ public ActionForward getLessonLearners(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, JSONException { + String searchPhrase = request.getParameter("searchPhrase"); Integer pageNumber = WebUtil.readIntParam(request, "pageNumber", true); if (pageNumber == null) { pageNumber = 1; } boolean orderAscending = WebUtil.readBooleanParam(request, "orderAscending", true); long lessonId = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); - List learners = getLessonService().getLessonLearners(lessonId, null, MonitoringAction.USER_PAGE_SIZE, - (pageNumber - 1) * MonitoringAction.USER_PAGE_SIZE, orderAscending); + List learners = getLessonService().getLessonLearners(lessonId, searchPhrase, + MonitoringAction.USER_PAGE_SIZE, (pageNumber - 1) * MonitoringAction.USER_PAGE_SIZE, orderAscending); JSONArray learnersJSON = new JSONArray(); for (User learner : learners) { learnersJSON.put(WebUtil.userToJSON(learner)); } - Integer learnerCount = getMonitoringService().getCountLearnersCompletedLesson(lessonId); + Integer learnerCount = getLessonService().getCountLessonLearners(lessonId, searchPhrase); JSONObject responseJSON = new JSONObject(); responseJSON.put("learners", learnersJSON); @@ -1310,22 +1311,33 @@ } /** - * Gives suggestions when a Monitor searches for a Learner in Sequence and Learners tabs. + * Gives suggestions when a Monitor searches for Learners and staff members. */ - public ActionForward autocompleteMonitoringLearners(ActionMapping mapping, ActionForm form, - HttpServletRequest request, HttpServletResponse response) throws Exception { + public ActionForward autocomplete(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws Exception { long lessonId = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); String searchPhrase = request.getParameter("term"); + boolean isOrganisationSearch = WebUtil.readStrParam(request, "scope").equalsIgnoreCase("organisation"); - List learners = getLessonService().getLessonLearners(lessonId, searchPhrase, - MonitoringAction.USER_PAGE_SIZE, null, true); + Collection users = null; + if (isOrganisationSearch) { + // search for Learners in the organisation + Map result = getLessonService().getUsersWithLessonParticipation(lessonId, Role.LEARNER, + searchPhrase, MonitoringAction.USER_PAGE_SIZE, null, true); + users = result.keySet(); + } else { + // search for Learners in the lesson + users = getLessonService().getLessonLearners(lessonId, searchPhrase, MonitoringAction.USER_PAGE_SIZE, null, + true); + } + JSONArray responseJSON = new JSONArray(); - for (User learner : learners) { - JSONObject learnerJSON = new JSONObject(); - learnerJSON.put("label", learner.getFirstName() + " " + learner.getLastName() + " " + learner.getLogin()); - learnerJSON.put("value", learner.getUserId()); + for (User user : users) { + JSONObject userJSON = new JSONObject(); + userJSON.put("label", user.getFirstName() + " " + user.getLastName() + " " + user.getLogin()); + userJSON.put("value", user.getUserId()); - responseJSON.put(learnerJSON); + responseJSON.put(userJSON); } response.setContentType("application/json;charset=utf-8"); Index: lams_monitoring/web/css/monitorLesson.css =================================================================== diff -u -r509d15bcc570bff483a13152ef8c45cbae767e78 -r927cd8d0d3f34e4efbfdcaa36779240244a041b1 --- lams_monitoring/web/css/monitorLesson.css (.../monitorLesson.css) (revision 509d15bcc570bff483a13152ef8c45cbae767e78) +++ lams_monitoring/web/css/monitorLesson.css (.../monitorLesson.css) (revision 927cd8d0d3f34e4efbfdcaa36779240244a041b1) @@ -163,23 +163,23 @@ float: right; } -#classDialogTable td { +#classDialogTable > tbody > tr > td { vertical-align: top; } #classDialogTable #classMonitorSearchRow { height: 23px; } -#classDialogTable #classSearchPhrase { +.dialogSearchPhrase { width: 90%; } -#classDialogTable #classSearchPhraseIcon { +.dialogSearchPhraseIcon { margin-top: 2px; } -#classDialogTable #classSearchPhraseClear { +.dialogSearchPhraseClear { visibility: hidden; margin-top: 3px; cursor: pointer; Index: lams_monitoring/web/includes/javascript/monitorLesson.js =================================================================== diff -u -r509d15bcc570bff483a13152ef8c45cbae767e78 -r927cd8d0d3f34e4efbfdcaa36779240244a041b1 --- lams_monitoring/web/includes/javascript/monitorLesson.js (.../monitorLesson.js) (revision 509d15bcc570bff483a13152ef8c45cbae767e78) +++ lams_monitoring/web/includes/javascript/monitorLesson.js (.../monitorLesson.js) (revision 927cd8d0d3f34e4efbfdcaa36779240244a041b1) @@ -34,7 +34,8 @@ // double tap support tapTimeout = 500, - lastTap = 0, + lastTapTime = 0, + lastTapTarget = null, // after first entering of branching in old SVGs layout gets a bit broken // setting this property fixes it @@ -181,7 +182,7 @@ }); // sets up dialog for editing class - $('#classDialog').dialog({ + var classDialog = $('#classDialog').dialog({ 'autoOpen' : false, 'height' : 435, 'width' : 700, @@ -209,32 +210,35 @@ }); - // search for users with the term the Monitor entered - $("#classSearchPhrase").autocomplete({ - 'source' : LAMS_URL + "monitoring/monitoring.do?method=autocompleteMonitoringLearners&lessonID=" + lessonId, + // search for users in the organisation with the term the Monitor entered + $('.dialogSearchPhrase', classDialog).autocomplete({ + 'source' : LAMS_URL + "monitoring/monitoring.do?method=autocomplete&scope=organisation&lessonID=" + lessonId, 'delay' : 700, 'select' : function(event, ui){ - var phraseField = $(this); + var phraseField = $(this), + dialog = $('#classDialog'); // learner's ID in ui.item.value is not used here phraseField.val(ui.item.label); - $('#classSearchPhraseClear').css('visibility', 'visible'); + // show the "clear search phrase" button + $('.dialogSearchPhraseClear', dialog).css('visibility', 'visible'); // reset to page 1 - $('#classDialog').dialog('option','LearnerAjaxProperties').pageNumber = 1; + dialog.dialog('option','LearnerAjaxProperties').pageNumber = 1; showClassDialog('Learner'); return false; } }) // run the real search when the Monitor presses Enter .keypress(function(e){ if (e.which == 13) { - var phraseField = $(this); + var phraseField = $(this), + dialog = $('#classDialog'); phraseField.autocomplete("close"); if (phraseField.val()) { - $('#classSearchPhraseClear').css('visibility', 'visible'); + $('.dialogSearchPhraseClear', dialog).css('visibility', 'visible'); } // reset to page 1 - $('#classDialog').dialog('option','LearnerAjaxProperties').pageNumber = 1; + dialog.dialog('option','LearnerAjaxProperties').pageNumber = 1; showClassDialog('Learner'); } }); @@ -275,7 +279,7 @@ } }; - showLearnerGroupDialog(ajaxProperties, LABELS.LESSON_GROUP_DIALOG_CLASS, false, false, true); + showLearnerGroupDialog(ajaxProperties, LABELS.LESSON_GROUP_DIALOG_CLASS, true, false, false, true); } /** @@ -568,9 +572,9 @@ */ function initSequenceTab(){ // initialise lesson dialog - $('#learnerGroupDialog').dialog({ + var learnerGroupDialog = $('#learnerGroupDialog').dialog({ 'autoOpen' : false, - 'height' : 365, + 'height' : 390, 'width' : 400, 'minWidth' : 400, 'modal' : true, @@ -592,7 +596,7 @@ 'id' : 'learnerGroupDialogForceCompleteButton', 'class' : 'learnerGroupDialogSelectableButton', 'click' : function() { - var selectedLearner = $('#learnerGroupList div.dialogListItemSelected'); + var selectedLearner = $('.dialogList div.dialogListItemSelected', this); // make sure there is only one selected learner if (selectedLearner.length == 1) { // go to "force complete" mode, similar to draggin user to an activity @@ -615,7 +619,7 @@ 'id' : 'learnerGroupDialogViewButton', 'class' : 'learnerGroupDialogSelectableButton', 'click' : function() { - var selectedLearner = $('#learnerGroupList div.dialogListItemSelected'); + var selectedLearner = $('.dialogList div.dialogListItemSelected', this); if (selectedLearner.length == 1) { // open pop up with user progress in the given activity openPopUp(selectedLearner.attr('viewUrl'), "LearnActivity", 600, 800, true); @@ -627,7 +631,7 @@ 'id' : 'learnerGroupDialogEmailButton', 'class' : 'learnerGroupDialogSelectableButton', 'click' : function() { - var selectedLearner = $('#learnerGroupList div.dialogListItemSelected'); + var selectedLearner = $('.dialogList div.dialogListItemSelected', this); if (selectedLearner.length == 1) { showEmailDialog(selectedLearner.attr('userId')); } @@ -641,8 +645,42 @@ } } ] + }); + + // search for users with the term the Monitor entered + $('.dialogSearchPhrase', learnerGroupDialog).autocomplete({ + 'source' : LAMS_URL + "monitoring/monitoring.do?method=autocomplete&scope=lesson&lessonID=" + lessonId, + 'delay' : 700, + 'select' : function(event, ui){ + var phraseField = $(this), + dialog = $('#learnerGroupDialog'); + // learner's ID in ui.item.value is not used here + phraseField.val(ui.item.label); + $('.dialogSearchPhraseClear', dialog).css('visibility', 'visible'); + // reset to page 1 + dialog.dialog('option','ajaxProperties').pageNumber = 1; + showLearnerGroupDialog(); + return false; + } + }) + // run the real search when the Monitor presses Enter + .keypress(function(e){ + if (e.which == 13) { + var phraseField = $(this), + dialog = $('#learnerGroupDialog'); + + phraseField.autocomplete("close"); + if (phraseField.val()) { + $('.dialogSearchPhraseClear', dialog).css('visibility', 'visible'); + } + // reset to page 1 + dialog.dialog('option','ajaxProperties').pageNumber = 1; + showLearnerGroupDialog(); + } }); + + // small info box on Sequence tab, activated when the tab is showed $('#sequenceInfoDialog').dialog({ 'autoOpen' : false, @@ -711,8 +749,8 @@ }); // search for users with the term the Monitor entered - $("#sequenceSearchPhrase").autocomplete( { - 'source' : LAMS_URL + "monitoring/monitoring.do?method=autocompleteMonitoringLearners&lessonID=" + lessonId, + $("#sequenceSearchPhrase").autocomplete({ + 'source' : LAMS_URL + "monitoring/monitoring.do?method=autocomplete&scope=lesson&lessonID=" + lessonId, 'delay' : 700, 'select' : function(event, ui){ // put the learner first name, last name and login into the box @@ -1175,7 +1213,7 @@ 'flaFormat' : flaFormat } }; - showLearnerGroupDialog(ajaxProperties, activity.title, true, usersViewable, false); + showLearnerGroupDialog(ajaxProperties, activity.title, false, true, usersViewable, false); }); } @@ -1251,7 +1289,7 @@ 'lessonID' : lessonId } }; - showLearnerGroupDialog(ajaxProperties, LABELS.LEARNER_FINISHED_DIALOG_TITLE, true, false, false); + showLearnerGroupDialog(ajaxProperties, LABELS.LEARNER_FINISHED_DIALOG_TITLE, false, true, false, false); }); } } @@ -1394,10 +1432,9 @@ */ function fillClassList(role, disableCreator) { var dialog = $('#classDialog'), - tableID = 'class' + role + 'Table', - table = $('#' + tableID, dialog), + table = $('#class' + role + 'Table', dialog), list = $('.dialogList', table).empty(), - searchPhrase = role == 'Learner' ? $('#classSearchPhrase', table).val() : null, + searchPhrase = role == 'Learner' ? $('.dialogSearchPhrase', table).val().trim() : null, ajaxProperties = dialog.dialog('option', role + 'AjaxProperties'), users = null, userCount = null; @@ -1422,7 +1459,7 @@ } // add properties for this call only - if (searchPhrase && searchPhrase.trim() == ''){ + if (!searchPhrase){ searchPhrase = null; } ajaxProperties.data.searchPhrase = searchPhrase; @@ -1471,7 +1508,7 @@ } }); - colorDialogList(tableID); + colorDialogList(table); } /** @@ -1581,7 +1618,7 @@ function initLearnersTab() { // search for users with the term the Monitor entered $("#learnersSearchPhrase").autocomplete( { - 'source' : LAMS_URL + "monitoring/monitoring.do?method=autocompleteMonitoringLearners&lessonID=" + lessonId, + 'source' : LAMS_URL + "monitoring/monitoring.do?method=autocomplete&scope=lesson&lessonID=" + lessonId, 'delay' : 700, 'select' : function(event, ui){ // learner's ID in ui.item.value is not used here @@ -1684,8 +1721,8 @@ } // calculate currently visible page numbers - var pageStartIndex = pageNumber - 5; - var pageEndIndex = pageNumber + 5 - Math.min(pageStartIndex,0); + var pageStartIndex = pageNumber - 5, + pageEndIndex = pageNumber + 5 - Math.min(pageStartIndex,0); shiftLearnerProgressPageHeader(pageStartIndex, pageEndIndex, pageNumber); } @@ -1792,27 +1829,40 @@ /** - * Clears previous run search for phrase. + * Clears previous run search for phrase, in Learners tab. */ function learnersClearSearchPhrase(){ $('#learnersSearchPhrase').val('').autocomplete("close"); loadLearnerProgressPage(1, ''); $('#learnersSearchPhraseClear').hide(); } + /** - * Clears previous run search for phrase. + * Clears previous run search for phrase, in Edit Class dialog. */ function classClearSearchPhrase(){ - $('#classSearchPhrase').val('').autocomplete("close"); - $('#classDialog').dialog('option', 'LearnerAjaxProperties').pageNumber = 1; + var dialog = $('#classDialog'); + $('.dialogSearchPhrase', dialog).val('').autocomplete("close"); + dialog.dialog('option', 'LearnerAjaxProperties').data.pageNumber = 1; showClassDialog('Learner'); - $('#classSearchPhraseClear').css('visibility', 'hidden'); + $('.dialogSearchPhraseClear', dialog).css('visibility', 'hidden'); } +/** + * Clears previous run search for phrase, in Learner Group dialogs. + */ +function learnerGroupClearSearchPhrase(){ + var dialog = $('#learnerGroupDialog'); + $('.dialogSearchPhrase', dialog).val('').autocomplete("close"); + dialog.dialog('option', 'ajaxProperties').data.pageNumber = 1; + showLearnerGroupDialog(); + $('.dialogSearchPhraseClear', dialog).css('visibility', 'hidden'); +} + //********** COMMON FUNCTIONS ********** /** @@ -1861,7 +1911,7 @@ /** * Show a dialog with user list and optional Force Complete and View Learner buttons. */ -function showLearnerGroupDialog(ajaxProperties, dialogTitle, allowForceComplete, allowView, allowEmail) { +function showLearnerGroupDialog(ajaxProperties, dialogTitle, allowSearch, allowForceComplete, allowView, allowEmail) { var learnerGroupDialog = $('#learnerGroupDialog'), learnerGroupList = $('.dialogList', learnerGroupDialog).empty(), // no parameters provided? just work on what we saved @@ -1875,6 +1925,7 @@ allowForceComplete = learnerGroupDialog.dialog('option', 'allowForceComplete'); allowView = learnerGroupDialog.dialog('option', 'allowView'); allowEmail = learnerGroupDialog.dialog('option', 'allowEmail'); + allowSearch = $('#learnerGroupSearchRow', learnerGroupDialog).is(':visible'); } else { // add few standard properties to ones provided by method calls ajaxProperties = $.extend(true, ajaxProperties, { @@ -1886,6 +1937,8 @@ 'orderAscending' : true } }); + + $('#learnerGroupSearchRow', learnerGroupDialog).css('display', allowSearch ? 'table-row' : 'none'); } var pageNumber = ajaxProperties.data.pageNumber; @@ -1896,12 +1949,15 @@ learnerCount = response.learnerCount; }; + var searchPhrase = allowSearch ? $('.dialogSearchPhrase', learnerGroupDialog).val().trim() : null; + ajaxProperties.data.searchPhrase = searchPhrase; + // make the call $.ajax(ajaxProperties); // did all users already drift away to an another activity or there was an error? // close the dialog and refresh the main screen - if (!learnerCount) { + if (!learnerCount && !searchPhrase) { if (isRefresh) { learnerGroupDialog.dialog('close'); } @@ -1912,8 +1968,8 @@ // did some users already drift away to an another activity? // move back until you get a page with any users var maxPageNumber = Math.ceil(learnerCount / 10); - if (pageNumber > maxPageNumber) { - shiftLearnerGroup(-1); + if (maxPageNumber > 0 && pageNumber > maxPageNumber) { + shiftLearnerGroupList(-1); return; } @@ -1951,7 +2007,7 @@ } }); - colorDialogList('learnerGroupDialog'); + colorDialogList(learnerGroupDialog); if (!isRefresh) { // show buttons depending on parameters @@ -2049,7 +2105,7 @@ * Colours a list of users */ function colorDialogList(parent) { - $('#' + parent + ' .dialogList div.dialogListItem').each(function(userIndex, userDiv){ + $('.dialogList div.dialogListItem', parent).each(function(userIndex, userDiv){ // every odd learner has different background $(userDiv).css('background-color', userIndex % 2 ? '#dfeffc' : 'inherit'); }); @@ -2142,12 +2198,17 @@ function dblTap(elem, dblClickFunction) { // double tap detection on mobile devices; it works also for mouse clicks elem.tap(function(event){ - var currentTime = new Date().getTime(), - tapLength = currentTime - lastTap; - if (tapLength < tapTimeout && tapLength > 0) { - event.preventDefault(); - dblClickFunction(event); - } - lastTap = currentTime; + // is the second click on the same element as the first one? + if (event.currentTarget == lastTapTarget) { + // was the second click quick enough after the first one? + var currentTime = new Date().getTime(), + tapLength = currentTime - lastTapTime; + if (tapLength < tapTimeout && tapLength > 0) { + event.preventDefault(); + dblClickFunction(event); + } + } + lastTapTime = currentTime; + lastTapTarget = event.currentTarget; }); } \ No newline at end of file Index: lams_monitoring/web/monitor.jsp =================================================================== diff -u -r509d15bcc570bff483a13152ef8c45cbae767e78 -r927cd8d0d3f34e4efbfdcaa36779240244a041b1 --- lams_monitoring/web/monitor.jsp (.../monitor.jsp) (revision 509d15bcc570bff483a13152ef8c45cbae767e78) +++ lams_monitoring/web/monitor.jsp (.../monitor.jsp) (revision 927cd8d0d3f34e4efbfdcaa36779240244a041b1) @@ -510,6 +510,22 @@
+ + + + +
+ + + + + +
- - -