Index: lams_admin/web/WEB-INF/lams.tld =================================================================== diff -u -rc5b655c3c11fa9d9b1d76e0ef602acf6363e45f9 -r9a772f5ba1954a3a719a19e7ae237b6b09dc76ef --- lams_admin/web/WEB-INF/lams.tld (.../lams.tld) (revision c5b655c3c11fa9d9b1d76e0ef602acf6363e45f9) +++ lams_admin/web/WEB-INF/lams.tld (.../lams.tld) (revision 9a772f5ba1954a3a719a19e7ae237b6b09dc76ef) @@ -13,28 +13,36 @@ - Output the basic URL for the current webapp. e.g. http://server/lams/tool/nb11/ - Base URL for the current web app + Output the Server URL as defined in the lams.xml configuration file. + LAMS URL - WebAppURL - org.lamsfoundation.lams.web.tag.WebAppURLTag + LAMSURL + org.lamsfoundation.lams.web.tag.LAMSURLTag empty - Output a random number for the learner and passon flash movies to communicate directly. - generate unique ID + Converts text from \n or \r\n to <BR> before rendering + Converts text from \n or \r\n to <BR> before rendering - generateID - org.lamsfoundation.lams.web.tag.GenerateIDTag + out + org.lamsfoundation.lams.web.tag.MultiLinesOutputTag empty - Output a random number for the learner and passon flash movies to communicate directly. - id + Converts text from \n or \r\n to <BR> before rendering + value + true + + true + + + + Converts text from \n or \r\n to <BR> before rendering + escapeHtml false true @@ -44,6 +52,26 @@ + Render html tag with direction and language + Render html tag with direction and language + + + html + org.lamsfoundation.lams.web.tag.HtmlTag + JSP + + + Render html tag with direction and language + xhtml + false + + true + + + + + + Get the configuration value for the specified key Configuration value @@ -64,28 +92,17 @@ - Output the Server URL as defined in the lams.xml configuration file. - LAMS URL + Output a random number for the learner and passon flash movies to communicate directly. + generate unique ID - LAMSURL - org.lamsfoundation.lams.web.tag.LAMSURLTag + generateID + org.lamsfoundation.lams.web.tag.GenerateIDTag empty - - - - Render html tag with direction and language - Render html tag with direction and language - - - html - org.lamsfoundation.lams.web.tag.HtmlTag - JSP - - Render html tag with direction and language - xhtml + Output a random number for the learner and passon flash movies to communicate directly. + id false true @@ -95,26 +112,29 @@ - Converts text from \n or \r\n to <BR> before rendering - Converts text from \n or \r\n to <BR> before rendering + Output the basic URL for the current webapp. e.g. http://server/lams/tool/nb11/ + Base URL for the current web app - out - org.lamsfoundation.lams.web.tag.MultiLinesOutputTag + WebAppURL + org.lamsfoundation.lams.web.tag.WebAppURLTag empty - - Converts text from \n or \r\n to <BR> before rendering - value - true + + - true + Converts role name into form usable as message resources key + Converts role name into form usable as message resources key + + + role + org.lamsfoundation.lams.web.tag.RoleTag + empty - - Converts text from \n or \r\n to <BR> before rendering - escapeHtml - false + Converts role name into form usable as message resources key + role + true true @@ -167,17 +187,17 @@ - Converts role name into form usable as message resources key - Converts role name into form usable as message resources key + Output details from the shared session UserDTO object + user details - role - org.lamsfoundation.lams.web.tag.RoleTag + user + org.lamsfoundation.lams.web.tag.UserTag empty - Converts role name into form usable as message resources key - role + Output details from the shared session UserDTO object + property true true @@ -213,27 +233,7 @@ - - Output details from the shared session UserDTO object - user details - - - user - org.lamsfoundation.lams.web.tag.UserTag - empty - - - Output details from the shared session UserDTO object - property - true - - true - - - - - STRUTS-textarea org.lamsfoundation.lams.web.tag.MultiLinesTextareaTag @@ -289,11 +289,6 @@ true - index - false - true - - indexed false true @@ -466,6 +461,10 @@ ImgButtonWrapper /WEB-INF/tags/ImgButtonWrapper.tag + + + TextSearch + /WEB-INF/tags/TextSearch.tag textarea Index: lams_admin/web/WEB-INF/tags/TextSearch.tag =================================================================== diff -u --- lams_admin/web/WEB-INF/tags/TextSearch.tag (revision 0) +++ lams_admin/web/WEB-INF/tags/TextSearch.tag (revision 9a772f5ba1954a3a719a19e7ae237b6b09dc76ef) @@ -0,0 +1,136 @@ +<% +/**************************************************************** + * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ + + /** + * TextSearch.tag + * Author: Marcin Cieslak + * Description: Displays form for creating text search conditions. + */ + + %> +<%@ tag body-content="scriptless" %> +<%@ taglib uri="tags-core" prefix="c" %> +<%@ taglib uri="tags-fmt" prefix="fmt" %> +<%@ taglib uri="tags-html" prefix="html" %> +<%@ taglib uri="tags-lams" prefix="lams" %> + +<%-- Required attributes --%> +<%@ attribute name="sessionMapID" required="true" rtexprvalue="true" %> +<%@ attribute name="wrapInFormTag" required="true" rtexprvalue="true" %> + +<%-- Optional attributes --%> +<%@ attribute name="action" required="false" rtexprvalue="true" %> +<%@ attribute name="formID" required="false" rtexprvalue="true" %> +<%@ attribute name="headingLabelKey" required="false" rtexprvalue="true" %> +<%@ attribute name="allWordsLabelKey" required="false" rtexprvalue="true" %> +<%@ attribute name="phraseLabelKey" required="false" rtexprvalue="true" %> +<%@ attribute name="anyWordsLabelKey" required="false" rtexprvalue="true" %> +<%@ attribute name="excludedWordsLabelKey" required="false" rtexprvalue="true" %> +<%@ attribute name="saveButtonLabelKey" required="false" rtexprvalue="true" %> +<%@ attribute name="cancelButtonLabelKey" required="false" rtexprvalue="true" %> +<%@ attribute name="cancelAction" required="false" rtexprvalue="true" %> + +<%-- Default value for message key --%> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +

+ + + + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + + + + + + \ No newline at end of file Index: lams_central/build.xml =================================================================== diff -u -rc234c64ad9ff9d713f6d8e3331d0c20075e49303 -r9a772f5ba1954a3a719a19e7ae237b6b09dc76ef --- lams_central/build.xml (.../build.xml) (revision c234c64ad9ff9d713f6d8e3331d0c20075e49303) +++ lams_central/build.xml (.../build.xml) (revision 9a772f5ba1954a3a719a19e7ae237b6b09dc76ef) @@ -165,6 +165,7 @@ + Index: lams_central/conf/language/lams/ApplicationResources.properties =================================================================== diff -u -r5bd95ffef22a2fdc60414cfd9cfb22968b88c13b -r9a772f5ba1954a3a719a19e7ae237b6b09dc76ef --- lams_central/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 5bd95ffef22a2fdc60414cfd9cfb22968b88c13b) +++ lams_central/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 9a772f5ba1954a3a719a19e7ae237b6b09dc76ef) @@ -232,4 +232,69 @@ videorecorder.instructions.fck =Click the record button to start and stop recording. Once a recording is completed, you can review it by clicking the play button. When ready to add the video, click the tick button. -#======= End labels: Exported 224 labels for en AU ===== +index.planner =Planner +planner.title =Pedagogical Planner +label.description =Description +planner.saved =All acitvities were saved successfully. +planner.not.saved =There were errors in activities. Not all acitvities were saved. +error.planner.title.blank =Sequence title must not be blank. +label.planner.not.supported =This activity does not support the planner. +button.planner.save =Save template +button.planner.preview =Preview +button.planner.view.full.author =View in Full Author + +label.planner.grouping.type=Group type +label.planner.grouping.type.random=Random grouping +label.planner.grouping.type.chosen=Choose in Monitor +label.planner.grouping.type.learner.choice=Learner's choice +label.planner.grouping.number.of.groups=Number of groups +label.planner.grouping.number.of.learners=Number of learners +error.planner.grouping.number.integer=Provided value must be a positive integer number. +label.planner.grouping.equal.group.size=Equal group sizes +msg.planner.not.saved =Are you sure you want to close? If you have not saved the design, changes you have made will be lost. +label.planner.editing.advice=Editing advice +label.planner.branch.empty =This branch is empty. +label.planner.branch=Branch +label.planner.branch.default=(default) +label.planner.option=Option + +button.planner.editor.open=Open editor +msg.planner.node.locked=This node is locked. You can not edit it. +button.planner.save.node=Save node +label.planner.create.subnode=Create subnode +label.planner.edit.node=Edit node +label.planner.root.node=Planner +msg.planner.open.template=This node opens a planner template. +msg.planner.remove.node=Remove node +label.planner.empty.subnode=There are no subnodes defined. +label.planner.description.brief=Brief description (for parent node) +label.planner.description.full=Full description (for self) +label.planner.root.choose=Choose a planner from one of the following activity categories: +msg.planner.remove.warning=Are you sure you want to remove this node and all of its subnodes? + +label.planner.node.type=This node: +label.planner.node.type.subnodes=has subnodes +label.planner.node.type.template=opens a template +label.planner.remove.file=Remove file +label.planner.change.file=Change file: +label.planner.uploaded.template=Uploaded template file: +msg.planner.move.node.up=Move node up +msg.planner.move.node.down=Move node down +label.planner.choose.file=Choose a template file: +error.planner.node.title.blank=Node title must not be blank. +error.planner.repository=There was a file respository error. Template file was not saved. +error.planner.file.empty=You must upload a file. +error.planner.file.bad.extension=Template file must have a ZIP or LAS extension. + +error.planner.tools=There were tool errors. Learning design could not be retrieved. +error.planner.learning.design.retrieve=Learning design could not be retrieved. +error.planner.file.open=There was an error while opening the template file. +error.planner.editor=There was an error while opening the editor. +error.planner.export=There was an error while exporting the node. +error.planner.import=There was an error while importing the node. +label.planner.export=Export node +label.planner.import=Import node + +label.planner.import.instruction=Please select Pedagogical Planner node to import. The import file must be a .zip file exported from LAMS 2 or above. +label.planner.grouping.view.students=View students before selection +#======= End labels: Exported 222 labels for en AU ===== Index: lams_central/conf/language/lams/ApplicationResources_en_AU.properties =================================================================== diff -u -r5bd95ffef22a2fdc60414cfd9cfb22968b88c13b -r9a772f5ba1954a3a719a19e7ae237b6b09dc76ef --- lams_central/conf/language/lams/ApplicationResources_en_AU.properties (.../ApplicationResources_en_AU.properties) (revision 5bd95ffef22a2fdc60414cfd9cfb22968b88c13b) +++ lams_central/conf/language/lams/ApplicationResources_en_AU.properties (.../ApplicationResources_en_AU.properties) (revision 9a772f5ba1954a3a719a19e7ae237b6b09dc76ef) @@ -232,4 +232,69 @@ videorecorder.instructions.fck =Click the record button to start and stop recording. Once a recording is completed, you can review it by clicking the play button. When ready to add the video, click the tick button. -#======= End labels: Exported 224 labels for en AU ===== +index.planner =Planner +planner.title =Pedagogical Planner +label.description =Description +planner.saved =All acitvities were saved successfully. +planner.not.saved =There were errors in activities. Not all acitvities were saved. +error.planner.title.blank =Sequence title must not be blank. +label.planner.not.supported =This activity does not support the planner. +button.planner.save =Save template +button.planner.preview =Preview +button.planner.view.full.author =View in Full Author + +label.planner.grouping.type=Group type +label.planner.grouping.type.random=Random grouping +label.planner.grouping.type.chosen=Choose in Monitor +label.planner.grouping.type.learner.choice=Learner's choice +label.planner.grouping.number.of.groups=Number of groups +label.planner.grouping.number.of.learners=Number of learners +error.planner.grouping.number.integer=Provided value must be a positive integer number. +label.planner.grouping.equal.group.size=Equal group sizes +msg.planner.not.saved =Are you sure you want to close? If you have not saved the design, changes you have made will be lost. +label.planner.editing.advice=Editing advice +label.planner.branch.empty =This branch is empty. +label.planner.branch=Branch +label.planner.branch.default=(default) +label.planner.option=Option + +button.planner.editor.open=Open editor +msg.planner.node.locked=This node is locked. You can not edit it. +button.planner.save.node=Save node +label.planner.create.subnode=Create subnode +label.planner.edit.node=Edit node +label.planner.root.node=Planner +msg.planner.open.template=This node opens a planner template. +msg.planner.remove.node=Remove node +label.planner.empty.subnode=There are no subnodes defined. +label.planner.description.brief=Brief description (for parent node) +label.planner.description.full=Full description (for self) +label.planner.root.choose=Choose a planner from one of the following activity categories: +msg.planner.remove.warning=Are you sure you want to remove this node and all of its subnodes? + +label.planner.node.type=This node: +label.planner.node.type.subnodes=has subnodes +label.planner.node.type.template=opens a template +label.planner.remove.file=Remove file +label.planner.change.file=Change file: +label.planner.uploaded.template=Uploaded template file: +msg.planner.move.node.up=Move node up +msg.planner.move.node.down=Move node down +label.planner.choose.file=Choose a template file: +error.planner.node.title.blank=Node title must not be blank. +error.planner.repository=There was a file respository error. Template file was not saved. +error.planner.file.empty=You must upload a file. +error.planner.file.bad.extension=Template file must have a ZIP or LAS extension. + +error.planner.tools=There were tool errors. Learning design could not be retrieved. +error.planner.learning.design.retrieve=Learning design could not be retrieved. +error.planner.file.open=There was an error while opening the template file. +error.planner.editor=There was an error while opening the editor. +error.planner.export=There was an error while exporting the node. +error.planner.import=There was an error while importing the node. +label.planner.export=Export node +label.planner.import=Import node + +label.planner.import.instruction=Please select Pedagogical Planner node to import. The import file must be a .zip file exported from LAMS 2 or above. +label.planner.grouping.view.students=View students before selection +#======= End labels: Exported 222 labels for en AU ===== Index: lams_central/conf/xdoclet/taglibs.xml =================================================================== diff -u -rc697b5c30ab742ab453859355b35cd518856334f -r9a772f5ba1954a3a719a19e7ae237b6b09dc76ef --- lams_central/conf/xdoclet/taglibs.xml (.../taglibs.xml) (revision c697b5c30ab742ab453859355b35cd518856334f) +++ lams_central/conf/xdoclet/taglibs.xml (.../taglibs.xml) (revision 9a772f5ba1954a3a719a19e7ae237b6b09dc76ef) @@ -65,7 +65,7 @@ fck-editor - /WEB-INF/jstl/tlds/FCKeditor.tld + /WEB-INF/fckeditor/tlds/FCKeditor.tld Index: lams_central/src/java/org/lamsfoundation/lams/authoring/service/AuthoringService.java =================================================================== diff -u -rc697b5c30ab742ab453859355b35cd518856334f -r9a772f5ba1954a3a719a19e7ae237b6b09dc76ef --- lams_central/src/java/org/lamsfoundation/lams/authoring/service/AuthoringService.java (.../AuthoringService.java) (revision c697b5c30ab742ab453859355b35cd518856334f) +++ lams_central/src/java/org/lamsfoundation/lams/authoring/service/AuthoringService.java (.../AuthoringService.java) (revision 9a772f5ba1954a3a719a19e7ae237b6b09dc76ef) @@ -534,8 +534,8 @@ } if (design != null) { /* - * only the user who is editing the design may unlock it - */ + * only the user who is editing the design may unlock it + */ if (design.getEditOverrideUser().equals(user)) { design.setEditOverrideLock(false); design.setEditOverrideUser(null); @@ -1363,17 +1363,18 @@ HashSet newCompeteces = new HashSet(); Set oldCompetences = originalLearningDesign.getCompetences(); - for (Competence competence : oldCompetences) { - Competence newCompetence = competence.createCopy(competence); - newCompetence.setLearningDesign(newLearningDesign); + if (oldCompetences != null) { + for (Competence competence : oldCompetences) { + Competence newCompetence = competence.createCopy(competence); + newCompetence.setLearningDesign(newLearningDesign); - // check for existing competences to prevent duplicates - if (competenceDAO.getCompetence(newLearningDesign, newCompetence.getTitle()) == null) { - competenceDAO.saveOrUpdate(newCompetence); + // check for existing competences to prevent duplicates + if (competenceDAO.getCompetence(newLearningDesign, newCompetence.getTitle()) == null) { + competenceDAO.saveOrUpdate(newCompetence); + } + newCompeteces.add(newCompetence); } - newCompeteces.add(newCompetence); } - if (newLearningDesign.getCompetences() != null) { if (!insert) { newLearningDesign.getCompetences().clear(); Index: lams_central/src/java/org/lamsfoundation/lams/util/CentralConstants.java =================================================================== diff -u -rc697b5c30ab742ab453859355b35cd518856334f -r9a772f5ba1954a3a719a19e7ae237b6b09dc76ef --- lams_central/src/java/org/lamsfoundation/lams/util/CentralConstants.java (.../CentralConstants.java) (revision c697b5c30ab742ab453859355b35cd518856334f) +++ lams_central/src/java/org/lamsfoundation/lams/util/CentralConstants.java (.../CentralConstants.java) (revision 9a772f5ba1954a3a719a19e7ae237b6b09dc76ef) @@ -155,6 +155,8 @@ public static final String PARAM_CREATE_SUBNODE = "createSubnode"; + public static final String PARAM_IMPORT_NODE = "importNode"; + public static final String PARAM_UID = "uid"; public static final String CENTRAL_TOOL_CONTENT_HANDLER_BEAN_NAME = "centralToolContentHandler"; Index: lams_central/src/java/org/lamsfoundation/lams/web/planner/PedagogicalPlannerAction.java =================================================================== diff -u -r5a30100855d83534e76db8dec0d0b603a1a1ded8 -r9a772f5ba1954a3a719a19e7ae237b6b09dc76ef --- lams_central/src/java/org/lamsfoundation/lams/web/planner/PedagogicalPlannerAction.java (.../PedagogicalPlannerAction.java) (revision 5a30100855d83534e76db8dec0d0b603a1a1ded8) +++ lams_central/src/java/org/lamsfoundation/lams/web/planner/PedagogicalPlannerAction.java (.../PedagogicalPlannerAction.java) (revision 9a772f5ba1954a3a719a19e7ae237b6b09dc76ef) @@ -23,15 +23,21 @@ /* $$Id$$ */ package org.lamsfoundation.lams.web.planner; +import java.io.BufferedInputStream; import java.io.File; +import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import java.util.Set; import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @@ -76,15 +82,22 @@ import org.lamsfoundation.lams.usermanagement.service.IUserManagementService; import org.lamsfoundation.lams.util.CentralConstants; import org.lamsfoundation.lams.util.CentralToolContentHandler; +import org.lamsfoundation.lams.util.Configuration; +import org.lamsfoundation.lams.util.ConfigurationKeys; import org.lamsfoundation.lams.util.FileUtil; +import org.lamsfoundation.lams.util.FileUtilException; import org.lamsfoundation.lams.util.MessageService; import org.lamsfoundation.lams.util.WebUtil; +import org.lamsfoundation.lams.util.zipfile.ZipFileUtil; +import org.lamsfoundation.lams.util.zipfile.ZipFileUtilException; import org.lamsfoundation.lams.web.action.LamsDispatchAction; import org.lamsfoundation.lams.web.session.SessionManager; import org.lamsfoundation.lams.web.util.AttributeNames; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; +import com.thoughtworks.xstream.XStream; + /** * Action managing Pedagogical Planner base page and non-tool activities. * @@ -105,6 +118,7 @@ private static final String FILE_EXTENSION_ZIP = ".zip"; private static final String FILE_EXTENSION_LAS = ".las"; + // ActionForwards private static final String FORWARD_TEMPLATE = "template"; private static final String FORWARD_PREVIEW = "preview"; private static final String FORWARD_SEQUENCE_CHOOSER = "sequenceChooser"; @@ -123,8 +137,9 @@ private static MessageService messageService; private static PedagogicalPlannerDAO pedagogicalPlannerDAO; private static ToolContentHandler contentHandler; + private static final String PEDAGOGICAL_PLANNER_DAO_BEAN_NAME = "pedagogicalPlannerDAO"; - // Error messages used in class + // Keys of error messages used in this class. They are ment to be displayed for user. private static final String ERROR_KEY_TOOL_ERRORS = "error.planner.tools."; private static final String ERROR_KEY_NODE_TITLE_BLANK = "error.planner.node.title.blank"; private static final String ERROR_KEY_REPOSITORY = "error.planner.repository"; @@ -133,7 +148,10 @@ private static final String ERROR_KEY_FILE_OPEN = "error.planner.file.open"; private static final String ERROR_KEY_LEARNING_DESIGN_COULD_NOT_BE_RETRIEVED = "error.planner.learning.design.retrieve"; private static final String ERROR_KEY_EDITOR = "error.planner.editor"; + private static final String ERROR_KEY_EXPORT = "error.planner.export"; + private static final String ERROR_KEY_IMPORT = "error.planner.import"; + // Error messages used in this class. They are ment to be thrown. private static final String ERROR_USER_NOT_FOUND = "User not found."; private static final String ERROR_NOT_PROPER_FILE = "The sequence template does not exist or is not a proper file."; private static final String ERROR_TOO_MANY_OPTIONS = "Number of options in options activity is limited to " @@ -145,112 +163,71 @@ private static Logger log = Logger.getLogger(PedagogicalPlannerAction.class); - private static final String PEDAGOGICAL_PLANNER_DAO_BEAN_NAME = "pedagogicalPlannerDAO"; + // Paths used in templateBase.jsp private static final String IMAGE_PATH_GATE = "images/stop.gif"; private static final String PATH_ACTIVITY_NO_PLANNER_SUPPORT = "/pedagogical_planner/defaultActivityForm.jsp"; private static final String IMAGE_PATH_GROUPING = "images/grouping.gif"; + // Parts of paths used in importing/exporting nodes + + private static final String NODE_FILE_NAME = "node.xml"; + private static final String DIR_CONTENT = "content"; + private static final String DIR_TEMPLATES = "template"; + + private static final String EXPORT_NODE_FOLDER_SUFFIX = "export_node"; + private static final String EXPORT_NODE_CONTENT_ZIP_PREFIX = "content_"; + private static final String HEADER_CONTENT_DISPOSITION = "Content-Disposition"; + private static final String RESPONSE_CONTENT_TYPE_DOWNLOAD = "application/x-download"; + private static final String ENCODING_UTF_8 = "UTF-8"; + private static final String DIR_UPLOADED_NODE_SUFFIX = "_uploaded_node"; + private static final String EXPORT_NODE_ZIP_PREFIX = "lams_planner_node_"; + + private static final int FILE_COPY_BUFFER_SIZE = 1024; + @Override /** - * Go straight to start(). + * Go straight to open sequence node. */ public ActionForward unspecified(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { return openSequenceNode(mapping, form, request, response); } + /*----------------------- TEMPLATE CHOOSER METHODS --------------------*/ + /** * The main method for opening and parsing template (chosen learning desing). * * @param mapping * @param form * @param request - * @param response + * @param fileUuid + * @param fileName * @return * @throws ServletException - * @throws IOException */ private ActionForward openTemplate(ActionMapping mapping, ActionForm form, HttpServletRequest request, Long fileUuid, String fileName) throws ServletException { - // Get the learning design template zip file + ActionMessages errors = new ActionMessages(); - File designFile = null; - - try { - designFile = copyFileFromRepository(fileUuid, fileName); - } catch (Exception e) { - PedagogicalPlannerAction.log.error(e); - errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(PedagogicalPlannerAction.ERROR_KEY_FILE_OPEN)); + // Open the learning design stored in the repository. + LearningDesign learningDesign = importLearningDesign(fileUuid, fileName, errors); + if (!errors.isEmpty()) { saveErrors(request, errors); + // If anything goes wrong, open the root node. Errors will be displayed at top. + // This approach is used widely in this action. return openSequenceNode(mapping, form, request, (Long) null); } - if (!designFile.exists() || designFile.isDirectory()) { - PedagogicalPlannerAction.log.error(PedagogicalPlannerAction.ERROR_NOT_PROPER_FILE); - errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(PedagogicalPlannerAction.ERROR_KEY_FILE_OPEN)); - saveErrors(request, errors); - return openSequenceNode(mapping, form, request, (Long) null); - } - HttpSession session = SessionManager.getSession(); - UserDTO userDto = (UserDTO) session.getAttribute(AttributeNames.USER); - User user = (User) getUserManagementService().findById(User.class, userDto.getUserID()); - if (user == null) { - throw new ServletException(PedagogicalPlannerAction.ERROR_USER_NOT_FOUND); - } - List toolsErrorMsgs = new ArrayList(); - Long learningDesignID = null; - LearningDesign learningDesign = null; - List learningDesignErrorMsgs = new ArrayList(); - // Extract the template - - try { - Object[] ldResults = getExportService().importLearningDesign(designFile, user, null, toolsErrorMsgs, ""); - designFile.delete(); - learningDesignID = (Long) ldResults[0]; - learningDesignErrorMsgs = (List) ldResults[1]; - toolsErrorMsgs = (List) ldResults[2]; - learningDesign = getAuthoringService().getLearningDesign(learningDesignID); - } catch (ImportToolContentException e) { - PedagogicalPlannerAction.log.error(e); - errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage( - PedagogicalPlannerAction.ERROR_KEY_LEARNING_DESIGN_COULD_NOT_BE_RETRIEVED)); - saveErrors(request, errors); - return openSequenceNode(mapping, form, request, (Long) null); - } - - if ((learningDesignID == null || learningDesignID.longValue() == -1) && learningDesignErrorMsgs.size() == 0) { - errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage( - PedagogicalPlannerAction.ERROR_KEY_LEARNING_DESIGN_COULD_NOT_BE_RETRIEVED)); - saveErrors(request, errors); - return openSequenceNode(mapping, form, request, (Long) null); - } - if (learningDesignErrorMsgs.size() > 0) { - for (String error : learningDesignErrorMsgs) { - PedagogicalPlannerAction.log.error(error); - } - errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage( - PedagogicalPlannerAction.ERROR_KEY_LEARNING_DESIGN_COULD_NOT_BE_RETRIEVED)); - saveErrors(request, errors); - return openSequenceNode(mapping, form, request, (Long) null); - } - if (toolsErrorMsgs.size() > 0) { - for (String error : toolsErrorMsgs) { - PedagogicalPlannerAction.log.error(error); - } - errors - .add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage( - PedagogicalPlannerAction.ERROR_KEY_TOOL_ERRORS)); - return openSequenceNode(mapping, form, request, (Long) null); - } - List activities = new ArrayList(); - // create DTOs that hold all the necessary information of the activities + // Create DTOs that hold all the necessary information of the activities Activity activity = learningDesign.getFirstActivity(); + PedagogicalPlannerAction.log.debug("Parsing learning design activities"); try { while (activity != null) { - // Iterate through all the activities + // Iterate through all the activities, detecting type of each one addActivityToPlanner(learningDesign, activities, activity); Transition transitionTo = activity.getTransitionTo(); if (transitionTo == null) { @@ -267,6 +244,7 @@ return openSequenceNode(mapping, form, request, (Long) null); } + // Recalculate how many activities actually support the planner int activitySupportingPlannerCount = 0; for (PedagogicalPlannerActivityDTO activityDTO : activities) { if (activityDTO.getSupportsPlanner()) { @@ -278,7 +256,7 @@ planner.setActivitySupportingPlannerCount(activitySupportingPlannerCount); planner.setSequenceTitle(learningDesign.getTitle()); planner.setActivities(activities); - planner.setLearningDesignID(learningDesignID); + planner.setLearningDesignID(learningDesign.getLearningDesignId()); // Some additional options for submitting activity forms; should be moved to configuration file in the future planner.setSendInPortions(false); @@ -290,99 +268,6 @@ } /** - * Saves additional, non tool bound template details - currently only the title. - * - * @param mapping - * @param form - * @param request - * @param response - * @return - * @throws IOException - */ - public ActionForward saveSequenceDetails(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws IOException { - String sequenceTitle = WebUtil.readStrParam(request, CentralConstants.PARAM_SEQUENCE_TITLE, true); - Long learningDesignID = WebUtil.readLongParam(request, CentralConstants.PARAM_LEARNING_DESIGN_ID); - Integer callAttemptedID = WebUtil.readIntParam(request, CentralConstants.PARAM_CALL_ATTEMPTED_ID); - // We send a message in format "&"; it is then parsed in JavaScript - String responseSuffix = PedagogicalPlannerAction.CHAR_AMPERSAND + callAttemptedID; - - if (StringUtils.isEmpty(sequenceTitle)) { - String blankTitleError = getMessageService().getMessage(CentralConstants.ERROR_PLANNER_TITLE_BLANK); - writeAJAXResponse(response, blankTitleError + responseSuffix); - } else { - LearningDesign learningDesign = getAuthoringService().getLearningDesign(learningDesignID); - learningDesign.setTitle(sequenceTitle); - getAuthoringService().saveLearningDesign(learningDesign); - writeAJAXResponse(response, PedagogicalPlannerAction.STRING_OK + responseSuffix); - } - return null; - } - - public ActionForward initGrouping(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) { - PedagogicalPlannerGroupingForm plannerForm = (PedagogicalPlannerGroupingForm) form; - Long groupingId = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_CONTENT_ID); - Grouping grouping = getAuthoringService().getGroupingById(groupingId); - plannerForm.fillForm(grouping); - return mapping.findForward(CentralConstants.FORWARD_GROUPING); - } - - public ActionForward saveOrUpdateGroupingForm(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) { - PedagogicalPlannerGroupingForm plannerForm = (PedagogicalPlannerGroupingForm) form; - ActionMessages errors = plannerForm.validate(); - if (errors.isEmpty()) { - Grouping grouping = getAuthoringService().getGroupingById(plannerForm.getToolContentID()); - if (grouping.isRandomGrouping()) { - RandomGrouping randomGrouping = (RandomGrouping) grouping; - Integer number = StringUtils.isEmpty(plannerForm.getNumberOfGroups()) ? null : Integer - .parseInt(plannerForm.getNumberOfGroups()); - randomGrouping.setNumberOfGroups(number); - - number = StringUtils.isEmpty(plannerForm.getLearnersPerGroup()) ? null : Integer.parseInt(plannerForm - .getLearnersPerGroup()); - randomGrouping.setLearnersPerGroup(number); - } else if (grouping.isLearnerChoiceGrouping()) { - LearnerChoiceGrouping learnerChoiceGrouping = (LearnerChoiceGrouping) grouping; - Integer number = StringUtils.isEmpty(plannerForm.getNumberOfGroups()) ? null : Integer - .parseInt(plannerForm.getNumberOfGroups()); - learnerChoiceGrouping.setNumberOfGroups(number); - - number = StringUtils.isEmpty(plannerForm.getLearnersPerGroup()) ? null : Integer.parseInt(plannerForm - .getLearnersPerGroup()); - learnerChoiceGrouping.setLearnersPerGroup(number); - learnerChoiceGrouping.setEqualNumberOfLearnersPerGroup(plannerForm.getEqualGroupSizes()); - } else { - Integer number = StringUtils.isEmpty(plannerForm.getNumberOfGroups()) ? null : Integer - .parseInt(plannerForm.getNumberOfGroups()); - grouping.setMaxNumberOfGroups(number); - } - } else { - saveMessages(request, errors); - } - return mapping.findForward(CentralConstants.FORWARD_GROUPING); - } - - public ActionForward startPreview(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) { - Long learningDesignID = WebUtil.readLongParam(request, CentralConstants.PARAM_LEARNING_DESIGN_ID); - HttpSession session = SessionManager.getSession(); - UserDTO userDto = (UserDTO) session.getAttribute(AttributeNames.USER); - - // Start preview the same way as in authoring - Lesson lesson = getMonitoringService().initializeLessonForPreview("Preview", null, learningDesignID, - userDto.getUserID(), null, false, false, false); - getMonitoringService().createPreviewClassForLesson(userDto.getUserID(), lesson.getLessonId()); - - getMonitoringService().startLesson(lesson.getLessonId(), userDto.getUserID()); - String newPath = mapping.findForward(PedagogicalPlannerAction.FORWARD_PREVIEW).getPath(); - newPath = newPath + PedagogicalPlannerAction.CHAR_AMPERSAND + AttributeNames.PARAM_LESSON_ID - + PedagogicalPlannerAction.CHAR_EQUALS + lesson.getLessonId(); - return new ActionForward(newPath, true); - } - - /** * Recognises activitiy type and creates proper DTO for web pages use. For branching and options it can be called * recursevely. * @@ -397,6 +282,8 @@ */ private PedagogicalPlannerActivityDTO addActivityToPlanner(LearningDesign learningDesign, List activities, Activity activity) throws ServletException { + PedagogicalPlannerAction.log.debug("Parsing activity: " + activity.getTitle()); + // Check if the activity is contained in some complex activity: branching or options boolean isNested = activity.getParentActivity() != null && (activity.getParentActivity().isBranchingActivity() || activity.isOptionsActivity()); @@ -537,6 +424,7 @@ } addedDTO.setLastNestedActivity(true); } else { + // If unknown/unsupported activity addedDTO = new PedagogicalPlannerActivityDTO(null, activity.getTitle(), false, PedagogicalPlannerAction.PATH_ACTIVITY_NO_PLANNER_SUPPORT, activity.getLibraryActivityUiImage(), null, null); @@ -545,51 +433,119 @@ return addedDTO; } + /** + * Starts a lesson preview, both in sequence chooser and in template base. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws ServletException + */ + public ActionForward startPreview(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws ServletException { + + Long learningDesignID = WebUtil.readLongParam(request, CentralConstants.PARAM_LEARNING_DESIGN_ID, true); + if (learningDesignID == null) { + Long nodeUid = WebUtil.readLongParam(request, CentralConstants.PARAM_UID); + PedagogicalPlannerSequenceNode node = getPedagogicalPlannerDAO().getByUid(nodeUid); + ActionMessages errors = new ActionMessages(); + LearningDesign learningDesign = importLearningDesign(node.getFileUuid(), node.getFileName(), errors); + if (!errors.isEmpty()) { + ActionMessage error = (ActionMessage) errors.get().next(); + String errorMessage = getMessageService().getMessage(error.getKey()); + throw new ServletException(errorMessage); + } + learningDesignID = learningDesign.getLearningDesignId(); + } + HttpSession session = SessionManager.getSession(); + UserDTO userDto = (UserDTO) session.getAttribute(AttributeNames.USER); + + // Start preview the same way as in authoring + PedagogicalPlannerAction.log.debug("Opening preview for learnind design id: " + learningDesignID); + Lesson lesson = getMonitoringService().initializeLessonForPreview("Preview", null, learningDesignID, + userDto.getUserID(), null, false, false, false); + getMonitoringService().createPreviewClassForLesson(userDto.getUserID(), lesson.getLessonId()); + + getMonitoringService().startLesson(lesson.getLessonId(), userDto.getUserID()); + String newPath = mapping.findForward(PedagogicalPlannerAction.FORWARD_PREVIEW).getPath(); + newPath = newPath + PedagogicalPlannerAction.CHAR_AMPERSAND + AttributeNames.PARAM_LESSON_ID + + PedagogicalPlannerAction.CHAR_EQUALS + lesson.getLessonId(); + return new ActionForward(newPath, true); + } + + /** + * Reads UID of the node and goes straight to + * {@link #openSequenceNode(ActionMapping, ActionForm, HttpServletRequest, Long)} + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws IOException + * @throws ServletException + */ public ActionForward openSequenceNode(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { Long nodeUid = WebUtil.readLongParam(request, CentralConstants.PARAM_UID, true); return openSequenceNode(mapping, form, request, nodeUid); } + /** + * Opens a sequence node and fill the necessary data into DTO and form. + * + * @param mapping + * @param form + * @param request + * @param nodeUid + * @return + * @throws ServletException + */ public ActionForward openSequenceNode(ActionMapping mapping, ActionForm form, HttpServletRequest request, Long nodeUid) throws ServletException { + // Only SysAdmin can open the editor Boolean isSysAdmin = request.isUserInRole(Role.SYSADMIN); Boolean edit = WebUtil.readBooleanParam(request, CentralConstants.PARAM_EDIT, false); edit &= isSysAdmin; - + // Do we display the root (top) node or an existing one PedagogicalPlannerSequenceNode node = null; if (nodeUid == null) { node = getPedagogicalPlannerDAO().getRootNode(); } else { node = getPedagogicalPlannerDAO().getByUid(nodeUid); if (!edit && node.getFileUuid() != null) { + // If we are not in the edit mode and we open a node containing a template, then we open the template return openTemplate(mapping, form, request, node.getFileUuid(), node.getFileName()); } } + PedagogicalPlannerAction.log.debug("Opening sequence node with UID: " + nodeUid); + + // Fill the DTO List titlePath = getPedagogicalPlannerDAO().getTitlePath(node); PedagogicalPlannerSequenceNodeDTO dto = new PedagogicalPlannerSequenceNodeDTO(node, titlePath); + // Additional DTO parameters Boolean createSubnode = WebUtil.readBooleanParam(request, CentralConstants.PARAM_CREATE_SUBNODE, false); + Boolean importNode = WebUtil.readBooleanParam(request, CentralConstants.PARAM_IMPORT_NODE, false); dto.setCreateSubnode(createSubnode); dto.setEdit(edit); dto.setIsSysAdmin(isSysAdmin); + dto.setImportNode(importNode); request.setAttribute(CentralConstants.ATTR_NODE, dto); if (edit) { + // If we are in edit mode, the node form is displayed, requiring additional parameters PedagogicalPlannerSequenceNodeForm nodeForm = (PedagogicalPlannerSequenceNodeForm) form; - nodeForm.setNodeType(node.getFileName() == null ? PedagogicalPlannerSequenceNodeForm.NODE_TYPE_SUBNODES - : PedagogicalPlannerSequenceNodeForm.NODE_TYPE_TEMPLATE); - nodeForm.setRemoveFile(false); - nodeForm.setTitle(dto.getTitle()); - nodeForm.setBriefDescription(dto.getBriefDescription()); - nodeForm.setFullDescription(dto.getFullDescription()); - nodeForm.setFileUuid(node.getFileUuid()); if (createSubnode) { - if (node.getParent() == null) { + // We create a new node, rather than edit the existing one + if (node.getContentFolderId() == null) { try { - String contentFolderId = getAuthoringService().generateUniqueContentFolder(); + // If it's a new top level node, we create an uniuqe ID + String contentFolderId = FileUtil.generateUniqueContentFolderID(); nodeForm.setContentFolderId(contentFolderId); } catch (Exception e) { PedagogicalPlannerAction.log.error(e); @@ -602,20 +558,42 @@ return openSequenceNode(mapping, form, request, (Long) null); } } else { - nodeForm.setContentFolderId(node.getParent().getContentFolderId()); + // Whole node tree share the same content folder ID + nodeForm.setContentFolderId(node.getContentFolderId()); } + } else if (!importNode) { + // We fill the form with necessary data + nodeForm.setNodeType(node.getFileName() == null ? PedagogicalPlannerSequenceNodeForm.NODE_TYPE_SUBNODES + : PedagogicalPlannerSequenceNodeForm.NODE_TYPE_TEMPLATE); + nodeForm.setRemoveFile(false); + nodeForm.setTitle(dto.getTitle()); + nodeForm.setBriefDescription(dto.getBriefDescription()); + nodeForm.setFullDescription(dto.getFullDescription()); + nodeForm.setFileUuid(node.getFileUuid()); } } return mapping.findForward(PedagogicalPlannerAction.FORWARD_SEQUENCE_CHOOSER); } + /** + * Saves the created/edited sequence node. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws IOException + * @throws ServletException + */ public ActionForward saveSequenceNode(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { Long nodeUid = WebUtil.readLongParam(request, CentralConstants.PARAM_UID, true); PedagogicalPlannerSequenceNode node = null; PedagogicalPlannerSequenceNodeForm nodeForm = (PedagogicalPlannerSequenceNodeForm) form; if (nodeUid == null) { + // It's a new subnode node = new PedagogicalPlannerSequenceNode(); Long parentUid = nodeForm.getParentUid() == 0 ? null : nodeForm.getParentUid(); if (parentUid != null) { @@ -624,10 +602,13 @@ } node.setOrder(getPedagogicalPlannerDAO().getNextOrderId(parentUid)); } else { + // It's an existing node node = getPedagogicalPlannerDAO().getByUid(nodeUid); nodeUid = node.getUid(); } + PedagogicalPlannerAction.log.debug("Saving sequence node with UID: " + nodeUid); + // If anything goes wrong, we need to put back these values String title = nodeForm.getTitle(); String briefDescription = nodeForm.getBriefDescription(); String fullDescription = nodeForm.getFullDescription(); @@ -640,6 +621,7 @@ node.setBriefDescription(briefDescription); node.setContentFolderId(nodeForm.getContentFolderId()); + // Different properties are set, depending on node type: with subnodes or template if (PedagogicalPlannerSequenceNodeForm.NODE_TYPE_SUBNODES.equals(nodeForm.getNodeType())) { if (node.getFileUuid() != null) { getContentHandler().deleteFile(node.getFileUuid()); @@ -652,22 +634,35 @@ node.setFileName(null); node.setFileUuid(null); node.setFullDescription(null); - } else if (nodeForm.getFile() != null) { + } else if (nodeForm.getFile() != null && nodeForm.getFile().getFileSize() > 0) { FormFile file = nodeForm.getFile(); InputStream inputStream = file.getInputStream(); String fileName = file.getFileName(); String type = file.getContentType(); + + PedagogicalPlannerAction.log.debug("Uploading to repository file: " + fileName); + // Upload to repository NodeKey nodeKey = getContentHandler().uploadFile(inputStream, fileName, type, IToolContentHandler.TYPE_OFFLINE); if (node.getFileUuid() != null) { getContentHandler().deleteFile(node.getFileUuid()); } + + // If there were subnodes, we delete them now + Iterator subnodeIter = node.getSubnodes().iterator(); + while (subnodeIter.hasNext()) { + PedagogicalPlannerSequenceNode subnode = subnodeIter.next(); + subnodeIter.remove(); + getPedagogicalPlannerDAO().removeNode(subnode); + } + node.setFileUuid(nodeKey.getUuid()); node.setFileName(fileName); node.setFullDescription(null); } getPedagogicalPlannerDAO().saveOrUpdateNode(node); + // If it was a new subnode, we need to retrieved the assigned UID nodeUid = node.getUid(); } catch (RepositoryCheckedException e) { @@ -676,11 +671,15 @@ PedagogicalPlannerAction.log.error(e); } } + + // If something went wrong and the new subnode was not saved, + // we need to inform the following method of that fact boolean createSubnode = false; if (nodeUid == null) { nodeUid = node.getParent() == null ? null : node.getParent().getUid(); createSubnode = true; } + // Set the parameters, but do not return yet openSequenceNode(mapping, form, request, nodeUid); if (!errors.isEmpty()) { @@ -698,44 +697,75 @@ return mapping.findForward(PedagogicalPlannerAction.FORWARD_SEQUENCE_CHOOSER); } + /** + * Validates node form fields. + * + * @param node + * @param form + * @return + */ private ActionMessages validateNodeForm(PedagogicalPlannerSequenceNode node, PedagogicalPlannerSequenceNodeForm form) { ActionMessages errors = new ActionMessages(); + // Title must not be blank if (StringUtils.isEmpty(form.getTitle())) { errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage( PedagogicalPlannerAction.ERROR_KEY_NODE_TITLE_BLANK)); } + // Template must a proper file if (PedagogicalPlannerSequenceNodeForm.NODE_TYPE_TEMPLATE.equals(form.getNodeType()) && node.getFileName() == null) { - if (form.getFile() == null || form.getFile().getFileSize() == 0) { - errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage( - PedagogicalPlannerAction.ERROR_KEY_FILE_EMPTY)); - } else { - String fileName = form.getFile().getFileName(); - boolean badExtension = false; - if (fileName.length() >= 4) { - String extension = fileName.substring(fileName.length() - 4); - if (!(extension.equalsIgnoreCase(PedagogicalPlannerAction.FILE_EXTENSION_LAS) || extension - .equalsIgnoreCase(PedagogicalPlannerAction.FILE_EXTENSION_ZIP))) { - badExtension = true; - } - } else { + errors.add(validateFormFile(form)); + } + return errors; + } + + /** + * Validates form file. Used both for templates and exported nodes. + * + * @param form + * @return + */ + private ActionMessages validateFormFile(PedagogicalPlannerSequenceNodeForm form) { + ActionMessages errors = new ActionMessages(); + if (form.getFile() == null || form.getFile().getFileSize() == 0) { + errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(PedagogicalPlannerAction.ERROR_KEY_FILE_EMPTY)); + } else { + String fileName = form.getFile().getFileName(); + boolean badExtension = false; + if (fileName.length() >= 4) { + String extension = fileName.substring(fileName.length() - 4); + if (!(extension.equalsIgnoreCase(PedagogicalPlannerAction.FILE_EXTENSION_LAS) || extension + .equalsIgnoreCase(PedagogicalPlannerAction.FILE_EXTENSION_ZIP))) { badExtension = true; } - if (badExtension) { - errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage( - PedagogicalPlannerAction.ERROR_KEY_FILE_BAD_EXTENSION)); - } - + } else { + badExtension = true; } + if (badExtension) { + errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage( + PedagogicalPlannerAction.ERROR_KEY_FILE_BAD_EXTENSION)); + } } return errors; } + /** + * Removes the selected node and all of its subnodes + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws IOException + * @throws ServletException + */ public ActionForward removeSequenceNode(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { Long nodeUid = WebUtil.readLongParam(request, CentralConstants.PARAM_UID); PedagogicalPlannerSequenceNode node = getPedagogicalPlannerDAO().getByUid(nodeUid); Long parentUid = node.getParent() == null ? null : node.getParent().getUid(); + PedagogicalPlannerAction.log.debug("Removing sequence node with UID" + nodeUid); getPedagogicalPlannerDAO().removeNode(node); return openSequenceNode(mapping, form, request, parentUid); } @@ -767,11 +797,359 @@ return openSequenceNode(mapping, form, request, parentUid); } - private File copyFileFromRepository(Long fileUuid, String fileName) throws RepositoryCheckedException, IOException { - InputStream inputStream = getContentHandler().getFileNode(fileUuid).getFile(); - File file = new File(FileUtil.TEMP_DIR, fileName); - FileOutputStream fileOutputStream = new FileOutputStream(file); - byte[] data = new byte[1024]; + /** + * Exports the selected node to a ZIP file. Method is based on a similar one for exporting learning designs. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws ServletException + * @throws IOException + */ + public ActionForward exportNode(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws ServletException, IOException { + Long nodeUid = WebUtil.readLongParam(request, CentralConstants.PARAM_UID); + ActionMessages errors = new ActionMessages(); + + PedagogicalPlannerAction.log.debug("Exporting sequence node with UID" + nodeUid); + String zipFilePath = null; + // Different browsers handle stream downloads differently LDEV-1243 + String filename = null; + try { + zipFilePath = exportNode(nodeUid); + + // get only filename + String zipfile = FileUtil.getFileName(zipFilePath); + + // replace spaces (" ") with underscores ("_") + + zipfile = zipfile.replaceAll(" ", "_"); + + // write zip file as response stream. + + filename = FileUtil.encodeFilenameForDownload(request, zipfile); + + PedagogicalPlannerAction.log.debug("Final filename to export: " + filename); + + response.setContentType(PedagogicalPlannerAction.RESPONSE_CONTENT_TYPE_DOWNLOAD); + // response.setContentType("application/zip"); + response.setHeader(PedagogicalPlannerAction.HEADER_CONTENT_DISPOSITION, "attachment;filename=" + filename); + } catch (Exception e) { + PedagogicalPlannerAction.log.error(e); + errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(PedagogicalPlannerAction.ERROR_KEY_EXPORT)); + saveErrors(request, errors); + return openSequenceNode(mapping, form, request, nodeUid); + } + InputStream in = null; + ServletOutputStream out = null; + try { + in = new BufferedInputStream(new FileInputStream(zipFilePath)); + out = response.getOutputStream(); + int count = 0; + + int ch; + while ((ch = in.read()) != -1) { + out.write((char) ch); + count++; + } + PedagogicalPlannerAction.log.debug("Wrote out " + count + " bytes"); + response.setContentLength(count); + out.flush(); + } finally { + /* + * If anything goes wrong, we can not display it nicely for the user. Once response.getOutputStream() was + * called to write the file data, we can not forward to a JSP page anymore. Maybe there is a way to avoid + * it, but currently we are simply throwing an error. So no "catch" clause. + */ + if (in != null) { + in.close(); // very important + } + } + return null; + } + + /** + * The proper method for exporting nodes. + * + * @param nodeUid + * @return + * @throws ZipFileUtilException + * @throws FileUtilException + * @throws IOException + * @throws RepositoryCheckedException + */ + private String exportNode(Long nodeUid) throws ZipFileUtilException, FileUtilException, IOException, + RepositoryCheckedException { + if (nodeUid != null) { + + String rootDir = FileUtil.createTempDirectory(PedagogicalPlannerAction.EXPORT_NODE_FOLDER_SUFFIX); + String contentDir = FileUtil.getFullPath(rootDir, PedagogicalPlannerAction.DIR_CONTENT); + FileUtil.createDirectory(contentDir); + + String nodeFileName = FileUtil.getFullPath(contentDir, PedagogicalPlannerAction.NODE_FILE_NAME); + Writer nodeFile = new OutputStreamWriter(new FileOutputStream(nodeFileName), + PedagogicalPlannerAction.ENCODING_UTF_8); + + PedagogicalPlannerSequenceNode node = getPedagogicalPlannerDAO().getByUid(nodeUid); + // exporting XML + XStream designXml = new XStream(); + designXml.toXML(node, nodeFile); + nodeFile.close(); + + PedagogicalPlannerAction.log.debug("Node xml export success"); + + // Copy templates' ZIP files from repository + File templateDir = new File(contentDir, PedagogicalPlannerAction.DIR_TEMPLATES); + exportSubnodeTemplates(node, templateDir); + + // create zip file for fckeditor unique content folder + String targetZipFileName = PedagogicalPlannerAction.EXPORT_NODE_CONTENT_ZIP_PREFIX + + node.getContentFolderId() + PedagogicalPlannerAction.FILE_EXTENSION_ZIP; + String secureDir = Configuration.get(ConfigurationKeys.LAMS_EAR_DIR) + File.separator + + FileUtil.LAMS_WWW_DIR + File.separator + FileUtil.LAMS_WWW_SECURE_DIR; + String nodeContentDir = FileUtil.getFullPath(secureDir, node.getContentFolderId()); + + if (!FileUtil.isEmptyDirectory(nodeContentDir, true)) { + PedagogicalPlannerAction.log.debug("Create export node content target zip file. File name is " + + targetZipFileName); + ZipFileUtil.createZipFile(targetZipFileName, nodeContentDir, contentDir); + } else { + PedagogicalPlannerAction.log.debug("No such directory (or empty directory): " + nodeContentDir); + } + + // zip file name with full path + targetZipFileName = PedagogicalPlannerAction.EXPORT_NODE_ZIP_PREFIX + node.getTitle() + + PedagogicalPlannerAction.FILE_EXTENSION_ZIP; + ; + PedagogicalPlannerAction.log + .debug("Create export node content zip file. File name is " + targetZipFileName); + // create zip file and return zip full file name + return ZipFileUtil.createZipFile(targetZipFileName, contentDir, rootDir); + } + return null; + } + + /** + * Imports a zipped node. Thi method is based on a similar one for importing learning designs. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws ServletException + */ + public ActionForward importNode(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws ServletException { + + PedagogicalPlannerSequenceNodeForm nodeForm = (PedagogicalPlannerSequenceNodeForm) form; + ActionMessages errors = validateFormFile(nodeForm); + + if (errors.isEmpty()) { + try { + String uploadPath = FileUtil.createTempDirectory(PedagogicalPlannerAction.DIR_UPLOADED_NODE_SUFFIX); + String fileName = nodeForm.getFile().getFileName(); + File importFile = new File(uploadPath + fileName); + PedagogicalPlannerAction.log.debug("Importing a node from file: " + fileName); + + // Copy the submitted file to the hard drive + InputStream inputStream = nodeForm.getFile().getInputStream(); + copyFileFromRepository(inputStream, importFile); + + nodeForm.setFile(null); + + String rootPath = ZipFileUtil.expandZip(new FileInputStream(importFile), fileName); + String nodeFilePath = FileUtil.getFullPath(rootPath, PedagogicalPlannerAction.NODE_FILE_NAME); + + PedagogicalPlannerSequenceNode node = (PedagogicalPlannerSequenceNode) FileUtil.getObjectFromXML(null, + nodeFilePath); + + // begin fckeditor content folder import + String contentZipFileName = PedagogicalPlannerAction.EXPORT_NODE_CONTENT_ZIP_PREFIX + + node.getContentFolderId() + PedagogicalPlannerAction.FILE_EXTENSION_ZIP; + String secureDir = Configuration.get(ConfigurationKeys.LAMS_EAR_DIR) + File.separator + + FileUtil.LAMS_WWW_DIR + File.separator + FileUtil.LAMS_WWW_SECURE_DIR + File.separator + + node.getContentFolderId(); + File contentZipFile = new File(FileUtil.getFullPath(rootPath, contentZipFileName)); + + // unzip file to target secure dir if exists + if (contentZipFile.exists()) { + InputStream is = new FileInputStream(contentZipFile); + ZipFileUtil.expandZipToFolder(is, secureDir); + } + + // Upload the template files back into the repository + File templateDir = new File(rootPath, PedagogicalPlannerAction.DIR_TEMPLATES); + importSubnodeTemplates(node, templateDir); + + // The imported node is added as the last one + Integer order = getPedagogicalPlannerDAO().getNextOrderId(null); + node.setOrder(order); + getPedagogicalPlannerDAO().saveOrUpdateNode(node); + } catch (Exception e) { + PedagogicalPlannerAction.log.error(e); + errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(PedagogicalPlannerAction.ERROR_KEY_IMPORT)); + } + } + if (!errors.isEmpty()) { + saveErrors(request, errors); + } + return openSequenceNode(mapping, form, request, (Long) null); + } + + /** + * Imports a learning design for edit/preview template purposes. + * + * @param fileUuid + * @param fileName + * @param errors + * @return + * @throws ServletException + */ + private LearningDesign importLearningDesign(Long fileUuid, String fileName, ActionMessages errors) + throws ServletException { + File designFile = null; + try { + designFile = new File(FileUtil.TEMP_DIR, fileName); + InputStream inputStream = getContentHandler().getFileNode(fileUuid).getFile(); + copyFileFromRepository(inputStream, designFile); + } catch (Exception e) { + PedagogicalPlannerAction.log.error(e); + errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(PedagogicalPlannerAction.ERROR_KEY_FILE_OPEN)); + return null; + } + if (!designFile.exists() || designFile.isDirectory()) { + PedagogicalPlannerAction.log.error(PedagogicalPlannerAction.ERROR_NOT_PROPER_FILE); + errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(PedagogicalPlannerAction.ERROR_KEY_FILE_OPEN)); + return null; + } + + HttpSession session = SessionManager.getSession(); + UserDTO userDto = (UserDTO) session.getAttribute(AttributeNames.USER); + User user = (User) getUserManagementService().findById(User.class, userDto.getUserID()); + if (user == null) { + throw new ServletException(PedagogicalPlannerAction.ERROR_USER_NOT_FOUND); + } + List toolsErrorMsgs = new ArrayList(); + Long learningDesignID = null; + LearningDesign learningDesign = null; + List learningDesignErrorMsgs = new ArrayList(); + // Extract the template + + try { + Object[] ldResults = getExportService().importLearningDesign(designFile, user, null, toolsErrorMsgs, ""); + designFile.delete(); + learningDesignID = (Long) ldResults[0]; + learningDesignErrorMsgs = (List) ldResults[1]; + toolsErrorMsgs = (List) ldResults[2]; + learningDesign = getAuthoringService().getLearningDesign(learningDesignID); + } catch (ImportToolContentException e) { + PedagogicalPlannerAction.log.error(e); + errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage( + PedagogicalPlannerAction.ERROR_KEY_LEARNING_DESIGN_COULD_NOT_BE_RETRIEVED)); + + } + + if ((learningDesignID == null || learningDesignID.longValue() == -1) && learningDesignErrorMsgs.size() == 0) { + errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage( + PedagogicalPlannerAction.ERROR_KEY_LEARNING_DESIGN_COULD_NOT_BE_RETRIEVED)); + return null; + } + if (learningDesignErrorMsgs.size() > 0) { + for (String error : learningDesignErrorMsgs) { + PedagogicalPlannerAction.log.error(error); + } + errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage( + PedagogicalPlannerAction.ERROR_KEY_LEARNING_DESIGN_COULD_NOT_BE_RETRIEVED)); + return null; + } + if (toolsErrorMsgs.size() > 0) { + for (String error : toolsErrorMsgs) { + PedagogicalPlannerAction.log.error(error); + } + errors + .add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage( + PedagogicalPlannerAction.ERROR_KEY_TOOL_ERRORS)); + return null; + } + return learningDesign; + } + + /** + * Copies the template files from repository into the selected dir. + * + * @param node + * @param outputDir + * @throws RepositoryCheckedException + * @throws IOException + */ + private void exportSubnodeTemplates(PedagogicalPlannerSequenceNode node, File outputDir) + throws RepositoryCheckedException, IOException { + if (node != null) { + if (node.getFileUuid() == null) { + if (node.getSubnodes() != null) { + for (PedagogicalPlannerSequenceNode subnode : node.getSubnodes()) { + exportSubnodeTemplates(subnode, outputDir); + } + } + } else { + File uuidDir = new File(outputDir, node.getFileUuid().toString()); + uuidDir.mkdirs(); + File targetFile = new File(uuidDir, node.getFileName()); + InputStream inputStream = getContentHandler().getFileNode(node.getFileUuid()).getFile(); + PedagogicalPlannerAction.log.debug("Preparing for zipping the template file: " + node.getFileName()); + copyFileFromRepository(inputStream, targetFile); + } + } + } + + /** + * Uploads the templates back into repository. Also sets all the nodes' UIDs to NULL. + * + * @param node + * @param inputDir + * @throws RepositoryCheckedException + * @throws IOException + */ + private void importSubnodeTemplates(PedagogicalPlannerSequenceNode node, File inputDir) + throws RepositoryCheckedException, IOException { + if (node != null) { + node.setUid(null); + + if (node.getFileUuid() == null) { + if (node.getSubnodes() != null) { + for (PedagogicalPlannerSequenceNode subnode : node.getSubnodes()) { + importSubnodeTemplates(subnode, inputDir); + } + } + } else { + File uuidDir = new File(inputDir, node.getFileUuid().toString()); + File file = new File(uuidDir, node.getFileName()); + InputStream inputStream = new FileInputStream(file); + String fileName = node.getFileName(); + PedagogicalPlannerAction.log.debug("Uploading into repository a template file: " + fileName); + NodeKey nodeKey = getContentHandler().uploadFile(inputStream, fileName, + PedagogicalPlannerAction.RESPONSE_CONTENT_TYPE_DOWNLOAD, IToolContentHandler.TYPE_OFFLINE); + node.setFileUuid(nodeKey.getUuid()); + } + } + } + + /** + * Copies a file using the provided input stream. + * + * @param inputStream + * @param targetFile + * @throws RepositoryCheckedException + * @throws IOException + */ + private void copyFileFromRepository(InputStream inputStream, File targetFile) throws RepositoryCheckedException, + IOException { + + FileOutputStream fileOutputStream = new FileOutputStream(targetFile); + byte[] data = new byte[PedagogicalPlannerAction.FILE_COPY_BUFFER_SIZE]; int read = 0; do { read = inputStream.read(data); @@ -781,9 +1159,104 @@ } while (read > 0); fileOutputStream.close(); inputStream.close(); - return file; } + /*----------------------- GROUPING METHODS -------------------------*/ + + /** + * Fill the grouping with initial data + */ + public ActionForward initGrouping(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + PedagogicalPlannerGroupingForm plannerForm = (PedagogicalPlannerGroupingForm) form; + Long groupingId = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_CONTENT_ID); + Grouping grouping = getAuthoringService().getGroupingById(groupingId); + plannerForm.fillForm(grouping); + return mapping.findForward(CentralConstants.FORWARD_GROUPING); + } + + /** + * Saves parameters of the grouping form, depending on the grouping type. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + public ActionForward saveOrUpdateGroupingForm(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + PedagogicalPlannerAction.log.debug("Saving grouping activity"); + PedagogicalPlannerGroupingForm plannerForm = (PedagogicalPlannerGroupingForm) form; + ActionMessages errors = plannerForm.validate(); + if (errors.isEmpty()) { + Grouping grouping = getAuthoringService().getGroupingById(plannerForm.getToolContentID()); + if (grouping.isRandomGrouping()) { + RandomGrouping randomGrouping = (RandomGrouping) grouping; + Integer number = StringUtils.isEmpty(plannerForm.getNumberOfGroups()) ? null : Integer + .parseInt(plannerForm.getNumberOfGroups()); + randomGrouping.setNumberOfGroups(number); + + number = StringUtils.isEmpty(plannerForm.getLearnersPerGroup()) ? null : Integer.parseInt(plannerForm + .getLearnersPerGroup()); + randomGrouping.setLearnersPerGroup(number); + } else if (grouping.isLearnerChoiceGrouping()) { + LearnerChoiceGrouping learnerChoiceGrouping = (LearnerChoiceGrouping) grouping; + Integer number = StringUtils.isEmpty(plannerForm.getNumberOfGroups()) ? null : Integer + .parseInt(plannerForm.getNumberOfGroups()); + learnerChoiceGrouping.setNumberOfGroups(number); + + number = StringUtils.isEmpty(plannerForm.getLearnersPerGroup()) ? null : Integer.parseInt(plannerForm + .getLearnersPerGroup()); + learnerChoiceGrouping.setLearnersPerGroup(number); + learnerChoiceGrouping.setEqualNumberOfLearnersPerGroup(plannerForm.getEqualGroupSizes()); + learnerChoiceGrouping.setViewStudentsBeforeSelection(plannerForm.getViewStudentsBeforeSelection()); + } else { + Integer number = StringUtils.isEmpty(plannerForm.getNumberOfGroups()) ? null : Integer + .parseInt(plannerForm.getNumberOfGroups()); + grouping.setMaxNumberOfGroups(number); + } + } else { + saveMessages(request, errors); + } + return mapping.findForward(CentralConstants.FORWARD_GROUPING); + } + + /*-------------------------- TEMPLATE BASE METHODS -----------------*/ + + /** + * Saves additional, non tool-bound template details - currently only the title. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws IOException + */ + public ActionForward saveSequenceDetails(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException { + PedagogicalPlannerAction.log.debug("Saving sequence title"); + String sequenceTitle = WebUtil.readStrParam(request, CentralConstants.PARAM_SEQUENCE_TITLE, true); + Long learningDesignID = WebUtil.readLongParam(request, CentralConstants.PARAM_LEARNING_DESIGN_ID); + Integer callAttemptedID = WebUtil.readIntParam(request, CentralConstants.PARAM_CALL_ATTEMPTED_ID); + // We send a message in format "&"; it is then parsed in JavaScript + String responseSuffix = PedagogicalPlannerAction.CHAR_AMPERSAND + callAttemptedID; + + if (StringUtils.isEmpty(sequenceTitle)) { + String blankTitleError = getMessageService().getMessage(CentralConstants.ERROR_PLANNER_TITLE_BLANK); + writeAJAXResponse(response, blankTitleError + responseSuffix); + } else { + LearningDesign learningDesign = getAuthoringService().getLearningDesign(learningDesignID); + learningDesign.setTitle(sequenceTitle); + getAuthoringService().saveLearningDesign(learningDesign); + writeAJAXResponse(response, PedagogicalPlannerAction.STRING_OK + responseSuffix); + } + return null; + } + + /*------------------------ SERVICE ACCESS METHODS --------------------*/ + private IExportToolContentService getExportService() { if (PedagogicalPlannerAction.exportService == null) { WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(getServlet() Index: lams_central/src/java/org/lamsfoundation/lams/web/planner/PedagogicalPlannerGroupingForm.java =================================================================== diff -u -r00a6e145b37916eb1561ea5c68319b0fc691681b -r9a772f5ba1954a3a719a19e7ae237b6b09dc76ef --- lams_central/src/java/org/lamsfoundation/lams/web/planner/PedagogicalPlannerGroupingForm.java (.../PedagogicalPlannerGroupingForm.java) (revision 00a6e145b37916eb1561ea5c68319b0fc691681b) +++ lams_central/src/java/org/lamsfoundation/lams/web/planner/PedagogicalPlannerGroupingForm.java (.../PedagogicalPlannerGroupingForm.java) (revision 9a772f5ba1954a3a719a19e7ae237b6b09dc76ef) @@ -41,6 +41,7 @@ private String numberOfGroups; private String learnersPerGroup; private Boolean equalGroupSizes; + private Boolean viewStudentsBeforeSelection; public Integer getGroupingTypeId() { return groupingTypeId; @@ -87,6 +88,7 @@ setLearnersPerGroup(number); setEqualGroupSizes(learnerChoiceGrouping.getEqualNumberOfLearnersPerGroup()); + setViewStudentsBeforeSelection(learnerChoiceGrouping.getViewStudentsBeforeSelection()); } else { String numberOfGroups = grouping.getMaxNumberOfGroups() == null ? null : String.valueOf(grouping .getMaxNumberOfGroups()); @@ -136,4 +138,12 @@ public void setEqualGroupSizes(Boolean equalGroupsSizes) { equalGroupSizes = equalGroupsSizes; } + + public Boolean getViewStudentsBeforeSelection() { + return viewStudentsBeforeSelection; + } + + public void setViewStudentsBeforeSelection(Boolean viewStudentsBeforeSelection) { + this.viewStudentsBeforeSelection = viewStudentsBeforeSelection; + } } \ No newline at end of file Index: lams_central/src/java/org/lamsfoundation/lams/web/planner/PedagogicalPlannerSequenceNodeForm.java =================================================================== diff -u -rc697b5c30ab742ab453859355b35cd518856334f -r9a772f5ba1954a3a719a19e7ae237b6b09dc76ef --- lams_central/src/java/org/lamsfoundation/lams/web/planner/PedagogicalPlannerSequenceNodeForm.java (.../PedagogicalPlannerSequenceNodeForm.java) (revision c697b5c30ab742ab453859355b35cd518856334f) +++ lams_central/src/java/org/lamsfoundation/lams/web/planner/PedagogicalPlannerSequenceNodeForm.java (.../PedagogicalPlannerSequenceNodeForm.java) (revision 9a772f5ba1954a3a719a19e7ae237b6b09dc76ef) @@ -27,6 +27,9 @@ import org.apache.struts.upload.FormFile; public class PedagogicalPlannerSequenceNodeForm extends ActionForm { + public final static String NODE_TYPE_SUBNODES = "subnodes"; + public final static String NODE_TYPE_TEMPLATE = "template"; + private Long uid; private Long parentUid; private String contentFolderId; @@ -35,12 +38,9 @@ private String fullDescription; private FormFile file; private Boolean removeFile; - private String nodeType; + private String nodeType = PedagogicalPlannerSequenceNodeForm.NODE_TYPE_SUBNODES; private Long fileUuid; - public final static String NODE_TYPE_SUBNODES = "subnodes"; - public final static String NODE_TYPE_TEMPLATE = "template"; - public Long getUid() { return uid; } Index: lams_central/web/WEB-INF/fckeditor/tlds/FCKeditor.tld =================================================================== diff -u --- lams_central/web/WEB-INF/fckeditor/tlds/FCKeditor.tld (revision 0) +++ lams_central/web/WEB-INF/fckeditor/tlds/FCKeditor.tld (revision 9a772f5ba1954a3a719a19e7ae237b6b09dc76ef) @@ -0,0 +1,129 @@ + + + + The FCKeditor Tag Library offers a very convenient way to create + several FCKeditor instances with different configurations. + Additionally, you can check for user-based capabilities. + + FCKeditor Tag Library + 2.4 + FCK + http://java.fckeditor.net + + + Creates a FCKeditor instance with the given parameters. Any + parameter except instanceName which is empty or contains + whitespaces only will be ignored. + + editor + editor + net.fckeditor.tags.EditorTag + JSP + + + The unique instance name under which the editor can be + retrieved through the API. + + instanceName + true + true + java.lang.String + + + + Width of the FCKeditor instance in the browser window. + + width + true + java.lang.String + + + + Height of the FCKeditor instance in the browser window. + + height + true + java.lang.String + + + + The toolbar set which shall be displayed to the user. + + toolbarSet + true + java.lang.String + + + + The path/folder in which the editor is deployed under + the given context. The context path will be attached + automatically. (e.g. '/fckeditor') + + basePath + true + java.lang.String + + + + Passes any content to the FCKeditor document. Use the + jsp:attribute tag for large inline content. \r, \n, and + \t will be truncated. + + value + true + java.lang.String + + ]]> + + + + + Sets a config property of the editor to the supplied value. + You may provide any attribute you want for the editor. Set + at least one attribute per tag or several attributes with + one tag. This tag can only be nested within an editor tag. + For all configuration options click + here]]>. + + config + config + net.fckeditor.tags.ConfigTag + empty + true + + ]]> + + + + + Displays session-dependent and compatibility-related + information. This tag is intended for developers only. + Response messages cannot be localized, they are English + only. + + check + check + net.fckeditor.tags.CheckTag + empty + + + Provide the feature name you want to check. Valid + features are [FileUpload, FileBrowsing, + CompatibleBrowser] + + command + true + java.lang.String + + +]]> + + + \ No newline at end of file Fisheye: Tag 9a772f5ba1954a3a719a19e7ae237b6b09dc76ef refers to a dead (removed) revision in file `lams_central/web/WEB-INF/jstl/tlds/FCKeditor.tld'. Fisheye: No comparison available. Pass `N' to diff? Index: lams_central/web/WEB-INF/web.xml =================================================================== diff -u -rbdd916337e3a48589da367f4c8b7705fe3197af2 -r9a772f5ba1954a3a719a19e7ae237b6b09dc76ef --- lams_central/web/WEB-INF/web.xml (.../web.xml) (revision bdd916337e3a48589da367f4c8b7705fe3197af2) +++ lams_central/web/WEB-INF/web.xml (.../web.xml) (revision 9a772f5ba1954a3a719a19e7ae237b6b09dc76ef) @@ -294,6 +294,11 @@ + GetRecordingServlet + org.lamsfoundation.lams.webservice.GetRecordingServlet + + + copyMultipleToolContent org.lamsfoundation.lams.authoring.web.CopyMultipleToolContentServlet @@ -493,6 +498,10 @@ /servlet/notebook/storeNotebookEntry + GetRecordingServlet + /GetRecording + + copyMultipleToolContent /servlet/authoring/copyMultipleToolContent Index: lams_central/web/includes/javascript/pedagogicalPlanner.js =================================================================== diff -u -rc697b5c30ab742ab453859355b35cd518856334f -r9a772f5ba1954a3a719a19e7ae237b6b09dc76ef --- lams_central/web/includes/javascript/pedagogicalPlanner.js (.../pedagogicalPlanner.js) (revision c697b5c30ab742ab453859355b35cd518856334f) +++ lams_central/web/includes/javascript/pedagogicalPlanner.js (.../pedagogicalPlanner.js) (revision 9a772f5ba1954a3a719a19e7ae237b6b09dc76ef) @@ -138,7 +138,7 @@ if (sequenceDetailsValid && activitiesValid==activitiesResponded){ $('#pedagogicalPlannerInfoArea').show(); if (actionAfterCompleted==ACTION_PREVIEW){ - window.open(startPreviewUrl,'Preview','width=800,height=600,scrollbars=yes,resizable=yes'); + startPreview(startPreviewUrl); } else if (actionAfterCompleted==ACTION_OPEN_AUTHOR){ window.resizeTo(authoring_width,authoring_height); @@ -154,6 +154,10 @@ } } + function startPreview(url){ + window.open(url,'Preview','width=800,height=600,scrollbars=yes,resizable=yes'); + } + function closePlanner(text){ if (text==null || confirm(text)){ window.close(); @@ -179,4 +183,6 @@ document.getElementById("fullDescriptionArea").style.display="none"; document.getElementById("fileArea").style.display="block"; } + + } \ No newline at end of file Index: lams_central/web/pedagogical_planner/grouping.jsp =================================================================== diff -u -r5a30100855d83534e76db8dec0d0b603a1a1ded8 -r9a772f5ba1954a3a719a19e7ae237b6b09dc76ef --- lams_central/web/pedagogical_planner/grouping.jsp (.../grouping.jsp) (revision 5a30100855d83534e76db8dec0d0b603a1a1ded8) +++ lams_central/web/pedagogical_planner/grouping.jsp (.../grouping.jsp) (revision 9a772f5ba1954a3a719a19e7ae237b6b09dc76ef) @@ -14,6 +14,10 @@