I'm creating a google site for my company and I'm utilizing google apps scripts to do a little extra on the site. I would really like to link a script to a drop-down menu that I made. However, I can't figure out how to link the script. I know how to link a script just as a google gadget and as a stand alone link, but I would really like to have the script run when I click on an item from my drop-down menu.
For security reasons, Google don't let you put javascript in Google Sites.
They provide Apps Scripts instead, but as they work on an isolated world (on the server rather than the browser), its very tricky and has its ways.
Because its very different to standard page's javascript, you have to rethink your goal in terms of what Apps Scripts lets you do.
Google Apps Scripts lets you build an User Interface (using its yet experimental UI API) that can be visualized as a standalone script in a full page or inserted in a iframe in Sites. This means you won't have a dropdown menu overlaping your site: you need an static space to visualize your script's UI.
There is another more primitive way to "embed" your scripts commands in your site: use links. A link that fires a script, even with your own parameters, only to run de command, but without any UI. You can make a menu with options, each of them fires a script. But I'm not talking about dropdown menu.
About Google Apps Scripts User Interfaces
https://developers.google.com/apps-script/guide_user_interfaces
https://developers.google.com/apps-script/guide_gui_builder
https://developers.google.com/apps-script/service_ui
Not sure what you mean by "link the script", do you have code someplace else? By "link" it sounds like you mean to "Call" the code, with an event handler. I'll show you how to call a function with a ServerHandler triggered by either a GUI ListBox Change event or from a Button Click event.
In Google Apps Scrips (GAS) there are three methods to do GUI.
HTML Service - Much like plain HTML, you could insert HTML form and input tags.
UI Service - Much like java (as far as layout managers), see below.
GUI Builder - I suggest doing it manually first to better understand layout.
In Google Sites you can add most HTML directly without a script. The UI Service and GUI Builder will generate HTML form tags for you, and since there's rarely any reason to insert GUI elements unless you are executing some code you probably want to start with using these.
Here is a Drop-Down list examplewith some changes to show how a handler function can be called from multiple UI elements (which they call Widgets sometimes) and how to use the parameter:
function doGet(e) { // use doGet() & UiApp to make a canvas.
var app = UiApp.createApplication();
var doEvent = app.createServerHandler('doEvent').setId('doEvent');
var myList = app.createListBox().setId('myList').setName('myList');
myList.addItem('one'); // add items, I use single quote strings.
myList.addItem('two').addItem('three') // I know it looks weird.
// Scripts let you do this, by returning self for your convenience.
.addChangeHandler(
app.createServerHandler('doEvent')
);
app.add(myList); // Add element to GUI.
doEvent.addCallbackElement(myList); // Add to Event Handler.
app.add(app.createButton('Click Me').setId('myButton')
.addClickHandler(doEvent));
return app;
} // Simple DropDown by Jason K.
function doEvent(e) { // use split() if isMultipleSelect is true
var app = UiApp.getActiveApplication();
app.add(app.createLabel(
'List Value is ' + e.parameter.myList
+ ' from ' + e.parameter.source));
return app;
}
As far as troubleshooting, remember to add each element with app.add() and return app; at the end of doGet and each handler function.
Handlers execute a function like JavaScript onClick() or onChange() functions, most UI are not useful without handlers. ClientHandler are more efficient but ServerHandler do more, start with ServerHandlers and any simple functions can be converted to ClientHandlers for better performance. You can choose to space out your handlers or cram it all into one line-of-code, really a matter of personal preference however do assign it to a variable if you plan to use it for more than one GUI object. You may want to look up the different layout managers to make more fancy looking applications, or just use the GUI Builder. Also there use to be other create functions like app.createServerClickHandler() but I understand those were useless and are now deprecated so ignore any other references you find like that, however we do still use addChangeHandler() and addClickHandler() to the GUI elements themselves.
The setName() seems to be silly, it is only needed to set the parameter name (I hope they change that) so for now I suggest just setting it the same as the element id. I also made the Handler's variable name = its id = the event function name just to illustrate how they are all related.
Related
Where do I make the initial function call to s_getLoadTime(). My library is being managed by Adobe.
https://marketing.adobe.com/resources/help/en_US/sc/implement/getLoadTime.html
Step 1: Add the plugin and timer start code
First, you need a Page Load Rule that is set to trigger at "Top of Page". If you already have an existing rule that triggers every page load at top of page, you can use that. If you do not, then create a new one.
Then, in the Javascript / Third Party Tags section, click on "Add New Script". Set the Type to "Sequential Javascript" and check the Execute Globally option.
In the code box, paste the following code:
// this is for older browser support
var inHeadTS=(new Date()).getTime();
// plugin
function s_getLoadTime(){if(!window.s_loadT){var b=new Date().getTime(),o=window.performance?performance.timing:0,a=o?o.requestStart:window.inHeadTS||0;s_loadT=a?Math.round((b-a)/100):''}return s_loadT}
// call plugin first time
s_getLoadTime();
Click on Save Code and then Save Rule.
Step 2: Make the 2nd call to plugin and assign to Adobe Analytics variables
Next, you need a Page Load Rule that is set to trigger at "Bottom of Page". If you already have an existing rule that triggers every page load at bottom of page, you can use that. If you do not, then create a new one.
Then, go to Conditions > Rule Conditions > Criteria and from the dropdown select Data > Custom and click "Add Criteria". In the code box, add the following:
_satellite.setVar('loadTime',s_getLoadTime());
return true;
Then within Adobe Analytics section of the rule, you can set your prop and/or eVar to %loadTime%.
Note: Using a rule set to trigger at "Onload" will technically be more accurate. However, DTM does not currently offer ability to trigger Adobe Analytics Onload (options are only for top or bottom of page), so if you set the rule to "Onload" it will trigger after AA has made a request so your variables will not be populated and sent in that request. If you really want to keep the accuracy then you will need to explore other options, such as implementing AA as a 3rd party script so that you have more control over when it triggers.
Click on Save Rule and then Approve/Publish once you have tested.
The question should really be, "Why should the getLoadTime() plugIn be used, ever?". Yasho, I started with the same question that you had and blindly implemented the plugIn in Adobe DTM following the instructions at https://marketing.adobe.com/resources/help/en_US/sc/implement/getLoadTime.html
Only after starting to analyze the data did I look into the plugIn to see what it does.
Below is the beautified code of the plugIn:
function s_getLoadTime() {
if (!window.s_loadT) {
var b = new Date().getTime(),
o = window.performance ? performance.timing : 0,
a = o ? o.requestStart : window.inHeadTS || 0;
s_loadT = a ? Math.round((b - a) / 100) : ''
}
return s_loadT
}
So, basically the function records s_loadT once and only once. The first call (way at the top of the page) sets the value and any subsequent call to the function will return that same value since it has been persisted in window.s_loadT
Scratch your head a bit and ask the obvious question, "So what does this measure anyway?" Best case, it measures the difference between window.performace.timing.requestStart and the timeStamp when the function was first called. Worst case it measures the difference between a timestamp set in the head of the document by javascript (and that difference could very well be a negative number). Or even worse if 'a' resolves to 0, you'll just get 'b' which will be a huge number.
If you are following the directions and calling getLoadTime() up high in the document (DTM page top rule), you're really just be measuring how long it takes to fire a page top rule. If you put the first call into the top of your s_code.js, you're just measuring how long it takes to load (and execute) s_code.js
I have multiple instances of Adobe Analytics in the same Adobe DTM web property. They all go to different report suites. I'd like to create a page load rule so that the data is only reported to one report suite for any given page. So far the page load rules that I have created are causing the AA data to report to all of the report suites. Does anyone have any idea to get them to only fire to one at a time?
Thanks,
Mike
It is possible to set DTM to suppress the call for an event based rule or direct call rule but currently it is not possible to do it with a page load rule within the DTM built-in interface.
Some things you can do:
1) Combine your Adobe Analytics instances into a single instance. Is there a particular reason you are using multiple instances of Adobe Analytics? I know you mentioned they are for separate report suites, but are they also for separate Adobe Analytics instances altogether? If not, is it because they are completely separate implementations with different variables and logic assigned for them? If the only thing different between them is report suite id, then you should combine them and write some logic to pop relevant report suite id(s) for s.account.
2) Make use of s.abort to suppress the calls. If your code version is H25.3+ or you are using AppMeasurement then you can set s.abort to true to make the next Adobe Analytics request (s.t or s.tl call) be cancelled. Note that this may only be feasible if your instances are all using separate namespaces.. if you are just outputting several instances of code all under the same namespace, you will have issues. Also, if you are doing that, then you may also have issues as far as variables carrying over to other instances. But in any case, basically within your page load rule you'd add a rule condition where criteria is Data:Custom and then you'd write js logic to determine which one(s) you don't want to pop and set [namespace].abort=true; for each of them. Then return true at the end to make sure the condition is always true.
Or, you can set s.abort=true; within the Custom Page Code section for each Adobe Analytics instance you want to suppress in the page load rule. There are various other methods for popping s.abort but hopefully you get the picture. Which one is best just depends on how all your stuff is actually setup.
3) Pop the Adobe Analytics tags as a regular tag instead of a Tool. Remove them as a tool and put them as a Javascript / Third Pary Tag within the page load rule. This includes the core lib code and anything else you may have in the Tool config section. This also means outputting the "trigger" (s.t call). Make a separate one for each one and then you can make conditions for them to pop.
To add to Crayon's answer, you can also choose a custom code implementation in the Library Management section of the tool configuration settings. You will have to paste in the s_code contents and check the box that says "Set report suites using custom code below"
Then, you can use whatever logic you want to set a variable in the code that directs data to the report suites.
if(document.location.href == "http://www.mypage1.com"){
s_account = "rsid_1";
}else{...}
To add to Brett's answer - with rare exception, I let Adobe manage the analytics file. However, you can use the customize page code section within the Adobe Analytics tool configuration to deploy plugins or set the report suite ID dynamically. Here's an example I commonly use:
var suiteid;
var enviro;
var getURL = window.location.href
// Set RSID based on URL
if (getURL.indexOf('myURL.com') != -1)
{
suiteid = 'rsidproduction';
s.linkInternalFilters = 'javascript:,mailto:,tel:,' + window.location.host;
enviro = 'prod';
}
else
{
suiteid = 'rsidstaging';
s.linkInternalFilters = 'javascript:,mailto:,tel:,' + window.location.host;
enviro = 'dev';
}
s.account = suiteid;
This is an easy way to dynamically change the RSID and keep the analytics file managed by Adobe. I also blogged about this here: Managing your RISD Dynamically
I'm trying to set the Visitor ID in Adobe Analytics through DTM.
Above the s_code I have:
var visitor = new Visitor("xxxx")
visitor.trackingServer = "xxx.xx.xx.omtrdc.net"
I've created a data element where the legacy code used to call the
Visitor.getInstance("xxxx");
and set the Visitor ID to %Visitor ID%
That's not working however, and my visitor ID is always just set to %Visitor ID% and obviously not reading any values. I'd really appreciate any input that someone can give me.
Thanks,
Mike
The Visitor ID pops s.visitorID and is in general related to visitor id, but is not the same as s.visitor which is what gets popped for the VisitorAPI integration. DTM does not currently have a built-in field for the s.visitor variable, so you will have to set it yourself within the config, either in the Library Management code editor (assuming you are opting to c/p the core lib and not the "Managed by Adobe" option) or else in the Custom Page Code section.
Since you are popping it in a data layer first, you can reference the data layer like this:
s.visitor = _satellite.getVar('Visitor ID');
NOTE: A separate potential issue you may have is with whether or not the Visitor object is available for your data element. Since data elements are the first thing to be evaluated by DTM, you will need to ensure that the VisitorAPI.js library is output before your top page DTM script include.
If this is a problem for you, or if you are wanting to host VisitorAPI.js within DTM, then you may need to adjust where you are popping that stuff. For example, place the VisitorAPI core code above the custom code as the first stuff within the data element, before:
var visitor = new Visitor("xxxx") visitor.trackingServer = "xxx.xx.xx.omtrdc.net
Or, don't use the data element at all. Instead, put the VisitorAPI code within the Adobe Analytics custom code or core lib section and pop all that stuff (aboove the s.visitor assignment). Or a number of other methods; point is, VisitorAPI stuff must be loaded before the data element can make use of it, same as it must be loaded before Adobe Analytics can make use of it.
So DTM is changing pretty fast and furious right now. They have a "Marketing Cloud Service ID" that works well. Before I used that, however, I did find a way to fix the code. Crayon Violent was right, as usual, that the problem was that the script wasn't available yet. I fixed this by putting the following code in between the VisitorAPI.js and the AppMeasurement stuff in the DTM managed library.
var aA = new AppMeasurement();
aA.visitorNamespace="companyname";
aA.visitor = Visitor.getInstance("companyname");
In addition, there were also some issues using my localhost for testing while trying to see if I had this correct or not. If you are having issues and think you have it correct, it may be worthwhile to elevate it to a different environment.
I know there are many tutorials but they concentrate on xul, and manipulating menus and examples are overcrowded with features.
What I need is a simple extension that will for example add a red border to all <body> elements of every page I'm visiting and js would show me alert when a page is finished loading. Just to show that it is working and I will have a point to start learning from.
I know that there are ready extensions like greasemonkey and user css but what I intend to do is to first make such functionality raw, without overhead of yet another extension. And second to have ha proof of concept code so I can learn other features of firefox api.
I know how to write chrome/opera extension. I know all the languages needed, and how to make a mock extension, so it show up in firefox addons list. Vut the problem is that I don't know what to put where to get to the content of actual web page.
I know that there is a file called main.js that I'm supposed to put somewhere with code like this:
var data = require("self").data;
var pageMod = require("page-mod");
pageMod.PageMod({
include: "*",
contentScriptFile: data.url("my_script.js"),
contentStyleFile: data.url("my_style.css")
});
And that begin to look familiar, like in Chrome., my script code:
window.addEventListener("load", function() {
alert("hello there!");
}, true);
But I don't know where to put these files. Are there some default location, or must I set some configuration file to let know the api where main.js is ?
I know that there are projects to make such css/js based extension simpler, like jetpack - but that still creates overhead. I want to learn, but also don't waste my time and create something useful while doing that based on the knowlegde I have from chrome API.
edit:
I found this tutorial: https://developer.mozilla.org/en-US/Add-ons/SDK/Guides/Content_Scripts/Accessing_the_DOM - but there is nothing on where to put these files there is no example extension using these features.
edit2: https://github.com/mozilla/addon-sdk/tree/master/examples - there is no link for these in mozdev examples, one must search this thru google
Are you still in need of a ready made example?
Here is a bootstrap addon template that does exactly this. You just need to edit the addDiv and removeDiv functions for starters.
https://gist.github.com/Noitidart/9287185
It's called the Add-on SDK. Start here
When creating tests for .Net applications, I can use the White library to find all elements of a given type. I can then write these elements to an Xml file, so they can be referenced and used for GUI tests. This is much faster than manually recording each individual element's info, so I would like to do the same for web applications using Selenium. I haven't been able to find any info on this yet.
I would like to be able to search for every element of a given type and save its information (location/XPath, value, and label) so I can write it to a text file later.
Here is the ideal workflow I'm trying to get to:
navigate_to_page(http://loginscreen.com)
log_in
open_account
button_elements = grab_elements_of_type(button) # this will return an array of XPaths and Names/IDs/whatever - some way of identifying each grabbed element
That code can run once, and I can then re-run it should any elements get changed, added, or removed.
I can then have another custom function iterate through the array, saving the info in a format I can use later easily; in this case, a Ruby class containing a list of constants:
LOGIN_BUTTON = "//div[1]/loginbutton"
EXIT_BUTTON = "//div[2]/exitbutton"
I can then write tests that look like this:
log_in # this will use the info that was automatically grabbed beforehand
current_screen.should == "Profile page"
Right now, every time I want to interact with a new element, I have to manually go to the page, select it, open it with XPather, and copy the XPath to whatever file I want my code to look at. This takes up a lot of time that could otherwise be spent writing code.
Ultimately what you're looking for is extracting the information you've recorded in your test into a reusable component.
Record your tests in Firefox using the Selenium IDE plugin.
Export your recorded test into a .cs file (assuming .NET as you mentioned White, but Ruby export options are also available)
Extract the XPath / CSS Ids and encapsulate them into a reusable classes and use the PageObject pattern to represent each page.
Using the above technique, you only need to update your PageObject with updated locators instead of re-recording your tests.
Update:
You want to automate the record portion? Sounds awkward. Maybe you want to extract all the hyperlinks off a particular page and perform the same action on them?
You should use Selenium's object model to script against the DOM.
[Test]
public void GetAllHyperLinks()
{
IWebDriver driver = new FireFoxDriver();
driver.Navigate().GoToUrl("http://youwebsite");
ReadOnlyCollection<IWebElement> query
= driver.FindElements( By.XPath("//yourxpath") );
// iterate through collection and access whatever you want
// save it to a file, update a database, etc...
}
Update 2:
Ok, so I understand your concerns now. You're looking to get the locators out of a web page for future reference. The challenge is in constructing the locator!
There are going to be some challenges with constructing your locators, especially if there are more than one instance, but you should be able to get far enough using CSS based locators which Selenium supports.
For example, you could find all hyperlinks using an xpath "//a", and then use Selenium to construct a CSS locator. You may have to customize the locator to suit your needs, but an example locator might be using the css class and text value of the hyperlink.
//a[contains(#class,'adminLink')][.='Edit']
// selenium 2.0 syntax
[Test]
public void GetAllHyperLinks()
{
IWebDriver driver = new FireFoxDriver();
driver.Navigate().GoToUrl("http://youwebsite");
ReadOnlyCollection<IWebElement> query
= driver.FindElements( By.XPath("//a") );
foreach(IWebElement hyperLink in query)
{
string locatorFormat = "//a[contains(#class,'{0}')][.='{1}']";
string locator = String.Format(locatorFormat,
hyperlink.GetAttribute("class"),
hyperlink.Value);
// spit out the locator for reference.
}
}
You're still going to need to associate the Locator to your code file, but this should at least get you started by extracting the locators for future use.
Here's an example of crawling links using Selenium 1.0 http://devio.wordpress.com/2008/10/24/crawling-all-links-with-selenium-and-nunit/
Selenium runs on browser side, even if you can grab all the elements, there is no way to save it in a file. As I know , Selenium is not design for that kinds of work.
You need to get the entire source of the page? if so, try the GetHtmlSource method
http://release.seleniumhq.org/selenium-remote-control/0.9.0/doc/dotnet/html/Selenium.DefaultSelenium.GetHtmlSource.html