Getting webpage elements by class using Keyboard Maestro - keyboard-maestro

I frequently go to a library results page that has two pieces of information I want:
The Listing Title: An <h1> with class="title"
The Call Number: A <td> with class="call"
I want to be able to automatically copy the content of these two elements to a couple of named clipboards. Is this possible?

Awesome person, ComplexPoint, answered this on the KM forums here
(function (strPath) {
var r = document.evaluate(strPath, document, null, 0, null),
lst = [],
oNode;
while (oNode = r.iterateNext()) {
lst.push(oNode.className + ' = ' +oNode.textContent);
}
return lst.join('\n');
})("//h1[#class='title'] | //td[#class='call']")

Related

How to display the value (sum) rather than count of markers in a dc.leaflet.js

I want to use crossfilter's reduceSum function dc.leaflet.js, and display the sum instead of the number of clustered markers.
The first example for dc.leaflet.js uses reduceCount. Additionally it doesn't use the reduced value; it just displays the number of markers in the cluster.
I want to use the sum of data using reduceSum.
Here is my data as tsv:
type geo say
wind 38.45330,28.55529 10
wind 38.45330,28.55529 10
solar 39.45330,28.55529 10
Here is my code:
<script type="text/javascript" src="../js/d3.js"></script>
<script type="text/javascript" src="../js/crossfilter.js"></script>
<script type="text/javascript" src="../js/dc.js"></script>
<script type="text/javascript" src="../js/leaflet.js"></script>
<script type="text/javascript" src="../js/leaflet.markercluster.js"></script>
<script type="text/javascript" src="../js/dc.leaflet.js"></script>
<script type="text/javascript">
/* Markers */
d3.csv("demo1.csv", function(data) {
drawMarkerSelect(data);
});
function drawMarkerSelect(data) {
var xf = crossfilter(data);
var facilities = xf.dimension(function(d) { return d.geo; });
var facilitiesGroup = facilities.group().reduceSum(function(d){return d.say});
dc.leafletMarkerChart("#demo1 .map")
.dimension(facilities)
.group(facilitiesGroup)
.width(1100)
.height(600)
.center([39,36])
.zoom(6)
.cluster(true);
var types = xf.dimension(function(d) { return d.type; });
var typesGroup = types.group().reduceSum(function(d){return d.say});
dc.pieChart("#demo1 .pie")
.dimension(types)
.group(typesGroup)
.width(200)
.height(200)
.renderLabel(true)
.renderTitle(true)
.ordering(function (p) {
return -p.value;
});
dc.renderAll();
}
</script>
I have rewritten the question because it was very unclear. I agree with #Kees that the intention was probably to display the sum in a clustered marker chart, rather than "reduceSum doesn't work".
#Kees also pointed out a Leaflet.markercluster issue which gives basic information about how to display a sum inside a marker cluster.
The question becomes, how to apply these customizations to dc.leaflet.js?
First, I've created a version of the example data with another column rnd:
type geo rnd
wind 43.45330,28.55529 1.97191
wind 43.44930,28.54611 3.9155
wind 43.45740,28.54814 3.9922
...
We can use reduceSum like this:
var facilitiesGroup = facilities.group().reduceSum(d => +d.rnd);
And annotate each marker with its value by overriding .marker(), wrapping the default callback:
const old_marker_function = marker.marker();
marker.marker(function(d, map) {
const m = old_marker_function(d, map);
m.value = d.value;
return m;
});
And we can specify a different rendering of the icon using .clusterOptions():
marker.clusterOptions({
iconCreateFunction: function(cluster) {
var children = cluster.getAllChildMarkers();
var sum = 0;
for (var i = 0; i < children.length; i++) {
sum += children[i].value;
}
sum = sum.toFixed(0);
var c = ' marker-cluster-';
if (sum < 10) {
c += 'small';
} else if (sum < 100) {
c += 'medium';
} else {
c += 'large';
}
return new L.DivIcon({ html: '<div><span>' + sum + '</span></div>', className: 'marker-cluster' + c, iconSize: new L.Point(40, 40) });
}
});
The example given in the above issue was missing any styling, so I copied the implementation of _defaultIconCreateFunction from the Leaflet.markercluster sources, and modified it.
Demo fiddle
As expected, the numbers are close to 2.5 times the original numbers (since the new column is a random number from 0 to 5).
Putting numbers on the individual markers
marker.icon() allows you change the icon for individual markers, so you can use DivIcon with similar styling to display the numbers:
marker.icon(function(d, map) {
return new L.DivIcon({
html: '<div><span>' + d.value.toFixed(0) + '</span></div>',
className: 'marker-cluster-indiv marker-cluster',
iconSize: new L.Point(40, 40) });
});
This introduces a new class .marker-cluster-indiv to distinguish it from the others; in the new fiddle I've colored them blue with
.marker-cluster-indiv {
background-color: #9ecae1;
}
.marker-cluster-indiv div {
background-color: #6baed6;
}
The interaction is perhaps less clear since clicking blue dots brings up a popup instead of expanding. Perhaps a different icon should be used.
The reduceSum part should work fine, since that is just a different crossfilter function.
Are you sure that your data is getting read correctly? You state that it is a tsv file, and show code that looks like it is tab-separated, but then you use d3.csv to load it, which would have pretty bad effects considering there is a comma in the middle of the second field.
Please try console.log(data) after your data is loaded, and verify that it is loading correctly.
Also, you do not state what problem you encounter. "It doesn't work" does not help us help you.

