[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] // catching all exceptions in order to return http response code private void RenderPackageContent(string resPath) { // If this is the primary resource of the current activity, then process it for rendering, including (in the case of // LRM content) injecting script to notify client script of page load. if (IsPrimaryResource(resPath)) { // If the resPath is empty or it matches the xmlBase value of the resource of the current activity, // that means it's asking for the default resource associated with the current // activity. Check if there is one. If there isn't, then show a message that indicates the content can't be shown // because there's no resource. if (Session.CurrentActivityResourceType == ResourceType.None) { RegisterError(ResHelper.GetMessage(IUDICO.TestingSystem.Localization.getMessage("CON_ResourceNotFoundTitle")), ResHelper.GetMessage(IUDICO.TestingSystem.Localization.getMessage("CON_ResourceNotFoundMsg")), false); return; } // If the entry point for the current activity is an absolute Uri, then we should not be here (the // hidden frame should have loaded the absolute Uri into the content frame). if (Session.CurrentActivityEntryPoint.IsAbsoluteUri) { RegisterError(ResHelper.GetMessage(IUDICO.TestingSystem.Localization.getMessage("CON_ResourceNotFoundTitle")), ResHelper.GetMessage(IUDICO.TestingSystem.Localization.getMessage("CON_ResourceNotFoundMsg")), false); return; } bool fileNotFound = false; // Check if we got an exception indicating the file could not be found try { string filePath = Session.CurrentActivityEntryPoint.OriginalString.Replace("%20", " "); RenderContext context = new RenderContext(filePath, Response); StringBuilder scriptBlock = new StringBuilder(1000); // Initialize the hidden control and script for the page InitHiddenControlInfo(context, scriptBlock); // Allow application to modify the context. UpdateRenderContext(context, scriptBlock, Session); FinishOnLoadScript(scriptBlock); // Save script to context, if neeed if (scriptBlock.Length > 0) { context.Script = scriptBlock.ToString(); } // Clear any previous page information and render the page Session.Render(context); // When the primary resource is rendered, the session may be changed, so save any changes. if (!SessionIsReadOnly) { Session.CommitChanges(); } } catch (FileNotFoundException) { fileNotFound = true; } catch (DirectoryNotFoundException) { fileNotFound = true; } if (fileNotFound) { // The entry point defined in the package was a relative Uri but does not map to a file in the package. RegisterError(ResHelper.GetMessage(IUDICO.TestingSystem.Localization.getMessage("CON_ResourceNotFoundTitle")), ResHelper.GetMessage(IUDICO.TestingSystem.Localization.getMessage("CON_ResourceNotFoundMsg")), false); return; } } else { long pageId; if (IsPrimaryResourceOfLrmActivity(resPath, out pageId)) { // If this is LRM content and is a request for the primary resource of another activity, then // move to that activity and render a 'please wait' // message that tells the frameset about the new activity. ProcessNavigationRequests(Session); string activityId = "ITEM" + FramesetUtil.GetStringInvariant(pageId); Session.MoveToActivity(activityId); if (!SessionIsReadOnly) { Session.CommitChanges(); } Response.Clear(); Response.Redirect(GetRedirectLocation()); } else { // There was a relative path provided. Write it to the output stream. If this method fails because the path was not // in the package or could not be accessed for some reason, return an error code. try { RenderContext context = new RenderContext(resPath.Replace("%20", " "), Response); UpdateRenderContext(context, null, Session); Session.Render(context); // Session is not changed in non-Execute views, so no need to call CommitChanges(). } catch (ThreadAbortException) { // Do nothing } catch (FileNotFoundException) { Response.StatusCode = 404; Response.StatusDescription = "Not Found"; } catch (HttpException) { // Something wrong with the http connection, so in this case do not set the response // headers. } catch { // This could fail for any number of reasons: invalid content that // refers to non-existant file, or a problem somewhere in the server // code. Return generic error code. Response.StatusCode = 500; Response.StatusDescription = "Internal Server Error"; } } } }
[SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] // it's not worth changing this now public void ProcessPageLoad(PackageStore packageStore, bool firstRendering, // frameset is being initialized bool isPostBack, // page was posted TryGetViewInfo TryGetViewInfo, TryGetAttemptInfo TryGetAttemptInfo, TryGetActivityInfo TryGetActivityInfo, GetResourcePath GetResourcePath, AppendContentFrameDetails appendContentFrameDetails, UpdateRenderContext updateRenderContext, ProcessPostedData ProcessPostedData, ProcessViewRequest ProcessViewRequest, ProcessPostedDataComplete ProcessPostedDataComplete, RegisterError registerError, GetErrorInfo getErrorInfo, GetFramesetMsg getFramesetMsg) { RegisterError = registerError; UpdateRenderContext = updateRenderContext; GetErrorInfo = getErrorInfo; AppendContentFrameDetails = appendContentFrameDetails; GetFramesetMsg = getFramesetMsg; m_isPostedPage = isPostBack; // If this is the first time the page is being rendered, just show 'please wait' and return. if (firstRendering) { // Initial page rendering, show "please wait" WritePleaseWaitToResponse(Response); Response.End(); return; } SessionView view; // Get View information. It determines what else to look for. if (!TryGetViewInfo(true, out view)) { return; } // There is something to display, so process the request... AttemptItemIdentifier attemptId; if (!TryGetAttemptInfo(true, out attemptId)) { return; } StoredLearningSession slsSession = new StoredLearningSession(view, attemptId, packageStore); if (!ProcessViewRequest(view, slsSession)) { return; } Session = slsSession; if (slsSession.View == SessionView.Execute) { // Check if the session can be executed... if (slsSession.AttemptStatus != AttemptStatus.Active) { RegisterError(GetFramesetMsg(FramesetStringId.CannotDisplayContentTitle), GetFramesetMsg(FramesetStringId.SessionIsNotActiveMsg), false); return; } if (!slsSession.CurrentActivityIsActive) { RegisterError(GetFramesetMsg(FramesetStringId.SelectActivityTitleHtml), GetFramesetMsg(FramesetStringId.SelectActivityMessageHtml), true); return; } } else if (slsSession.View == SessionView.Review) { // Get information about which activity to review, then make that the current activity. long activityId = -1; // make compiler happy if (!TryGetActivityInfo(true, out activityId)) { return; } // Move to the requested activity. Under normal conditions, this should always succeed, since the frameset should be // giving this page a valid activity id. MoveToActivity(slsSession, activityId); } else if (slsSession.View == SessionView.RandomAccess) { // Get information about which activity to edit, then make that the current activity. long activityId = -1; // make compiler happy if (!TryGetActivityInfo(true, out activityId)) { return; } // Move to the requested activity. Under normal conditions, this should always succeed, since the frameset should be // giving this page a valid activity id. MoveToActivity(slsSession, activityId); } if (isPostBack /* && !SessionEnded */) { //Process information from posted content if (!this.SessionIsReadOnly) { HttpFileCollection files = Request.Files; int numFiles = files.Count; Dictionary <string, HttpPostedFile> newFileCollection = new Dictionary <string, HttpPostedFile>(numFiles); // Allow the application to process the form data if (!ProcessPostedData(slsSession, Request, newFileCollection)) { return; } // Allow MLC to process the form data Session.ProcessFormData(Request.Form, newFileCollection); // Allow application to do final processing after all posted data is processed. ProcessPostedDataComplete(Session); // If there was an error in processing form data, end the processing. This allows, for instance, to // save the data, display an error and not have commands (such as 'move to next activity') executed. if (HasError) { Session.CommitChanges(); return; } } // Issue with Review view: where to get activity id? From URL or posted data? // Find out what the commands are and do them. ICollection <CommandInfo> commands = GetCommands(); foreach (CommandInfo cmdInfo in commands) { switch (cmdInfo.Command) { case Commands.DoNext: { // When leaving a current activity, we must allow navigation requests the SCO has made to be // executed. If that results in changing the current activity, then do not also ask for another // move. if (!ProcessNavigationRequests(Session)) { if (Session.IsMoveToNextValid()) { MoveToNextActivity(Session); ActivityHasChanged = true; } } else { ActivityHasChanged = true; } if (!ActivityHasChanged) { // Moving to the next activity is not valid. WriteError(ResHelper.Format(GetFramesetMsg(FramesetStringId.MoveToNextFailedHtml), ThemeFolderPath), true); } } break; case Commands.DoPrevious: { if (!ProcessNavigationRequests(Session)) { if (Session.IsMoveToPreviousValid()) { MoveToPreviousActivity(Session); ActivityHasChanged = true; } } else { ActivityHasChanged = true; } if (!ActivityHasChanged) { // Moving to the previous activity is not valid. WriteError(ResHelper.Format(GetFramesetMsg(FramesetStringId.MoveToPreviousFailedHtml), ThemeFolderPath), true); } } break; case Commands.DoChoice: case Commands.DoTocChoice: { // These commands are used to navigate to activities, and to navigate to the final 'submit' page. // In SCORM content, these commands do different things. In LRM content (which is what we are // in, since this is the posted page), they have identical effects. // First check whether this is a request for the submit page or an activity. string cmdData = cmdInfo.CommandData; if (String.CompareOrdinal(cmdData, SubmitId) == 0) { // Requesting submit page. Do not change the current activity, but mark it as changed so that // it appears to the user that it has changed. ActivityHasChanged = true; string title = GetFramesetMsg(FramesetStringId.SubmitPageTitleHtml); string message; string saveBtn = GetFramesetMsg(FramesetStringId.SubmitPageSaveButtonHtml); if (Session.HasCurrentActivity) { message = GetFramesetMsg(FramesetStringId.SubmitPageMessageHtml); } else { message = GetFramesetMsg(FramesetStringId.SubmitPageMessageNoCurrentActivityHtml); } WriteSubmitPage(title, message, saveBtn); } else { long activityId; if (long.TryParse(cmdData, out activityId)) { // If the requested activity is the current activity, then do not do the navigation. // We skip it because moving to the activity basically exits the current attempt and creates // a new one. That new one also increments the attempt count. If we don't do the move, we // pretend it was done. This will force the content frame to be reloaded with the current // activity. if (IsCurrentActiveActivity(activityId)) { ActivityHasChanged = true; } else { if (!ProcessNavigationRequests(Session)) { if (Session.IsMoveToActivityValid(activityId)) { MoveToActivity(Session, activityId); ActivityHasChanged = true; } } else { ActivityHasChanged = true; } } } } if (!ActivityHasChanged) { // Moving to the selected activity is not valid. WriteError(ResHelper.Format(GetFramesetMsg(FramesetStringId.MoveToActivityFailedHtml), ThemeFolderPath), true); } } break; case Commands.DoSave: { // Do nothing. The information will be saved since the page was posted. } break; case Commands.DoSubmit: { if (Session.View == SessionView.Execute) { ProcessNavigationRequests(Session); Session.Exit(); } ActivityHasChanged = true; } break; } } } // If an error has been registered (and it's not the submit // page rendering), don't attempt to render the content. if (HasError && !SubmitPageDisplayed) { if (!SessionIsReadOnly) { Session.CommitChanges(); } return; } // There was no error, so go ahead and render the content from the package. // If the current activity has changed in the processing of this page, then render the current activity's resource. // Otherwise, ask the application which resource to read. if (ActivityHasChanged) { // If the activity has changed, we render the content page without rendering the content. The page will then // reload the content frame with the new activity. if (!SessionIsReadOnly) { Session.CommitChanges(); } } else { // Render the requested file in the current activity. RenderPackageContent(GetResourcePath()); // If there was no error, end the response. Otherwise, we wait and render the error on the page. if (!HasError) { Response.End(); } } }
/// <summary>Write initialization code for frameset manager. </summary> /// <remarks> /// This method is called in three possible cases: /// 1. An error condition occurred /// 2. The submit page is being displayed. Note that in this case, since the submit page is registered as displaying an /// error condition, HasError will be true. /// 3. The current activity has changed and we display this page mainly so that the 'please wait' information can be /// displayed and the client can issue a GET request to load the new activity. /// </remarks> public void WriteFrameMgrInit() { // Write frame to post. When displaying an error (which is the case, since we are here) the hidden frame is posted next Response.Write("frameMgr.SetPostFrame('frameHidden');\r\n"); Response.Write("frameMgr.SetPostableForm(parent.parent.frames[MAIN_FRAME].document.getElementById(HIDDEN_FRAME).contentWindow.document.forms[0]);\r\n"); if (HasError || SubmitPageDisplayed) { // Set the content frame URL to be null. This means the content frame will not be re-loaded by the frameMgr. Response.Write("frameMgr.SetContentFrameUrl(null); \r\n"); } // If there is no session, we can't do anything else if (Session == null) { return; } if ((ActivityHasChanged) && (!SubmitPageDisplayed)) { // Reload the content frame with the new activity. Response.Write(String.Format(CultureInfo.CurrentCulture, "frameMgr.SetContentFrameUrl(\"{0}\"); \r\n", GetContentFrameUrl())); // The new activity may be scorm content, so reinitialize the rte, if needed Response.Write(ResHelper.Format("frameMgr.InitNewActivity( {0} );\r\n", (CurrentActivityRequiresRte ? "true" : "false"))); } Response.Write(ResHelper.Format("frameMgr.SetAttemptId('{0}');\r\n", FramesetUtil.GetStringInvariant(Session.AttemptId.GetKey()))); // Write view to display. Response.Write(String.Format(CultureInfo.CurrentCulture, "frameMgr.SetView('{0}');\r\n", FramesetUtil.GetString(Session.View))); // Write the current activity Id. Write -1 if there isn't one. string activityId; if (SubmitPageDisplayed) { activityId = SubmitId; } else { activityId = (Session.HasCurrentActivity ? FramesetUtil.GetStringInvariant(Session.CurrentActivityId) : "-1"); } Response.Write(String.Format(CultureInfo.InvariantCulture, "frameMgr.SetActivityId({0});\r\n", JScriptString.QuoteString(activityId, true))); // Write nav visibility, in case it's changed since the hidden frame was rendered if (SubmitPageDisplayed) { // If the submit page is being displayed, don't show UI elements Response.Write(String.Format(CultureInfo.CurrentCulture, "frameMgr.SetNavVisibility( {0}, {1}, {2}, {3}, {4});", ("false"), // showNext ("false"), // showPrevious ("false"), // showAbandon ("false"), // showExit (Session.ShowSave ? "true" : "false"))); // If the submit page is now being displayed, make sure the frameset isn't waiting for another commit Response.Write("frameMgr.WaitForContentCompleted(0);\r\n"); } else { Response.Write(String.Format(CultureInfo.CurrentCulture, "frameMgr.SetNavVisibility( {0}, {1}, {2}, {3}, {4});\r\n", (Session.ShowNext ? "true" : "false"), (Session.ShowPrevious ? "true" : "false"), (Session.ShowAbandon ? "true" : "false"), (Session.ShowExit ? "true" : "false"), (Session.ShowSave ? "true" : "false"))); } // Register that the frame loading is complete. This is required so as to notify the frameset of activity id, and // other UI status. Response.Write(String.Format(CultureInfo.InvariantCulture, "frameMgr.RegisterFrameLoad({0});\r\n ", JScriptString.QuoteString("frameContent", false))); if (m_isPostedPage) { // Set PostIsComplete. THIS MUST BE THE LAST VALUE SET! Response.Write("frameMgr.PostIsComplete();"); } }
[SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")] // parameter is validated private void WriteTocEntry(HtmlStringWriter sw, TableOfContentsElement currentElement) { FramesetUtil.ValidateNonNullParameter("sw", sw); FramesetUtil.ValidateNonNullParameter("currentElement", currentElement); string activityId = FramesetUtil.GetStringInvariant(currentElement.ActivityId); bool elementHasChildren = currentElement.Children.Count > 0; HtmlString activityIdHtml = new PlainTextString(activityId).ToHtmlString(); HtmlString titleHtml = new PlainTextString(currentElement.Title).ToHtmlString(); // If the current element is visible or is an invisible leaf node, then render it. (If it's an // invisible leaf node, the node will exist but not be visible.) if (RenderThisNode(currentElement)) { sw.AddAttribute(HtmlTextWriterAttribute.Class, new PlainTextString("NodeParent")); sw.AddAttribute("activityId", activityIdHtml); sw.AddAttribute("isValidChoice", (currentElement.IsValidChoiceNavigationDestination ? "true" : "false")); sw.AddAttribute(HtmlTextWriterAttribute.Id, ResHelper.FormatInvariant("div{0}", activityIdHtml)); sw.RenderBeginTag(HtmlTextWriterTag.Div); // #Div1 if (currentElement.IsVisible) { sw.AddAttribute(HtmlTextWriterAttribute.Id, ResHelper.FormatInvariant("icon{0}", activityIdHtml)); if (currentElement.HasVisibleChildren) { sw.AddAttribute(HtmlTextWriterAttribute.Src, "Theme/Minus.png"); } else { sw.AddAttribute(HtmlTextWriterAttribute.Src, "Theme/Leaf.png"); } sw.AddAttribute(HtmlTextWriterAttribute.Align, "absMiddle"); sw.RenderBeginTag(HtmlTextWriterTag.Img); sw.RenderEndTag(); sw.AddAttribute(HtmlTextWriterAttribute.Src, "Theme/1px.gif"); sw.AddAttribute(HtmlTextWriterAttribute.Align, "absMiddle"); sw.RenderBeginTag(HtmlTextWriterTag.Img); sw.RenderEndTag(); sw.WriteLine(); sw.AddAttribute(HtmlTextWriterAttribute.Href, "javascript:void(0)"); sw.AddAttribute(HtmlTextWriterAttribute.Id, ResHelper.FormatInvariant("a{0}", activityIdHtml)); if (!currentElement.IsValidChoiceNavigationDestination) { sw.AddAttribute(HtmlTextWriterAttribute.Disabled, "true"); sw.AddAttribute("class", "disable"); } sw.AddAttribute( HtmlTextWriterAttribute.Style, ResHelper.FormatInvariant("FONT-WEIGHT: normal;visibility:{0}", (currentElement.IsVisible ? "visible" : "hidden"))); sw.AddAttribute(HtmlTextWriterAttribute.Title, titleHtml); sw.RenderBeginTag(HtmlTextWriterTag.A); sw.WriteHtml(titleHtml); sw.RenderEndTag(); } } // Write sub-elements (regardless of whether or not this node is rendered) if (elementHasChildren) { sw.WriteLine(); bool clusterStarted = false; if (currentElement.IsVisible) { sw.AddAttribute( HtmlTextWriterAttribute.Id, ResHelper.FormatInvariant("divCluster{0}", activityIdHtml)); sw.AddAttribute( HtmlTextWriterAttribute.Style, "MARGIN-TOP: 5px; DISPLAY: block; MARGIN-LEFT: 18px;"); sw.RenderBeginTag(HtmlTextWriterTag.Div); clusterStarted = true; } foreach (TableOfContentsElement childElement in currentElement.Children) { this.WriteTocEntry(sw, childElement); } if (clusterStarted) { sw.RenderEndTag(); // end div sw.WriteLine(); } } if (RenderThisNode(currentElement)) { sw.RenderEndTag(); // div (see #Div1, above) sw.WriteLine(); } }