I am currently using this code to retrieve the content as string after it is has been rendered by TWebBrowser and you visually can see it shows the content loaded dynamicly through AJAX:
function TMyViewerIE.GetDocumentAsStr: string;
begin
if Assigned(FWebBrowser.Document) then
begin
iall := (FWebBrowser.Document AS IHTMLDocument2).body;
while iall.parentElement <> nil do
begin
iall := iall.parentElement;
end;
Result := iall.outerHTML;
end
;
end;
However, this code does not appear to include changes performed by AJAX.
Note: For those who believe above code is "out of context", please also see this SO where a variation of this code was suggested as a solution:
Delphi TWebBrowser get HTML source after AJAX load
Problem is that it does not work for me. I had thought above would work since (again I thought) AJAX changes the internal document structure and that was what was saved.
Maybe I am missing something - if anyone knows the answer, I will appreciate it. I will also continue my own research and post results.
Note: I may try construct an AJAX page (or public / goverment page) so I can share my test cases more easily. I believe that will satisfy suggestions about a working example.
Related
I have a public website made using Apex 21.1.3
When a user shares a page of my website, let's say on facebook, Facebook adds "?fbclickId=something" to the URL.
My app then crashes saying : Unable to find item ID for item fbclickId in application.
Apex thinks the user is trying to set an element that does not exist on the application.
I have url processing layer using htaccess that formats the urls before sending them to Apex in a reverse proxy. I could say let's ignore all what comes after a question mark "?" but in this case I wont be able to set any application item value neither. So that's not possible.
Does anyone have an idea how to make Apex ignore setting a parameter if it doesn't exist ?
Using google for example :
This URL https://www.google.com/?anyparameter=anyvalue will always resolve to https://www.google.com
Thanks
Cheers
I'm not aware of any way to ignore invalid parameters, but you can make the error a bit nicer for the end user.
Create a custom apex error handling function. The only difference with standard error handling is that the error with code WWV_FLOW.FIND_ITEM_ID_ERR has a custom message and no additional info. Change the string "Invalid url arguments" to something more relevant for your business case.
create or replace function apex_error_custom
(
p_error IN apex_error.t_error
)
RETURN apex_error.t_error_result
IS
l_result apex_error.t_error_result := apex_error.t_error_result();
BEGIN
l_result := apex_error.init_error_result ( p_error => APEX_ERROR_CUSTOM.p_error );
IF p_error.apex_error_code = 'WWV_FLOW.FIND_ITEM_ID_ERR' THEN
l_result.message := 'Invalid url arguments';
l_result.additional_info := NULL;
END IF;
RETURN l_result;
END apex_error_custom;
Change the application definition to use the new error function:
Application Definitions > Error Handling > Custom Error Function. Note this affects all errors in the application.
An additional way to make the error nicer is to change the default error page to use a defined template (Shared Components > Themes > your theme > Component Defaults > Error page). Note this affects all errors in the application.
Here is the solution I came up with.
I couldn't find any way to ignore unavailable fields but found a trick to avoid sending them to Apex, hence escaping the error.
In the middle tier (nginx, apache, IIS) add the following logic :
Whenever there are two question marks, ignore the second one part:
For example : someApexAppUrl?Parameter=value?fbclickid=something
Should become : someApexAppUrl?Parameter=value
Whenever there is a parameter added to the url for example
someApexAppUrl?Parameter=value
Check the parameter name against
Application Items with a protection level of Unrestricted, Checksum Required - Application Level, Checksum Required - User Level, Checksum Required - Session Level
The hard coded list of the default Apex urls parameters which are : session, request, clear, debug, printerFriendly, trace, timezone, lang, territory, cs, dialogCs, x01 according to this article
Application page items with a name pattern P99_Someting
Whenever a parameter is not among these three categories, ignore it and don't send it to Apex. This way even if facebook adds something like ?fbclickid=xxx the Apex App will still work nicely.
You can add the item to your application to avoid getting this error message.
Create an Application Item (under Shared Components) called FBCLICKID. Set its Session State Protected to Unrestricted.
fphttpclient works fine with simple examples like
procedure ReadFromURL(theURL: string);
var
httpClient: TFPHTTPClient;
FileContents: String;
theStatusCode: integer;
begin
httpClient := TFPHTTPClient.Create(nil);
try
FileContents := httpClient.Get(theURL);
theStatusCode := httpClient.ResponseStatusCode;
if theStatusCode = 200 then
begin
; // do something
end
else
ShowMessage(IntToStr(theStatusCode));
finally
httpClient.Free;
end;
end;
but only, if the URL exists, so that the status code is 200. In other cases the code crashes at httpClient.Get with an exception of class EHTTPClient, ESocketError or EXC_BAD_ACCESS, although the procedure uses a try ... finally section (formulating it as try ... except doesn't change anything). Unfortunately, the exception is raised before the status code can be processed.
What is the recommended way to handle errors with fphttpclient? Is there any method to check for the existence of a resource (and, possibly, the correctness of an URL, too), before invoking the Get method?
Make sure the various events are assigned, so that the class knows what to do on password prompts, redirects etc.
Standard examples init the class like
With TFPHTTPClient.Create(Nil) do
try
AllowRedirect:=True;
OnRedirect:=#ShowRedirect;
OnPassword:=#DoPassword;
OnDataReceived:=#DoProgress;
OnHeaders:=#DoHeaders;
{ Set this if you want to try a proxy.
Proxy.Host:='ahostname.net.domain';
Proxy.Port:=80;
etc.
Please study examples and try to sort through your problems till you have reproducible cases. If then there is still a problem, please submit it to the bugtracker
In rare cases, checking the existences of headers with HEAD() can speed up e.g. sifting through lists of old urls
I have some issues with "expected_title" procedure from watir-page-helper.
It is throwing an error like the current web page has a different title than the expected one, although it is the correct title:
RuntimeError: Expected title 'Some title' instead of 'Some Title'.
This happens randomly, and my tests fail frequently on different pages. The website on which I am working is loading in a reasonable amount of time, I don't think it is a loading page issue.
To initialize the pages I am using the next method:
#new_mail_editor = Module::Page.new(#browser, false)
This is for pages that are opened when accessing links.
Does someone have a clue why this is happening?
Is there a way to dodge this issue?
Thank you.
Watir-page-helper has been end-of-lifed, you should try page-object gem.
Meantime I found out what I was doing wrong. When initializing the browser and checking the title, I was using "has_expected_title?" instead of "expected_title". It seems that I didn't used correctly the first function
Now everything works great.
I am trying to implement a custom web resource using jquery/ajax and odata. I ran into trouble and eventually found that when I call:
var serverUrl = context.getServerUrl();
The code throws exceptions.
However, when I change serverUrl to the literal url, it works. I then found forum posts that said I should verify my .aspx page manually by going to https://[org url]//WebResources/ClientGlobalContext.js.aspx to verify that it is working. When I did that I received a warning page:
The XML page cannot be displayed
Cannot view XML input using style sheet. Please correct the error and then click the Refresh button, or try again later.
--------------------------------------------------------------------------------
Invalid at the top level of the document. Error processing resource 'https://[org url]//WebResources/Clien...
document.write('<script type="text/javascript" src="'+'\x26\x2347\x3b_common\x26\x2347\x3bglobal.ashx\x26\x2363\x3bver\x2...
What the heck does that mean?
Hard to tell outside of context (pun not intended) of your code, but why aren't you doing this?
var serverUrl = Xrm.Page.context.getServerUrl();
(Presumably, because you have defined your own context var?)
Also, this method is deprecated as of Rollup 12, see here: http://msdn.microsoft.com/en-us/library/d7d0b052-abca-4f81-9b86-0b9dc5e62a66. You can now use getClientUrl instead.
I now it is late but hope this will be useful for other people who will face this problem.
Until nowadays even with R15 there are two available ClientGlobalContext.js.aspx
https://[org url]/WebResources/ClientGlobalContext.js.aspx (the bad one)
https://[org url]/[organization name]/[publication id]/WebResources/ClientGlobalContext.js.aspx (The good one)
I don't know why exist 1. but it causes many issues like:
It could not be published or hold information (Your case #Steve).
In a deployment with multiple organizations, seems it saves info only for the last organization deployed causing that methods under Xrm.Page.context. will return info from a fixed organization. Actually each method that underground uses these constants included in ClientGlobalContext.js.aspx: USER_GUID, ORG_LANGUAGE_CODE, ORG_UNIQUE_NAME, SERVER_URL, USER_LANGUAGE_CODE, USER_ROLES, CRM2007_WEBSERVICE_NS, CRM2007_CORETYPES_NS, AUTHENTICATION_TYPE, CURRENT_THEME_TYPE, CURRENT_WEB_THEME, IS_OUTLOOK_CLIENT, IS_OUTLOOK_LAPTOP_CLIENT, IS_OUTLOOK_14_CLIENT, IS_ONLINE, LOCID_UNRECOGNIZE_DOTC, EDIT_PRELOAD, WEB_SERVER_HOST, WEB_SERVER_PORT, IS_PATHBASEDURLS, LOCID_UNRECOGNIZE_DOTC, EDIT_PRELOAD, WEB_RESOURCE_ORG_VERSION_NUMBER, YAMMER_IS_INSTALLED, YAMMER_IS_CONFIGURED_FOR_ORG, YAMMER_APP_ID, YAMMER_NETWORK_NAME, YAMMER_GROUP_ID, YAMMER_TOKEN_EXPIRED, YAMMER_IS_CONFIGURED_FOR_USER, YAMMER_HAS_CONFIGURE_PRIVILEGE, YAMMER_POST_METHOD. For instance method Xrm.Page.context.getUserId() is implemented as return window.USER_GUID;
To be sure that your URL is the correct just follow the link posted by #Chris
I added a few custom pages to my setup. In one of this custom pages I do some checks. If this checks failed, I want switch to finish page. How can I do this?
I can not do this with ShouldSkipPage event function because:
function ShouldSkipPage(PageID: Integer): Boolean;
begin
// this will NEVER happened - see documentation below
if (PageID = wpInstalling) or (PageID = wpPreparing) or (PageID = wpWelcome) then
begin
// skip install - simply for example
result := True;
exit;
end;
resutl := false;
end;
From Inno Setup documentation:
The wizard calls this event function
to determine whether or not a
particular page (specified by PageID)
should be shown at all. If you return
True, the page will be skipped; if you
return False, the page may be shown.
Note: This event function isn't called
for the wpWelcome, wpPreparing, and
wpInstalling pages, nor for pages that
Setup has already determined should be
skipped (for example,
wpSelectComponents in an install
containing no components).
I'm sorry, i did not understand why you cannot use ShouldSkipPage.
The usual way of doing it is in ShouldSkipPage:
function ShouldSkipPage(curPageId : Integer) : Boolean;
begin
{For a certain condition, skip to wpFinished}
if (SomeCondition and (curPageId <> wpFinished)) then
Result := True
{Probably more checks}
else
Result := False
end;
If I understand you correctly, you are performing a check, and if it fails, you want to skip wpWelcome, wpPreparing, and wpInstalling (and perhaps more custom pages).
I assume that you also want to skip the actions performed when these pages are shown, specifically, you don't want to perform the installation step.
If that is the case, you should cancel the installation, not continue it without performing the actual installation steps. You can do it in InitializeSetup, for example:
Procedure InitializeSetup();
VAR
Check: Integer;
BEGIN
// perform you check here, set the variable according to it's result
IF (Check <> 0) THEN
// abort installation
Return False;
ELSE
Return True;
END;
Edit
In response to your comment: The easiest solution would be to show a message box with the result of your check, instead of a complete wizard page. If that is not enough for your purposes I would suggest the following approach:
Perform your check in InitializeSetup and store the result in a global variable.
Create a new wizard page (lets call it CheckResult) to display the results of your check, it should be displayed directly after wpWelcome.
In that page's OnNextButtonClick just call CancelButtonClick, that way the installation is always aborted when this page is displayed
Now is the time to modify ShouldSkipPage ;-) If the global check variable indicates that everything is ok, skip your CheckResult page, so that the installation is not aborted automatically
This should work, but if you somehow can, follow the KISS principle and go with the message box approach.