How to handle table data in Protractor

In Protractor, how does one handle repeated content, from say a table? For example, given the following code, that kicks out a table with 3 columns: Index, Name and Delete-Button in each row:
<table class="table table-striped">
<tr ng-repeat="row in rows | filter : search" ng-class="{'muted':isTemp($index)}">
<td>{{$index+1}}</td>
<td>{{row}}</td>
<td>
<button class="btn btn-danger btn-mini" ng-click="deleteRow(row)" ng-hide="isTemp($index)"><i class="icon-trash icon-white"></i></button>
</td>
</tr>
</table>
And in my test I need to click the delete button based on a given name. What's the best way to find this in Protractor?
I know I could grab the rows.colum({{row}}) text, get the index of that, and then click on the button[index], but I'm hoping for a more elegant solution.
For example, in Geb, you could pass a row locator to a module, that would then dice up each row with column indicators. And that solution has me eyeing Protractors map method...
You can use map or filter. The api would look like this:
var name = 'some name';
// This is like element.all(by.css(''))
return $$('.table.table-stripe tr').filter(function(row) {
// Get the second column's text.
return row.$$('td').get(2).getText().then(function(rowName) {
// Filter rows matching the name you are looking for.
return rowName === name;
});
}).then(function(rows) {
// This is an array. Find the button in the row and click on it.
rows[0].$('button').click();
});
http://angular.github.io/protractor/#/api?view=ElementArrayFinder.prototype.filter
Here is how I am doing something similar in my application using Protractor against a Kendo grid:
I have a page object that has the following functions:
// Query all table rows (tr) inside the kendo grid content container
this.getGrid = function () {
return element.all(by.css('.k-grid-content tr'));
};
// Use the given rows element finder to query for the delete button within the context of the row
this.getDeleteButtonInRow = function (row) {
return row.element(by.css(".btn.delete"));
};
Then I use these functions in my test like so:
// Verify that a delete button appears in every row of the grid
var grid = pageObj.getGrid();
grid.each(function (row) {
var deleteButton = downloadsPage.getDeleteButtonInRow(row);
expect(deleteButton.isDisplayed()).toBe(true);
});
Here's my solution, based on #Andres solution, that I used in my page object:
this.deleteFriend = function(nameString) {
return this.rows.filter(function(row) {
// find the row with the name we want...
return row.$$('td').get(1).getText().then(function(name) {
return name === nameString;
});
}).then(function(filteredRows) {
filteredRows[0].$('i.icon-trash').click();
});
};

Can anybody help me to resolve ng-grid filtering in a multi row Grid

