In YUI determine if an element exists that has a specific value - yui

I'm fairly familiar with jQuery, but I'm working on a project in YUI, which I am totally new to, and am not sure how to accomplish this.
In essence, I need to display a js popup if a span element exists that has the text "Inactive" in it and is several steps down the tree from a div with a class of "list_subpanel_cases".
This is a rough example, but the point is, this is dynamically built, so my only definite selectors are the div with the class and the descendant span with a text value of "Inactive".
<div class="list_subpanel_cases">
<table>
<tbody>
<tr>
<td>
<span>Active</span>
</td>
</tr>
<tr>
<td>
<span>Inactive</span>
And I need to find out if any spans exist with the text "Inactive".
Hope this isn't too confusing!

It appears that CSS3 selectors can't examine content (only attributes) so you'd have to use a selector for the candidate span tags and then use code to look at the content for a match. Here's one way to do that:
function findInactive() {
var found = null;
Y.all(".list_subpanel_cases span").some(function(node, index, nodeList) {
if (node.getContent() == "Inactive") {
found = node;
return(true); // stop looking for more matches
}
return(false); // keep looking for more matches
});
return(found);
}
if (findInactive()) {
// execute code here when the Inactive span exists
}
You can see it work here: http://jsfiddle.net/jfriend00/BVzqL/.

Related

Function call inside ngStyle gets sanitized

