private void LoadPageDomFromBrowser()
{
Debug.Assert(!InvokeRequired);
if (_pageEditDom == null)
return;
GeckoDocument contentDocument = null;
try
{
if (_pageEditDom == _rootDom)
contentDocument = _browser.Document;
else
{
// Assume _editDom corresponds to a frame called 'page' in the root. This may eventually need to be more configurable.
if (_browser.Window == null || _browser.Window.Document == null)
return;
var frameElement = _browser.Window.Document.GetElementById("page") as GeckoIFrameElement;
if (frameElement == null)
return;
// contentDocument = frameElement.ContentDocument; unreliable in Gecko45
contentDocument = (GeckoDocument) frameElement.ContentWindow.Document; // TomH says this will always succeed
}
if (contentDocument == null)
return; // can this happen?
// As of august 2012 textareas only occur in the Calendar
if (_pageEditDom.SelectNodes("//textarea").Count > 0)
{
//This approach was to force an onblur so that we can get at the actual user-edited value.
//This caused problems, with Bloom itself (the Shell) not knowing that it is active.
//_browser.WebBrowserFocus.Deactivate();
//_browser.WebBrowserFocus.Activate();
// Now, we just do the blur directly.
var activeElement = contentDocument.ActiveElement;
if (activeElement != null)
activeElement.Blur();
}
var body = contentDocument.GetElementsByTagName("body");
if (body.Length ==0) //review: a previous comment said this could happen in OnValidating, but that is gone...may be obsolete
return;
var content = body[0].InnerHtml;
XmlDocument dom;
//todo: deal with exception that can come out of this
dom = XmlHtmlConverter.GetXmlDomFromHtml(content, false);
var bodyDom = dom.SelectSingleNode("//body");
if (_pageEditDom == null)
return;
var destinationDomPage = _pageEditDom.SelectSingleNode("//body//div[contains(@class,'bloom-page')]");
if (destinationDomPage == null)
return;
var expectedPageId = destinationDomPage.Attributes["id"].Value;
var browserDomPage = bodyDom.SelectSingleNode("//body//div[contains(@class,'bloom-page')]");
if (browserDomPage == null)
return;//why? but I've seen it happen
var thisPageId = browserDomPage.Attributes["id"].Value;
if(expectedPageId != thisPageId)
{
SIL.Reporting.ErrorReport.NotifyUserOfProblem("Bloom encountered an error saving that page (unexpected page id)");
return;
}
_pageEditDom.GetElementsByTagName("body")[0].InnerXml = bodyDom.InnerXml;
var userModifiedStyleSheet = contentDocument.StyleSheets.FirstOrDefault(s =>
{
// workaround for bug #40 (https://bitbucket.org/geckofx/geckofx-29.0/issue/40/xpath-error-hresult-0x805b0034)
// var titleNode = s.OwnerNode.EvaluateXPath("@title").GetSingleNodeValue();
var titleNode = s.OwnerNode.EvaluateXPath("@title").GetNodes().FirstOrDefault();
if (titleNode == null)
return false;
return titleNode.NodeValue == "userModifiedStyles";
});
if (userModifiedStyleSheet != null)
{
SaveCustomizedCssRules(userModifiedStyleSheet);
}
//enhance: we have jscript for this: cleanup()... but running jscript in this method was leading the browser to show blank screen
// foreach (XmlElement j in _editDom.SafeSelectNodes("//div[contains(@class, 'ui-tooltip')]"))
// {
// j.ParentNode.RemoveChild(j);
// }
// foreach (XmlAttribute j in _editDom.SafeSelectNodes("//@ariasecondary-describedby | //@aria-describedby"))
// {
// j.OwnerElement.RemoveAttributeNode(j);
// }
}
catch(Exception e)
{
Debug.Fail("Debug Mode Only: Error while trying to read changes to CSSRules. In Release, this just gets swallowed. Will now re-throw the exception.");
#if DEBUG
throw;
#endif
}
finally
{
if (contentDocument != null)
contentDocument.Dispose();
}
try
{
XmlHtmlConverter.ThrowIfHtmlHasErrors(_pageEditDom.OuterXml);
}
catch (Exception e)
{
//var exceptionWithHtmlContents = new Exception(content);
ErrorReport.NotifyUserOfProblem(e,
"Sorry, Bloom choked on something on this page (validating page).{1}{1}+{0}",
e.Message, Environment.NewLine);
}
}