Here is the plunker: http://plnkr.co/edit/fGVVOOIwvf4GrEj3XtJ6?p=preview
I have created a multi row grid and I would like to filter the grid data for each column header.
If I put an input box outside the grid it is working fine. If I put an input box inside the column header filtering is not working
Please see the code and help me for this.
Use this filterBar plugin. (I cannot take credit for this, I do not remember where I found it.)
Plugin
var filterBarPlugin = {
init: function(scope, grid) {
filterBarPlugin.scope = scope;
filterBarPlugin.grid = grid;
$scope.$watch(function() {
var searchQuery = "";
angular.forEach(filterBarPlugin.scope.columns, function(col) {
if (col.visible && col.filterText) {
var filterText = (col.filterText.indexOf('*') == 0 ? col.filterText.replace('*', '') : "^" + col.filterText) + ";";
searchQuery += col.displayName + ": " + filterText;
}
});
return searchQuery;
}, function(searchQuery) {
filterBarPlugin.scope.$parent.filterText = searchQuery;
filterBarPlugin.grid.searchProvider.evalFilter();
});
},
scope: undefined,
grid: undefined,
};
Change your header cell input ng-model to: col.filterText
<input type="text" placeholder="MY NAME" ng-model="col.filterText" ng-change="activateFilter()"/>
Add plugin to gridOptions
...
plugins: [filterBarPlugin],
...
Updated Plunker: Plunker
I know this is old, but in case someone else ends up here...
Here is a google group thread discussing this: https://groups.google.com/forum/#!topic/angular/lhu5Fbs97G4
and within that discussion you can find the following plnkr which does what you are wanting (and which I think the above answer references):
http://plnkr.co/edit/c8mHmAXattallFRzXSaG?p=preview

Class prefix as selector for each function

