I got the following code which was written into a Chrome Extension (Javascript?)
;
(function() {
function findCaptcha() {
return document.querySelector('.g-recaptcha') || document.getElementById('g-recaptcha');
}
function completeCaptch(intervalID) {
intervalID = setInterval(function() {
if (findCaptcha() != null) {
findCaptcha()
.remove();
clearInterval(intervalID);
}
}, 200);
}
var loadedID = null;
if (location.hash === '#checkout' || location.pathname === '/checkout') {
completeCaptch(loadedID);
}
var stateID = null;
window.addEventListener('popstate', function(event) {
stateID = null;
clearInterval(stateID);
if (location.hash === '#checkout' || location.pathname === '/checkout') {
completeCaptch(stateID);
}
}, false);
})();
Reading this code is simple enough, it calls the function completeCaptch with some sort of ID that is irrelevant and then calls the function findCaptch if it is present (return document.querySelector('.g-recaptcha') || document.getElementById('g-recaptcha');) and simply removes the document.ID by calling .remove();
This is code that bypasses reCAPTCHA in a demo and I was wondering if it is possible to convert this code (whatever it was written in) to C# if I were to use a .net WebBrowser.
Using a .net WebBrowser I would be able to getElementById but would I be able to call .remove() in C#?
Thanks.
Checkout the HtmlAgilityPack library. It's a fantastic library for dealing with HTML DOMs, allowing you to do something like this:
doc.DocumentNode.SelectSingleNode("/xpath/to/node").Remove();
Related
I'm implemeting a very simple use case, and yet not only do I not find a solution, but I can't find any article that talks about it, as if I was the only one.
I want my custom Javascript to execute on every page of a given SharePoint site.
Easy, you'll say. Well, no. Far from it, like always with SharePoint.
Steps to reproduce :
Create a out-of-the-box publishing site
Include the custom javascript below using any of the means I describe below
Go to the site, to the home page. It's a publishing site, so by default you should have the left navigation pane with at least "Home" and "Documents" by default.
The first time you load the page, the javascript executes. Now, click on "documents". The page changes but the Javascript is not executed.
That's because SharePoint uses Ajax. Even if the MDS is disabled. It uses Ajax through the hash ( # ) in the URL.
For example, it transforms a very inocuous link like this one :
< a href src="/SitePages/Home.aspx">
into this URL when you click it:
https://your-url/sites/your-site/_layouts/15/start.aspx#/SitePages/Home.aspx
Here is my Javascript :
if (ExecuteOrDelayUntilScriptLoaded && _spBodyOnLoadFunctionNames) {
_spBodyOnLoadFunctionNames.push(ExecuteOrDelayUntilScriptLoaded(
function () {
alert("It's working!");
}, "sp.js"));
}
So, I've tried the following ways of including the Javascript :
Through a User Custom Action. I've used this very handy page to add it, but that's not relevant. The action is added to the site and I can see the JS in the DOM on first load. But then after I click on a link in the page and after SP uses Ajax, it does not execute it again.
By modifying the master page -- namely: seattle.html. at first I included it this way, simply under other native inclusions :
<head runat="server">
...
<!--SPM:<SharePoint:ScriptLink language="javascript" name="suitelinks.js" OnDemand="true" runat="server" Localizable="false"/>-->
<!--SPM:<SharePoint:ScriptLink language="javascript" Name="~sitecollection/SiteAssets/MYJAVASCRIPT.js" runat="server"/>-->
But then I read about AjaxDelta (here : https://msdn.microsoft.com/fr-fr/library/office/dn456543.aspx ) , and I moved my inclusion (still in the header) into < AjaxDelta >, like this :
<head runat="server">
...
<!--SPM:<SharePoint:AjaxDelta id="DeltaPlaceHolderAdditionalPageHead" Container="false" runat="server">-->
<!--SPM:<asp:ContentPlaceHolder id="PlaceHolderAdditionalPageHead" runat="server"/>-->
<!--SPM:<SharePoint:DelegateControl runat="server" ControlId="AdditionalPageHead" AllowMultipleControls="true"/>-->
<!--SPM:<SharePoint:ScriptLink language="javascript" Name="~sitecollection/SiteAssets/MYJAVASCRIPT.js" runat="server"/>-->
<!--SPM:</SharePoint:AjaxDelta>-->
...and yet nothing works. The Javascript is never executed when switching between pages of the same site by clicking on SharePoint's "managed" links.
I'm looking for a solution that handles elegantly SharePoint's Ajax, not something heavy and risky that hijacks every hyperlink on a page. For example I've tried to hook my code onto ajaxNavigate methods (for example : addNavigate) but I'm not sure I understand what's actualy going on there and if it could be of any help to me.
EDIT :
There seems to be a consensus (for example, here at the very bottom) that User Custom Actions get executed no matter what -- because SharePoint allegedly places their ScriptLink into the AjaxDelta for some reason. Well, that's not what I witnessed.
There's another consensus that this issue can be adressed by using "RegisterModuleInit". This doesn't work for me either.
I'm extermely puzzled. I think those two solutions do address navigation issues when the user clicks on a link and then clicks "back". But it does NOT address SharePoint's clever "managed", Ajax-riddled, hyperlinks.
I've finally found a solution that never seems to fail so far. That's a real relief.
Short answer: use asyncDeltaManager.add_endRequest
This MSDN discussion suggests a simple way to implement it:
https://social.msdn.microsoft.com/Forums/office/en-US/1ae292b4-3589-46f6-bedc-7bd9dc741f1b/javascript-code-to-execute-after-all-the-elements-and-css-are-loaded?forum=appsforsharepoint
$(function () {
ExecuteOrDelayUntilScriptLoaded(function () {
if (typeof asyncDeltaManager != "undefined")
asyncDeltaManager.add_endRequest(MYCUSTOMCODE); //execute it after any ajax event
else
MYCUSTOMCODE(); //execute it at first load
}, "start.js");
});
This shows how to include it properly in SharePoint's cycle (with ExecuteOrDelayUntilScriptLoaded )
https://sharepoint.stackexchange.com/questions/171490/javacript-only-executed-on-first-page-load
Full-blown solution (objet "LefeCycleHelper"), by Mx
https://sharepoint.stackexchange.com/questions/192974/where-to-place-a-js-script-with-whom-i-need-to-get-an-div-id/193009#193009
//use an IIFE to create a scope and dont dirty the global scope
(function (_) {
// use strict to ensure we dont code stupid
'use strict';
var initHandlers = [];
var initMDSHandlers = [];
var ensureSharePoint = function (handler) {
var sodLoaded = typeof (_v_dictSod) !== 'undefined' && _v_dictSod['sp.js'] != null && _v_dictSod['sp.js'].state === Sods.loaded;
if (sodLoaded) {
handler();
} else {
SP.SOD.executeFunc('sp.js', 'SP.ClientContext', function () { });
SP.SOD.executeOrDelayUntilScriptLoaded(handler, 'sp.js');
}
};
var initMDS = function () {
for (var i = 0; i < initMDSHandlers.length; i++) {
initMDSHandlers[i]();
}
};
var init = function () {
// Register MDS handler
if ('undefined' != typeof g_MinimalDownload && g_MinimalDownload && (window.location.pathname.toLowerCase()).endsWith('/_layouts/15/start.aspx') && 'undefined' != typeof asyncDeltaManager) {
asyncDeltaManager.add_endRequest(initMDS);
} else {
for (var i = 0; i < initHandlers.length; i++) {
initHandlers[i]();
}
}
};
var registerInit = function (handler) {
initHandlers.push(handler);
};
var registerInitMDS = function (handler) {
initMDSHandlers.push(handler);
};
var domReady = (function (handler) {
var fns = [];
var listener;
var loaded = (document.documentElement.doScroll ? /^loaded|^c/ : /^loaded|^i|^c/).test(document.readyState);
if (!loaded) {
document.addEventListener('DOMContentLoaded', listener = function () {
document.removeEventListener('DOMContentLoaded', listener);
loaded = 1;
while (listener = fns.shift()) listener();
});
}
return function (fn) {
loaded ? setTimeout(fn, 0) : fns.push(fn);
};
})();
var attachToLoad = function (functionToAttach) {
registerInit(functionToAttach);
registerInitMDS(functionToAttach);
domReady(function () {
init();
});
};
_.AttachToLoad = attachToLoad;
// THIS WILL PROTECT YOUR GLOBAL VAR FROM THE GARBAGE COLLECTOR
window.LifeCycleHelper = _;
if (window.Function != 'undefined' && typeof (Function.registerNamespace) == 'function') {
Function.registerNamespace('LifeCycleHelper');
}
})({});
var theCodeYouWantToRun = function () {
alert('theCodeYouWantToRun');
};
window.LifeCycleHelper.AttachToLoad(theCodeYouWantToRun);
The goal of this is to have my extension wait for a change in the History, depending on what it says, do a certain action.
Here is what I have so far
popup.js
chrome.tabs.update({ url: "https://www.WEBSITE.com/messages" });
chrome.webNavigation.onHistoryStateUpdated.addListener(function(details) {
if (details.url.indexOf("messages") >= 0) {
chrome.extension.getBackgroundPage().chrome.tabs.executeScript(null, {
file: 'getInboxStats.js'
});;
} else {//if (details.url.indexOf("match") >= 0) {
chrome.extension.getBackgroundPage().chrome.tabs.executeScript(null, {
file: 'startBotting.js'
});;
}
});
chrome.runtime.onMessage.addListener(function(message) {
if (message.type == "emptyAmount") {
emptyAmount = message.content;
if (!(percentageOfMessages > 0)) {
percentageOfMessages = 50;
}
amountToSend = Math.floor(emptyAmount * (percentageOfMessages / 100));
alert(amountToSend);
chrome.tabs.update({ url: "https://www.WEBSITE.com/match" });
}
});
getInboxStats.js
var currentAmount = document.getElementsByClassName('count')[1].innerHTML;
var maxAmount = document.getElementsByClassName('total')[0].innerHTML;
var emptyAmount = maxAmount - currentAmount;
chrome.runtime.sendMessage({ content: emptyAmount, type: "emptyAmount" });
startBotting.js
alert("TEST");
The issue I have is that the getInboxStats.js starts, but it's like the onHistoryStateUpdated only seems to work once because the file startBotting.js never displays an alert that says 'TEST'
You misunderstand the purpose of onHistoryStateUpdated.
It captures the instances of history state manipulation without navigation via History API as opposed to regular navigation. When you call update({url: "..."}) it's a regular navigation.
If you're really concerned about browser history updates, you should be using chrome.history.onVisited.
If you want to use webNavigation API to capture regular navigations, you should use onCommitted event.
You should also look into chrome.tabs API.
I have javascript code like this:
<a href="javascript:window.history.back()"...
When I test my website (using HTML5, MVC4) in a browser, it works fine. But when I run it in an Android/iPhone app using a embedded browser my back link doesn't work.
Is there a way to simulate a history.back using razor, like Url.Action?
You can save a previous page url in session. Something like this:
public ActionResult SomeCoolController(SomeCoolClass parameters) {
//some logic
var previousPageUrl = Session["PreviousPageUrl"];
if(previousPageUrl == null)
Session["PreviousPageUrl"] = Request.Url;
var isTimeToChangePreviousUrl = Session["IsTimeToChangePreviousUrl"];
if(isTimeToChangePreviousUrl != null) {
if(isTimeToChangePreviousUrl) {
Session["IsTimeToChangePreviousUrl"] = false;
Session["PreviousPageUrl"] = Request.Url;
} else {
Session["IsTimeToChangePreviousUrl"] = true;
}
} else {
Session["IsTimeToChangePreviousUrl"] = false;
}
//some return
}
Also to don't always copy/paste this code you can write your own SuperDupaActionResult which will be inherit from ActionResult and contain the code above (as a method for example).
I'm developing a simple gadget for Windows 7 as a learning exercise.
I read in this article (under the subtopic Gadgets and Script) that to initialize the gadget, you should use document.onreadystatechange instead of events such as onLOad. I've seen it in the example project code I've looked through as well. This is what I came up with for my project.
document.onreadystatechange = function()
{
if(document.readyState == "complete")
{
System.Gadget.settingsUI = "settings.html"; //this line enables the settings UI
System.Gadget.onSettingsClosed = settingsClosed;
}
}
However when I use this snippet in my work, it doesn't work. The Options button in the gadget doesn't show up. If I use onLoad, it works. I have installed 2 gadgets. Each of them use these 2 methods. One use onLoad and the other use document.onreadystatechange. And both of them works!
Now I'm confused why it doesn't work with my gadget. Is there any important part I'm overlooking?
try something along these lines,
move your onsettingsclosed to a different event and call the function with it
document.onreadystatechange = function()
{
if(document.readyState=="complete")
{
var searchTags = System.Gadget.Settings.read("searchTags");
if(searchTags != "")
{
searchBox.value = searchTags;
}
}
}
System.Gadget.onSettingsClosing = function(event)
{
if (event.closeAction == event.Action.commit)
{
var searchTags = searchBox.value;
if(searchTags != "")
{
System.Gadget.Settings.write("searchTags", searchTags);
}
event.cancel = false;
}
}
We'd like to allow our users to download an hta file and run our web app inside it, and have certain pages detect that they are running in an hta file and offer additional features that a web app wouldn't normally have permission to do.
How can I simply detect if the page is being browsed from an hta file container?
window.location.protocol=='file:' would indicate a local page but that could be a local
html page or a local hta.
I'm thinking window.external may be different in each context.
So making and opening a.htm and a.hta containing:
<script>document.write(window.external)</script>
We get:
IE: [object]
FireFox: [xpconnect wrapped (nsISupports, nsISidebar, nsISidebarExternal, nsIClassInfo)]
Chrome: [object Object]
HTA: null
So, isHTA=(window.external==null) would indicate the HTA context.
Or, isHTA=false;try{isHTA=(window.external==null)}catch(e){}
To be on the safe side, since I have only tested current versions of IE, FF, and Chrome and who knows what the other browsers will do.
What about just:-
var isHTA = (document.all && top.document && (top.document.getElementsByTagName('application')[0]));
HTAs are unique in how they populate the DOM with the <HTA:APPLICATION> tag. I use the following to grab the HTA object:
var hta;
var elements = document.getElementsByTagName("APPLICATION");
for(var i=0; i<elements.length; i+=1) {
if ("hta" === elements[i].scopeName.toString().toLowerCase()) {
hta = elements[i];
break;
}
}
// To test if the page is an HTA:
var isHta = (undefined !== hta);
In other browsers, you will have to use the full tag name to access the same object:
// For Firefox/Chrome/IE
var elements = document.getElementsByTagName("HTA:APPLICATION");
I haven't tested, but wouldn't just looking at window.location work?
This might fit the bill. Verifying the attributes could be removed.
<hta:application id="myHTA"/>
<script>
alert("isHTA = " + isHTA("myHTA"));
function isHTA(htaId) {
var retval = false;
var hta = window[htaId];
if (!hta) {
// hta wasn't defined
} else if (hta.scopeName != "hta") {
// hta:application
} else if (hta.nodeName != "application") {
// hta:application
} else if (hta.tagName != "application") {
// hta:application
} else {
retval = true;
// attributes only a real hta would have
var attribKeys = [
"applicationName",
"border",
"borderStyle",
"caption",
"commandLine",
"contextMenu",
"icon",
"innerBorder",
"maximizeButton",
"minimizeButton",
"scroll",
"scrollFlat",
"selection",
"showInTaskBar",
"singleInstance",
"sysMenu",
"version",
"windowState"
];
for (var i=0;i<attribKeys.length;i++) {
var attribKey = attribKeys[i];
if (!hta.attribKey === undefined) {
retval = false;
break;
}
}
}
return retval;
}
</script>
Checking the commandLine property of the HTA-Application object is the best method to see if you are running as real HTML-Application, because this property is only available in the mshta.exe.
You need to get the HTM-Application object to check this property. If you don't know the ID of the object you can use this code:
// Check if running in a HTML-Application
var isHTA = false;
var htaApp = document.getElementsByTagName("HTA:APPLICATION")
if (!htaApp.length) {
htaApp = document.getElementsByTagName("APPLICATION");
}
if (htaApp.length == 1 && htaApp[0]) {
isHTA = typeof htaApp[0].commandLine !== "undefined";
}
guess not many people still using HTA nowadays, anyway, I think the below should cover all the scenarios:
<script language=javascript>
var VBScriptVersion = "";
function getVBScriptVersion() {
var firstScriptBlock = document.getElementsByTagName('script')[0];
var tmpScript = document.createElement('script');
tmpScript.setAttribute("language", "VBScript");
tmpScript.text = 'VBScriptVersion = ScriptEngineMajorVersion & "." & ScriptEngineMinorVersion';
tmpScript.async = false;
tmpScript.onload = function() {
this.parentNode.removeChild(this);
}
firstScriptBlock.parentNode.insertBefore(tmpScript, firstScriptBlock);
return VBScriptVersion;
}
var isHTA = (getVBScriptVersion()!="" && window.external==null);
</script>