Javascript function not found when moved to external file - javascript

I'm moderatley new to ASP.NET and very new to Javascript. I'm writing a ASP.NET UserControl. I had the following:
<head>
<title>Select Asset </title>
<script src="../Scripts/jquery-1.9.1.min.js" type="text/javascript"></script>
<script type="text/javascript">
function CheckThenCloseActiveToolTip(supplierID) {
var radGrid = $find('ctl00_MainContent_SelectAssetGrid1_gridAssetList_ctl00');
var selectedItems = radGrid.get_masterTableView().get_selectedItems()
if (selectedItems == null || selectedItems.length == 0) return 'You must select an asset first';
else {
DoPartialPostBack('selectasset', selectedItems[0]._dataItem.Id);
CloseActiveToolTip();
}
}
function PopulateRooms(e) {
var idx = e.selectedIndex;
if (idx > -1) {
var dcId = JSON.stringify({ dataCenterId: e.options[idx].value });
var pageUrl = '/WebService/AVWebService.asmx';
$.ajax({
url: pageUrl + '/GetRooms',
type: 'post',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
data: dcId,
success: OnRoomsReceived,
error: OnErrorCall
});
}
else {
var ddlRooms = document.getElementById('MainContent_SelectAssetGrid1_ddlRooms');
ddlRooms.disabled = true;
$('#ddlRooms').empty();
ddlRooms.options[0] = new Option('', '-1');
getAssets(0);
}
}
function OnRoomsReceived(result) {
var ddlRooms = document.getElementById('MainContent_SelectAssetGrid1_ddlRooms');
if (result.d.length > 0) {
ddlRooms.disabled = false;
$('#ddlRooms').empty();
ddlRooms.options[0] = new Option('', '-1');
for (var i = 0; i < result.d.length; i++) {
ddlRooms.options[i + 1] = new Option(result.d[i].Name, result.d[i].Id);
}
}
if (result.d.length = 1)
ddlRooms.selectedIndex = 1;
getAssets(0);
}
function resetGridData() {
getAssets(0);
}
function getAssets(startAt) {
var cpId = document.getElementById('hfldCompanyId').value;
var pageUrl = '/WebService/AVWebService.asmx';
var tableView = $find('ctl00_MainContent_SelectAssetGrid1_gridAssetList').get_masterTableView();
var ddldc = document.getElementById('MainContent_SelectAssetGrid1_ddlDataCenter');
var dcIdx = ddldc.selectedIndex;
var dcId = '';
if (dcIdx > -1)
dcId = ddldc.options[dcIdx].value;
var ddlrm = document.getElementById('MainContent_SelectAssetGrid1_ddlRooms');
var rmIdx = ddlrm.selectedIndex;
var rmId = '';
if (rmIdx > -1)
rmId = ddlrm.options[rmIdx].value;
var ddlStatuses = $find('ctl00_MainContent_SelectAssetGrid1_ddlStatuses';
var rbgAssetClass = document.getElementById('MainContent_SelectAssetGrid1_rbgAssetClass');
var ac = 0;
var rbgInputs = rbgAssetClass.getElementsByTagName('input');
for (var i = 0; i < rbgInputs.length; i++) {
if (rbgInputs[i].checked) {
ac = i;
}
}
var filters = [];
var fbs = document.getElementsByClassName('rgFilterBox');
for (var i = 0; i < fbs.length; i++)
if (fbs[i].value != '')
filters[filters.length] = { field: fbs[i].alt, value: fbs[i].value };
var params = JSON.stringify({ companyId: cpId,
startIndex: startAt,
maximumRows: tableView.get_pageSize(),
filterExpressions: filters,
dataCenterId: ddldc.options[ddldc.selectedIndex].value,
roomId: rmId,
Statuses: ddlStatuses._checkedIndices,
assetClass: ac
});
$.ajax({
url: pageUrl + '/GetSelectAssetData',
type: 'post',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
data: params,
success: updateGrid,
error: OnErrorCall
});
}
function updateGrid(result) {
var tableView = $find('ctl00_MainContent_SelectAssetGrid1_gridAssetList').get_masterTableView();
tableView.set_dataSource(result.d.gridData);
tableView.dataBind();
tableView.set_virtualItemCount(result.d.count);
}
function gridAssetList_Command(sender, args) {
args.set_cancel(true);
var pageSize = sender.get_masterTableView().get_pageSize();
var currentPageIndex = sender.get_masterTableView().get_currentPageIndex();
if (args.get_commandName() == 'Filter')
currentPageIndex = 0;
getAssets(pageSize * currentPageIndex);
}
function gridAssetList_Created(sender, args) {
var fbtns = document.getElementsByClassName('rgFilter');
for (var i = 0; i < fbtns.length; i++)
fbtns[i].style.visibility = 'hidden';
var fbs = document.getElementsByClassName('rgFilterBox');
for (var i = 0; i < fbs.length; i++)
fbs[i].onkeypress = applyFilter;
}
function applyFilter(args) {
if (args.keyCode == 13)
resetGridData();
}
</script>
This works most of the time, but if I'm loading the UserControl using Page.LoadControl(), it didn't always load the scripts correctly. For a couple of reasons (maybe poor ones) I thought I'd move the scripts to an external file.
<script src="../Scripts/jquery-1.9.1.min.js" type="text/javascript"></script>
<script src="../Scripts/SelectAsset.js" type="text/javascript"></script>
There's no additional code or setup in the .js file, just
function CheckThenCloseActiveToolTip(supplierID) {
var radGrid = $find('ctl00_MainContent_SelectAssetGrid1_gridAssetList_ctl00');
var selectedItems = radGrid.get_masterTableView().get_selectedItems()
if (selectedItems == null || selectedItems.length == 0) return 'You must select an asset first';
...
But now I get a RunTime error that "function gridAssetList_Command" us undefined. That function is bound to a grid's OnCommand event in the page .
When I examine the page in Firebug, it doesn't list my .js file in the list of script files.
I'm loading my scripts in the . I didn't change them, just moved them. What am I missing?
MORE INFO:
It appears to be using different ClientIds when adding the functions to the controls. The error I'm getting drops be in a dynamic resource with the following:
Sys.Application.add_init(function() {
$create(Telerik.Web.UI.RadGrid, {"ClientID":"ctl00_MainContent_ctl03_gridAssetList","ClientSettings": ...
I'm going to try changing referenes to getElementByClass()

The best way to add javascript reference on asp.net web form is using ScriptManager on parent element or parent page such as a Master Page, And use ScriptManagerProxy on content pages and user controls.
Try use ScriptManager or combination of both to resolve your problem. Also use root application alias (~) for refer to file ex. src="~/Scripts/jquery-1.9.1.min.js"
So for simple way change your script reference to become:
<asp:ScriptManager ID="ScriptManagerProxy1" runat="server">
<Scripts>
<asp:ScriptReference Path="~/Scripts/jquery-1.9.1.min.js" />
<asp:ScriptReference Path="~/Scripts/SelectAsset.js" />
</Scripts>
</asp:ScriptManager>
Update:
use for example:
$('table[id*="gridAssetList"]') for table with id = ctl00_gridAssetList_xx
$('input[id*="inputTxt"]') for input with id = ctl100_inputTxt
etc
to call html tag that rendered by asp.net component using jquery selector.

hi steve i think its shows error due to script source path please check that first then to verify the script loaded or not try this below code
if(typeof(yourfunction_name=='function')
{
// this code will make sure that the function is present in the page
//function exits do your functionality.
}else
{
alert('Script not loaded');
}

Related

How to refer on dynamically created variables

I want to know if it is possible to refer to an dynamically created variables and if yes how?
I create on this site many forms which have p elements on the bottom is one button and if I click that button I want to transmit the variable(IdJB) which was created specific in this form.
I marked the variable with a command in the code.
$(document).ready(function() {
var Id = sessionStorage.getItem('Id');
var status = 0;
var nummer = 0;
$.ajax({
type: "POST",
url: "http://localhost/jQuery&PHPnew/Markt.N.php",
data: {
status: status
},
success: function(data) {
var anzahl = data;
status = 1;
while (anzahl > nummer) {
nummer++;
$.ajax({
type: "POST",
url: "http://localhost/jQuery&PHPnew/Markt.N.php",
data: {
nummer: nummer,
status: status
},
success: function(data) {
var Daten = JSON.parse(data);
var Ausgabebereich = document.getElementById('main');
var IdJB = Daten.id;
window.IdJB = IdJB; //This Variable !!!!!!!!!!!!!
var f = document.createElement("form");
var pInhalt = document.createElement('p');
var Inhalt = document.createTextNode(Daten.inhalt);
pInhalt.appendChild(Inhalt);
f.appendChild(pInhalt);
var pDatum = document.createElement('p');
var Inhalt = document.createTextNode(Daten.datum);
pDatum.appendChild(Inhalt);
f.appendChild(pDatum);
var pUhrzeit = document.createElement('p');
var Inhalt = document.createTextNode(Daten.uhrzeit);
pUhrzeit.appendChild(Inhalt);
f.appendChild(pUhrzeit);
var pGehalt = document.createElement('p');
var Inhalt = document.createTextNode(Daten.gehalt);
pGehalt.appendChild(Inhalt);
f.appendChild(pGehalt);
var pDauer = document.createElement('p');
var Inhalt = document.createTextNode(Daten.dauer);
pDauer.appendChild(Inhalt);
f.appendChild(pDauer);
var pAdresse = document.createElement('p');
var Inhalt = document.createTextNode(Daten.adresse);
pAdresse.appendChild(Inhalt);
f.appendChild(pAdresse);
var pNam_ersteller = document.createElement('p');
var Inhalt = document.createTextNode(Daten.nam_ersteller);
pNam_ersteller.appendChild(Inhalt);
f.appendChild(pNam_ersteller);
var bInhalt = document.createElement('button');
var Inhalt = document.createTextNode("Senden");
bInhalt.appendChild(Inhalt);
bInhalt.setAttribute("type", "button");
bInhalt.setAttribute("onclick", "zuJB()");
f.appendChild(bInhalt);
Ausgabebereich.appendChild(f);
$(document).on('click', 'button', function() {
sessionStorage.setItem('IdJB', IdJB); //Here !!!!!!!!!!!!!
alert(IdJB);
window.location = "http://localhost/jQuery&PHPnew/JobBlock.html";
});
}
})
}
}
})
$("#sub").click(function() {
window.location = "http://localhost/jQuery&PHPnew/Markt.html";
})
})
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Jobs</title>
<script type="text/javascript" src="jQuery.js"></script>
<script type="text/javascript">
</script>
</head>
<body>
<button id="sub">Update</button>
Alle Jobs
Meine Jobs
Einstellungen
<main id="main">
</main>
</body>
</html>
This is how the Programm looks like
Don't use a global variable. Put IdJB in an attribute of the button. You can use the jQuery .data() method for this.
Also, don't add the event handler every time through the loop. When you use event delegation, you should just add the handler once.
$(document).ready(function() {
$(document).on('click', 'button', function() {
var IdJB = $(this).data("IdJB");
sessionStorage.setItem('IdJB', IdJB);
alert(IdJB);
window.location = "http://localhost/jQuery&PHPnew/JobBlock.html";
});
var Id = sessionStorage.getItem('Id');
var status = 0;
var nummer = 0;
$.ajax({
type: "POST",
url: "http://localhost/jQuery&PHPnew/Markt.N.php",
data: {
status: status
},
success: function(data) {
var anzahl = data;
status = 1;
while (anzahl > nummer) {
nummer++;
$.ajax({
type: "POST",
url: "http://localhost/jQuery&PHPnew/Markt.N.php",
data: {
nummer: nummer,
status: status
},
success: function(data) {
var Daten = JSON.parse(data);
var Ausgabebereich = document.getElementById('main');
var IdJB = Daten.id;
window.IdJB = IdJB; //This Variable !!!!!!!!!!!!!
var f = document.createElement("form");
var pInhalt = document.createElement('p');
var Inhalt = document.createTextNode(Daten.inhalt);
pInhalt.appendChild(Inhalt);
f.appendChild(pInhalt);
var pDatum = document.createElement('p');
var Inhalt = document.createTextNode(Daten.datum);
pDatum.appendChild(Inhalt);
f.appendChild(pDatum);
var pUhrzeit = document.createElement('p');
var Inhalt = document.createTextNode(Daten.uhrzeit);
pUhrzeit.appendChild(Inhalt);
f.appendChild(pUhrzeit);
var pGehalt = document.createElement('p');
var Inhalt = document.createTextNode(Daten.gehalt);
pGehalt.appendChild(Inhalt);
f.appendChild(pGehalt);
var pDauer = document.createElement('p');
var Inhalt = document.createTextNode(Daten.dauer);
pDauer.appendChild(Inhalt);
f.appendChild(pDauer);
var pAdresse = document.createElement('p');
var Inhalt = document.createTextNode(Daten.adresse);
pAdresse.appendChild(Inhalt);
f.appendChild(pAdresse);
var pNam_ersteller = document.createElement('p');
var Inhalt = document.createTextNode(Daten.nam_ersteller);
pNam_ersteller.appendChild(Inhalt);
f.appendChild(pNam_ersteller);
var bInhalt = document.createElement('button');
var Inhalt = document.createTextNode("Senden");
bInhalt.appendChild(Inhalt);
bInhalt.setAttribute("type", "button");
bInhalt.setAttribute("onclick", "zuJB()");
f.appendChild(bInhalt);
$(bInhalt).data('IdJB', IdJB);
Ausgabebereich.appendChild(f);
}
})
}
}
})
$("#sub").click(function() {
window.location = "http://localhost/jQuery&PHPnew/Markt.html";
})
})
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Jobs</title>
<script type="text/javascript" src="jQuery.js"></script>
<script type="text/javascript">
</script>
</head>
<body>
<button id="sub">Update</button>
Alle Jobs
Meine Jobs
Einstellungen
<main id="main">
</main>
</body>
</html>
I may be misunderstanding your question, but if not: In order to reference dynamically created elements, the click handler just needs to be instantiated after the element is created and put in the DOM. An easy way to handle this is by having a function generate your tag like so:
function appendTag(parent, child){
parent.append(child)
child.click(function(){
//Click code here
});
}
So it looks like when you are adding the button click event dynamically you are adding it to all the buttons on the page. This is why when you click one it runs 3 times.
This can be seen by the button text in this line of code:
$(document).on('click', 'button', function() {
.....
});
To address this problem you need to make the click listener specific to the button. You can do that by making a more specific button selector. Although it's not a perfect solution one way to do this is to give each button a unique I'd. Something like button-## where ## here is a different number each time you create a new button. You can then do:
$(document).on('click', '#button-##', function() {
.....
});
Again replacing ## with the corresponding Id value.
Edit: actually you can use the answer #Laif posted by rather than using the $(document).on( call just simply do b.click()

AJAX - reload page if JSON has changed

I cannot find a suitable way to achieve this:
I have this script
<script type="text/javascript">
function updateSpots() {
$.ajax({
url : '/epark/api/spots/last',
dataType : 'text',
success : function(data) {
var json = $.parseJSON(data);
var currentMessage = json.dateTime;
var idPosto = json.idPosto;
console.log('current '+currentMessage);
console.log('old '+oldMessage);
if(currentMessage != oldMessage){
setTimeout(function(){location.reload();}, 5000);
$('#idPosto').toggle("higlight");
}
oldMessage = currentMessage;
}
});
}
var intervalId = 0;
intervalId = setInterval(updateSpots, 3000);
var oldMessage ="";
</script>
This should check every 3 seconds if the dateTimehas changed on the JSON.
The problem is that I cannot get to go further first step. I mean, when the page loads, oldMessageempty so the if condition is not satisfied. If I could "jump" this first iteration, then everything would go well...
var oldMessage = false;
//...
if (oldMessage && oldMessage !== currentMessage) {
//...

Google Contacts API error

I'm using the following code to get google contacts name and phone number. Authorization page itself is not coming properly it shows error as "The page you requested is invalid". :( pls help me to solve this...
`
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load("gdata", "1.x");
var contactsService;
function setupContactsService()
{
contactsService = new google.gdata.contacts.ContactsService('exampleCo-exampleApp-1.0');
}
function logMeIn() {
var scope = 'https://www.google.com/m8/feeds';
var token = google.accounts.user.login(scope);
}
function initFunc() {
setupContactsService();
logMeIn();
getMyContacts();
}
function checkLoggedIn(){
scope = "https://www.google.com/m8/feeds";
var token = google.accounts.user.checkLogin(scope);
if(token != "")
return true;
else
return false;
}
function getMyContacts() {
var contactsFeedUri = 'https://www.google.com/m8/feeds/contacts/default/full';
var query = new google.gdata.contacts.ContactQuery(contactsFeedUri);
//We load all results by default//
query.setMaxResults(10);
contactsService.getContactFeed(query, handleContactsFeed, ContactsServiceInitError);
}
//Gets the contacts feed passed as parameter//
var handleContactsFeed = function(result) {
//All contact entries//
entries = result.feed.entry;
for (var i = 0; i < entries.length; i++) {
var contactEntry = entries[i];
var telNumbers = contactEntry.getPhoneNumbers();
var title = contactEntry.getTitle().getText();
}
}
</script>
<body>
<input type="submit" value="Login to Google" id="glogin" onclick="initFunc();">
</body>`
Thanks
It looks like you are trying to use the Google Contacts 1.X API. That's been deprecated. Look at the JavaScript examples for the Google 3.X API and see if that helps.
You can try this example
var config = {
'client_id': 'Client ID',
'scope': 'https://www.google.com/m8/feeds'
};
inviteContacts = function() {
gapi.auth.authorize($scope.config, function() {
fetch(gapi.auth.getToken());
});
}
function fetch(token) {
$.get("https://www.google.com/m8/feeds/contacts/default/full?access_token=" + token.access_token + "&alt=json", function(response) {
console.log(response);
//console.log(response.data.feed.entry);
});
}
Don't forget to add <script src="https://apis.google.com/js/client.js"></script> into your html file. Good Luck!

Javascript code not displaying wanted output

I've written some code to display my favorites in IE8 but for an unknown reason I have no output on the screen despite the fact that my page is accepted by IE and that the test text 'this is a test' is displayed.
my code :
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso 8859-1" />
<script type="text/javascript">
var i = 0;
var favString = "";
var fso;
function GetFavourites(Folder) {
var FavFolder = fso.GetFolder(Folder);
//Gets Favourite Names & URL's for given folder.
var files = new Enumerator(FavFolder.Files);
for (; !files.atEnd(); files.moveNext()) {
var fil = files.item();
if (fil.Type == "Internet Shortcut") {
var textReader = fso.OpenTextFile(fil.Path, 1, false, -2);
var favtext = textReader.ReadAll();
var start = favtext.indexOf("URL", 16);
var stop = favtext.indexOf("\n", start);
favString += fil.Name.replace(/.url/, "");
favString += ":URL:";
//to separate favourite name & favorite URL
favString += favtext.substring(start + 4, stop - 1);
favorites.innerHTML += favString; // Not working !
favorites.innerHTML += 'test'; // Not working too !
favString += ":NEXT:"; //to separate favorites.
i++;
}
}
//Checks any subfolder exists
var subfolders = new Enumerator(FavFolder.SubFolders);
for (; !subfolders.atEnd(); subfolders.moveNext()) {
var folder = subfolders.item();
GetFavourites(folder.Path);
}
}
function Import() {
try {
fso = new ActiveXObject("Scripting.FileSystemObject");
if (fso !== null) {
//Create windows script shell object to access Favorites folder in user system.
var object = new ActiveXObject("WScript.Shell");
var favfolderName = object.SpecialFolders("Favorites");
if (favString === "") {
GetFavourites(favfolderName);
}
}
}
catch (err) {
alert("Security settings to be modified in your browser ");
}
}
</script>
</head>
<body onload="Import()">
<p>this is a test</p> <!-- Working ! -->
<div id="favorites">
</div>
</body>
</html>
The following works for me:
var fso, favs = [];
function GetFavourites(Folder) {
var FavFolder = fso.GetFolder(Folder);
//Gets Favourite Names & URL's for given folder.
var files = new Enumerator(FavFolder.Files);
for (; !files.atEnd(); files.moveNext()) {
var fil = files.item();
if (fil.Type == "Internet Shortcut") {
var textReader = fso.OpenTextFile(fil.Path, 1, false, -2);
var favtext = textReader.ReadAll();
var start = favtext.indexOf("URL", 16);
var stop = favtext.indexOf("\n", start);
favString = fil.Name.replace(/.url/, "");
favString += ":URL:";
//to separate favourite name & favorite URL
favString += favtext.substring(start + 4, stop - 1);
favs.push(favString);
}
}
//Checks any subfolder exists
var subfolders = new Enumerator(FavFolder.SubFolders);
for (; !subfolders.atEnd(); subfolders.moveNext()) {
var folder = subfolders.item();
GetFavourites(folder.Path);
}
}
function Import() {
try {
fso = new ActiveXObject("Scripting.FileSystemObject");
if (fso !== null) {
//Create windows script shell object to access Favorites folder in user system.
var object = new ActiveXObject("WScript.Shell");
var favfolderName = object.SpecialFolders("Favorites");
if (favString === "") {
GetFavourites(favfolderName);
}
}
}
catch (err) {
alert("Security settings to be modified in your browser ");
}
}
Note that all I changed was the output from an element to an array named favs. I also removed the i variable, because it wasn't used. After running the script, I checked the array in the developer tools console and it contained all my favourites.
If you're getting no output at all, then either fso is null in the Import method or files.AtEnd() always evaluates to false. Since you're focusing on IE here, you might consider placing alert methods in various places with values to debug (such as alert(fso);) throughout your expected code path.

How to dynamically read RSS

I want to read multiple RSS feeds using jQuery.
I'm trying to write a flexible function that will just take the RSS URL and it will output only its TITLE AND IMAGE how to do that for multiple RSS URLs?
The easiest way would be to use the Google AJAX Feed API. They have a really simple example, which suits what you want nicely:
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load("feeds", "1");
function initialize() {
var feed = new google.feeds.Feed("http://www.digg.com/rss/index.xml");
feed.load(function(result) {
if (!result.error) {
var container = document.getElementById("feed");
for (var i = 0; i < result.feed.entries.length; i++) {
var entry = result.feed.entries[i];
var div = document.createElement("div");
div.appendChild(document.createTextNode(entry.title));
container.appendChild(div);
}
}
});
}
google.setOnLoadCallback(initialize);
</script>
<div id="feed"></div>
Of course, you can mix jQuery with the API instead of using native DOM calls.
Have you seen this JQuery plug-in: http://plugins.jquery.com/project/jFeed
A little late to the party but I actually did something similar to this using the deviantART gallery feed and displaying the latest thumbnail. I wrapped it up into a couple of functions for easy use:
function keratin_callback(elem, data)
{
if (!data
|| !data.entries
|| data.entries.length < 1
|| !data.entries[0].mediaGroups
|| data.entries[0].mediaGroups.length < 1
|| !data.entries[0].mediaGroups[0].contents
|| data.entries[0].mediaGroups[0].contents.length < 1
|| !data.entries[0].mediaGroups[0].contents[0].thumbnails
|| data.entries[0].mediaGroups[0].contents[0].thumbnails.length < 1) {
$("<span>Data returned from feed not in expected format.</span>").appendTo(elem);
return;
}
var entry = data.entries[0];
$("<img>").attr("src", entry.mediaGroups[0].contents[0].thumbnails[0].url)
.appendTo(elem)
.wrap("");
}
function keratin(elem, url)
{
//keratin written by adam james naylor - www.adamjamesnaylor.com
if (!elem || elem.length < 1) return; //no element found
$.ajax({
//you could use document.location.protocol on the below line if your site uses HTTPS
url: 'http:' + '//ajax.googleapis.com/ajax/services/feed/load?v=1.0&num=10&callback=?&q=' + encodeURIComponent(url + '&cache=' + Date.UTC()),
dataType: 'json',
success: function(data) {
if (!data || !data.responseData) {
return keratin_callback(elem, null);
}
return keratin_callback(elem, data.responseData.feed);
}
});
}
$(document).ready(function() {
keratin($('#da_gallery'), 'http://backend.deviantart.com/rss.xml?q=gallery%3Adeusuk%2F28671222&type=deviation')
});
Full details here: http://www.adamjamesnaylor.com/2012/11/05/Keratin-DeviantART-Latest-Deviation-Widget.aspx

Categories

Resources