I am able to do this using an ID prefix as the selector, but I need to be able to do it with classes instead. It's an each function for opening up different modal windows on the same page. I need to avoid using ID names because I have some modal windows that will have multiple links on the same page, and when using IDs, only the first link will work.
So here's the function as it works with IDs:
$('div[id^=ssfamodal-help-]').each(function() {
var sfx = this.id,
mdl = $(this),
lnk = $('.link-' + sfx),
cls = $('.ssfamodal-close'),
con = $('.ssfamodal-content');
lnk.click(function(){
mdl.show();
});
cls.click(function(){
mdl.hide();
});
mdl.click(function() {
mdl.hide();
});
con.click(function() {
return false;
});
});
and I'm trying to change it to classes instead, like:
$('div[class^=ssfamodal-help-]').each(function() {
var sfx = this.attr('class'),
etc.
But I cannot get it to work without using IDs. Is it possible?
EDIT Fixed error with semi-colon at end of Vars, and updated Fiddle with the fix. Still not working though.
Here's a Fiddle
** UPDATE **
To be clearer, I need to be able to refer to the same modal more than once on the same page. E.g.:
MODAL 1
MODAL 2
MODAL 3
MODAL 4
LINK TO MODAL 1
LINK TO MODAL 2
LINK TO MODAL 3
LINK TO MODAL 4
OTHER STUFF
LINK TO MODAL 1
LINK TO MODAL 4
LINK TO MODAL 3
OTHER STUFF
LINK TO MODAL 2
ETC.
When using classes get rid of the ID habit :
className1, className2, className3 ... etc
simply use
className
HTML:
<div class="ssfamodal-help-base ssfamodal-backdrop">
<div id="help-content" class="ssfamodal-content">
<span class="ssfamodal-close">[x]</span>
Howdy
</div>
</div>
<div class="ssfamodal-help-base ssfamodal-backdrop">
<div id="help-content" class="ssfamodal-content">
<span class="ssfamodal-close">[x]</span>
Howdy Ho
</div>
</div>
<span class="link-ssfamodal-help-base">One</span>
<span class="link-ssfamodal-help-base">Two</span>
LIVE DEMO
var $btn = $('.link-ssfamodal-help-base'),
$mod = $('.ssfamodal-help-base'),
$X = $('.ssfamodal-close');
$btn.click(function(i) {
var i = $('[class^="link-"]').index(this); // all .link-** but get the index of this!
// Why that?! cause if you only do:
// var i = $('.link-ssfamodal-help-base').index();
// you'll get // 2
// cause that element, inside a parent is the 3rd element
// but retargeting it's index using $('className').index(this);
// you'll get the correct index for that class name!
$('.ssfamodal-help-base').eq(i).show() // Show the referenced element by .eq()
.siblings('.ssfamodal-help-base').hide(); // hide all other elements (with same class)
});
$X.click(function(){
$(this).closest('.ssfamodal-help-base').hide();
});
From the DOCS:
http://api.jquery.com/eq/
http://api.jquery.com/index/
http://api.jquery.com/closest/
Here I created a quite basic example on how you can create a jQuery plugin of your own to handle modals: http://jsbin.com/ulUPIje/1/edit
feel free to use and abuse.
The problem is that class attributes can consist of many classes, rather than IDs which only have one value. One solution, which isn't exactly clean, but seems to work is the following.
$('div').filter(function () {
var classes = $(this).attr('class').split(/\s+/);
for (var i = 0; i < classes.length; i++)
if (classes[i].indexOf('ssfamodal-help-') == 0)
return true;
return false;
}).each(function() {
// code
});
jsFiddle
Or, equivalently
$('div').filter(function () {
return $(this).attr('class').split(/\s+/).some(function (e) {
return e.indexOf('ssfamodal-help-') == 0;
});
}).each(function() {
// code
});
jsFiddle
If there is one-to-one relationship between the modal helps and the modal links which it appears there is...can simplfy needing to match class values by using indexing.
For this reason you don't need unique class names, rather they just overcomplicate things. Following assumes classes stay unique however
var $helps=$('div[id^=ssfamodal-help-]');
var $help_links=$('div[id^=link-ssfamodal-help-]');
$help_links.click(function(){
var linkIndex= $help_links.index(this);
$helps.hide().eq( linkIndex ).show();
});
/* not sure if this is what's wanted, but appeared original code had it*/
$helps.click(function(){
$(this).hide()
})
/* close buttons using traverse*/
$('.ssfamodal-close').click(function(){
$(this).closest('div[id^=ssfamodal-help-]' ).hide();
});
Also believe that this code is a little more readable than original apporach
DEMO
Can you try this,
$('div[class^=ssfamodal-help-]').each(function() {
var sfx = $(this).attr('class');
console.log(sfx);
/*console log:
ssfamodal-help-base ssfamodal-backdrop
ssfamodal-help-base2 ssfamodal-backdrop
*/
});
Demo: http://jsfiddle.net/xAssR/51/
why don't you write like
$('div.classname').each(function() {
// you can write your desired code here
var sfx = this.attr('class');
var aa= this.attr('id');
});
or
$('.classname').each(function() {
// you can write your desired code here
var sfx = this.attr('class');
var aa= this.attr('id');
});
where classname is the name of the class used for the div in html
Thanks.

jQuery show div if value > x

I've been reading lots of topics about jQuery and showing div's, but I haven't found the answer to my specific question yet. Here's the thing:
Based on my value I want to show either div A or div B. The select field is filled with 20 countries, of which 19 get the same div (B) and only one get's another div (A). The one that get's div A has "value=1", so I figured to apply a "if select value > 1, show div B" principle. However, I can't manage to get it working. My other select-show-div mechanism was based on the exact value (I've posted it below), but this if-else thing makes me going crazy.
Any help would be appreciated!
My old value=exact code:
$('.div').hide();
$('#country').change(function() {
$('.div').hide();
$('#country' + $(this).val()).show();
});
});
And the corresponding HTML:
<div id="country1" class="div">
BLABLA
</div>
<div id="country2" class="div">
BLABLA
</div>
etc
I don't understand if you have a select menu, or divs. A possible solution could be the following:
$('select').change(function() {
var countryVal = $("select option:selected").val(); //get the value of the selected
$("#country1, #country2").hide(); //hide country divs, of previous selection
if(countryVal == 1) {$("#country1").show();} else {$("#country2").show()}; //if countryVal is 1 (the diffrent value) show the div #country1 else show the div #country2
});
updated Demo: http://jsfiddle.net/YnYxD/1
If I understood correctly, all the others countries have a value > 1, so you can't simply use the value to generate the id. The id must be 1 if the value is 1 and 2 otherwise.
Try :
$('#country').change(function() {
$('.div').hide();
var id = $(this).val() == 1 ? 1 : 2;
$('#country' + id).show();
});
});