I have a problem with style sanitization with Angular 8.
I've used ngStyle multiple times, but this time i cannot set the border of a td element.
I am trying to set the border style based on a field. If this field has a relevant content for me then i hilghlight it, otherwise i don't. I don't know the number of possible values of the field, neither the exact values: it's complitely dynamic, I only know my values of interest.
I'm returning the border style from a function inside the .ts file. Here are the code snippets:
<ng-container matColumnDef="{{cam}}">
<th mat-header-cell *matHeaderCellDef class="header"> {{cam}} </th>
<td mat-cell *matCellDef="let piano" class="cellaMagazzino" [ngStyle]=" {'border':shouldHighlight(piano[cam])}">
<div>
<!--content-->
</div>
</td>
</ng-container>
My typescript function looks like this:
shouldHighlight(element){
if (this.listaCommittenti == undefined && this.listaNumOrdine == undefined) {
let found = this.releventContentList.find(item => item.property == element.property)
let result = found != undefined ? '3px solid ' + this.myVariable["color"] : ""
return result
}
I used ngStyle calling functions other times, but in this case i get the error:
WARNING: sanitizing unsafe style value 3px solid rgb(241, 196, 15) (see http://g.co/ng/security#xss).
Is there some kind of configuration to do? is there a workaround?
Does this work for you?
Typescript:
getHighlightColor():string {
return "rgba(255,255,255,1)";
}
shouldHighlight(): boolean {
return true;
}
HTML:
<td mat-cell [style.border-color]="getHighlightColor(piano[cam])" [ngClass]="{ 'highlighted': shouldHighlight(piano[cam])}"
CSS:
.highlighted{
border-width:3px;
border-style:solid;
border-color:transparent;
}
In general, I would strongly advice against using function calls in your template as it's a real performance killer. It's much better to calculate the desired classes and add them to your data instead.
Federico's approach is a nice work around, however you could also use your orignal approach and bypass the style security via bypassSecurityTrustStyle(yourStyleString) see Trusting safe values

Scrape and iterate over html table without classes

I'm building a webscraper with nodejs and pupeteer.
Everthing works fine, but now im stuck on how to get structured data from a table without classes. Here's an example:
I don't know how to iterate thru the table and extract the data in json format which should like this:
<table class="tableclass">
<tbody>
<tr>
<td>
<b>
<strong>
<span>A</span></strong> & B <strong><span>C</span></strong>Name</b>
</td>
<td >
Street No<br>
Zip City
</td>
<td >
Map | Website
</td>
</tr>
<tr>
<td>
<b>
<strong>
<span>A</span></strong> & B <strong><span>C</span></strong>Name</b>
</td>
<td >
Street No<br>
Zip City
</td>
<td >
Map | Website
</td>
</tr>
</table>
Obj ={
"content":[
{
"name":"A&B C Name",
"adress":[
"Street No",
"Zip",
"City"
],
"link":"http://www.websiteB.de"
},
]
}
Does the table have a consistent structure in each case? If so, you just need to figure out how to get to each element from the root of of table. For instance, to get the name, assuming that the above table structure is the same for all tables:
const table = document.querySelector('.tableclass')
Obj ={
"content":[
{
"name": table.querySelectorAll('tr')[0].querySelectorAll('td')[0].innerText;
....
]
}
Here, I get the table element I am interested in using document.querySelector('.tableclass') - which will return the first instance of .tableclass on the page. If you have multiple, you will have to use document.querySelectorAll and perform these operations on each table in a for-loop.
Then, I use the querySelector but limited to this table, and I grab the first element, because that's where the name is. (table.querySelectorAll('tr')[0]). Here I could have just used (table.querySelector('tr')) as I wanted the first element, but this is just to show you how you can access any of the s by their index. Finally, following the same logic, I need to select the first element as that is the element that contains all the 'name' text, then I just use its .innerText attribute to extract the text.
innerText will be your friend here - just traverse the DOM nodes using node.querySelector until you get to one that contains all the text you want and no more, then get the .innerText attribute on that node. If the table has consistent structure, you should just be able to figure this out for one table and it should work on all of them.
let data = await page.evaluate(() => {
var i = 0;
for (var i = 0; i < 5; i++) {
const table = document.querySelector('#tableclass');
let dealer = table.querySelectorAll('tr')[i].querySelectorAll('td')[0].innerText;
let adress = table.querySelectorAll('tr')[i].querySelectorAll('td')[1].innerText;
let link = table.querySelectorAll('tr')[i].querySelectorAll('td')[2].querySelectorAll('a')[1].getAttribute("href");
return {
dealer,
adress,
link
}
}
I want to loop thru the table/ each row in it. I know this is wrong, but I don't know how to loop in this case. Thanks for help!

ng-bind-html not recognizing ID names

I'm using ng-bind-html and it pulls in the HTML with class names, but the id names are all missing. What is causing this?
actual code example:
service partial example
var assets = {
'sampleInvoice': '<div id="invoice-div"><table id="invoice-table-id" cellspacing="0" cellpadding="0" border="0"><tbody>......
}
controller portion:
$scope.invoiceDetails = function(params) {
console.log("Here I am ");
var modalInstance = $uibModal.open({
templateUrl: 'invoice-details-modal',
controller: 'invoiceDetailsCtrl',
windowClass: 'invoice-details-modal',
resolve: {
invoice: function resolveInvoiceTemplate($q) {
return $q.resolve($templateCache.get("sampleInvoice"));
}
}
});
HTML Part
<div ng-bind-html="invoice"></div>
What it's producing:
<div><table cellspacing="0" cellpadding="0" border="0"><tbody><tr valign="top"><td><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td class="invoice-logo-td"><div class="invoice-logo">....
Notice the class names are there, but the ids are gone. Now, I can switch all the ids to classes as a work around, but it seems like it should be able to recognize id names as well.
Does anyone know why this is happening? (Yes, I injected ngSanitize)
Thanks in advance!
Stripping id's from elements in an intentional sanitation. You can see the original commit that caused this back in v1.0.0-rc2.
The reasoning isn't given in the commit, but a later issue filed against angularjs about striping id's from img tags explains this:
the reason why we strip out id and name is that browsers put them on window
<div id="angular"> would overwrite the window.angular with an element. This is considered a security issue and so we don't allow it.
— mhevery

Conditionally render depending on presence of a faces message

I have a special row in my table for errors:
<tr>
<td colspan="2"><p:message for="questionId" id="msgQuestion" /></td>
</tr>
How can I set this so the row is only displayed when there is an error?
In first place i will recommend not to use table to display layout elements
after that the ellement will apear even if the message is not present, if you are obliged to use it you can use som think like this in JS:
<script type="text/javascript">
window.onload = function() {
hideTdMessage();
};
hideTdMessage(){
var message = document.getElementById(msgQuestion);
if(message){
//the msg is present
}else{
//the msg is not present
}}
</script>
Or You can use your MBean to change the CSS class it's better than using JS.
But i will say that the best solution is not tu use the tabel.
Hope it helped
Use a JSF component and the property rendered
rendered="#{not empty facesContext.messageList}"

Filtering a page with infinite scroll in AngularJS

I implemented an infinite scrolling feature on my AngularJS + Node.js app.
It is based on this JSfiddle and works the same way: http://jsfiddle.net/vojtajina/U7Bz9/
HTML:
<div id="fixed" when-scrolled="loadMore()">
<ul>
<li ng-repeat="i in items">{{i.id}}</li>
</ul>
</div>​
Javascript:
function Main($scope) {
$scope.items = [];
var counter = 0;
$scope.loadMore = function() {
for (var i = 0; i < 5; i++) {
$scope.items.push({id: counter});
counter += 10;
}
};
$scope.loadMore();
}
angular.module('scroll', []).directive('whenScrolled', function() {
return function(scope, elm, attr) {
var raw = elm[0];
elm.bind('scroll', function() {
if (raw.scrollTop + raw.offsetHeight >= raw.scrollHeight) {
scope.$apply(attr.whenScrolled);
}
});
};
});
​
My reasons for implementing the infinite scroll is in order to save my users bandwidth by not loading all 1000 results and their corresponding images unless the user wants to see all of it.
However when searching within the results using an AngularJS filter I am encountering problems, because of course not all the results are there (unless the user has scrolled to the very bottom) so the search will only return a fraction of the required results.
I then removed the infinite scrolling feature in order to have the search function work properly but this provided new issues on chrome (not on Firefox though) when I open the page the browser starts loading images from the top. If I then filter the results by searching for something starting with "z" (at the very bottom of the results) Firefox switches focus and loads the results starting with "z" first (as they are then the only ones being displayed). However chrome continues loading through the list and thus the user will only see the results of their search (for "z") once all the images in the app have been loaded.
I am looking for a way to have angular provide both the infinite scroll and a proper search filter on the results at the same time. If this is not possible then a way to make chrome load the visible images first.
I am currently trying some weird stuff with a bunch of different arrays in the scope but I haven't had any luck so far.
Since several people here had a similar issue and I was struggling myself, I took the time to create a fiddle that works (for my case).
https://jsfiddle.net/lisapfisterer/Lu4sbxps/
The main idea is to dynamically extend the limitTo value using infinite-scroll's function call
<div infinite-scroll="loadMore()" infinite-scroll-distance="20">
<tr data-ng-repeat="logEvent in logEventFilter = (logEvents | filter:searchTerm | limitTo:numberToDisplay) track by $index">
<td> {{$index}} </td>
<td> {{logEvent.name}} </td>
<td> {{numberToDisplay}} </td>
</tr>
</div>
loadMore just increases the limit
$scope.loadMore = function() {
if ($scope.numberToDisplay + 5 < $scope.logEvents.length) {
$scope.numberToDisplay += 5;
} else {
$scope.numberToDisplay = $scope.logEvents.length;
}
};
What you want to do isn't "impossible" but it's certainly going to be a little complicated.
Have your server do all of the "filtering" to ensure that the paginated values returned are the proper values for the filter(s).
When the server returns the results, render all of the HTML to the screen except the src attributes of image tags. This way none of the images will begin loading yet.
Scroll to the proper "page".
Make sure all of the heights prior to the images being loaded are the same, now do some JS magic to figure out which ones are visible.
Set the src attribute of the visible images only, Subscribe to their "load" events and create a $q promise that is complete once all loads are complete.
after that promise completes, set the rest of the image src attributes so the remainder of the images will load.

Resources