'data:post-snippet' truncation in blogger - html

Let's say I wrote a post like this on Blogger:
abc def ghi <div class="pls-exclude-from-snippet">jkl mno pqr stu vwxyz</div>
Instead of listing from a to z, I want Blogger to set its data:post.snippet to 'abc def ghi' only (letting Blogger know to stop if it reads the token: a div with class 'pls-exclude-from-snippet'). How do I do that?

I found help here https://productforums.google.com/forum/#!topic/blogger/X9LxrjXnb2s
Still have to tweak it a little, but it works. Think gonna post it to help people with similar problem as I had.
Here's my code. Before </head>, add:
<script type='text/javascript'>
//<![CDATA[
function stopIfFound(strx,token){
var theLocation = strx.indexOf(token);
if(theLocation!=-1){
strx = strx.substr(0,theLocation);
}
return strx;
}
function removeHtmlTag(strx, chop){
strx = stopIfFound(strx,'<div class="pls-exclude-from-snippet">');
if(strx.indexOf("<")!=-1){
var snippet = strx.split("<");
for(var i=0;i<snippet.length;i++){
if(snippet[i].indexOf(">")!=-1){
snippet[i] = snippet[i].substring(snippet[i].indexOf(">")+1,snippet[i].length);
}
}
strx = snippet.join("");
}
chop = (chop < strx.length-1) ? chop : strx.length-2;
while(strx.charAt(chop-1)!=' ' && strx.indexOf(' ',chop)!=-1) chop++;
strx = strx.substring(0,chop-1);
return strx+'...';
}
function createSnippet(pID){
var div = document.getElementById(pID);
var summ = snippet_count;
var summary = '<div class="snippets">' + removeHtmlTag(div.innerHTML,summ) + '</div>';
div.innerHTML = summary;
}
//]]>
</script>
Find <data:post.snippet/>, in
<div class='post-body'>
<b:if cond='data:post.snippet'>
<data:post.snippet/>
</b:if>
</div>
replace it with
<div expr:id='"summary" + data:post.id'><data:post.body/></div>
<script type='text/javascript'>createSnippet("summary<data:post.id/>");
</script>

You can try to limit the length of the characters.
Use this syntax:
<b:eval expr='snippet(data:post.body, {length: 150})' />
150 is the length. You can change it to any numbers you want.
Check my personal blog change snippet length on Blogger without Javascript to see more example.

Related

Targeting elements of an a-tag with Nokogiri when classes dont work

I am trying to build a scraper and I would need some help with the following:
I would like to grab a bunch of data from an a-tag and some divs/spans nested in the same div.
My code look like this:
page = Nokogiri::HTML(open(website))
page.search('.company').each { |e| companies << e.text.strip }
page.search('.jobtitle').each { |e| jobtitles << e.text.strip }
page.search('.location').each { |e| locations << e.text.strip }
page.xpath('//a[#class="turnstileLink"]').map{ |e| links << e['href'] }
For the first three (company, title and location) I get either 16 or 15 results, but for the last search my array only contains 10 elements. Weirdly its they also dont match the first 10 of one of the other arrays, but rather start matching somewhere around the 3rd or 4th element of one of the other arrays.
The html of a typical card that I would like to target is here:
<div class="row result clickcard" id="pj_81c3e09223cbc6b3" data-jk="81c3e09223cbc6b3" data-advn="4563763653116462" data-tu="">
<a target="_blank" id="sja1" data-tn-element="jobTitle" class="jobtitle turnstileLink" href="/pagead/clk?mo=r&ad=-6NYlbfkN0DhDTzlYIMy8YIuVE6IrMC_kH05KGZgoAT6LTrcTn8STrwXoiuruouegXiAvJy4qud6xIecRibm3b0Q5eOBkpCiV3R04sAyQbvP7gt6NKZVpCRp32eFzXudmk-TIABX3xEZGo90a47Vz9OofqZaLDh37545RNQ3sFjM6VzWNEWwKf_YoXxeGKcAICj9AADyBuYAY7p9UIUxoox7J5U9gO8Zo2dvRW-i5FJtaUr49Vjsl04W0Jp-CN2azbfp6rrfT6RYFbJ_YAc2iI-L37eeygDtI4KXQwv_elrV8ZLEKo9rkcfEzbE129kX7JKeEq5wJ1dj7GJ4ONH1lIPJQd1gJLoqNYJVQlLTKJiBP72Z0RBmgfZQ-69U8AoEyMT6pytz6iqykLCnO-SxClmvFPJsNV96oBGzpMWtWQeVgGQ49jZfBBRq9Ubw7N73iEjCv6oQ70hcW1P4d8DYK0pCI7vu2KfUh0P9vx8AKC6wY2QoAZeeP4OiBIJ8ikKSIUYJTbe3UwKcLYP7r_3_rx1gY_JO1ReG21ctCxfqGH9DnqTSjz3SYCMZ2ZekooXa&vjs=3&p=1&sk=&fvj=1" title="Private Care Jobs With Elder - Immediate Start - £550 to £750 pw" rel="noopener nofollow" onmousedown="sjomd('sja1'); clk('sja1');" onclick="setRefineByCookie([]); sjoc('sja1',0); convCtr('SJ')">Private Care Jobs With Elder - Immediate Start - £550 to £75...</a>
<br>
<div class="sjcl">
<span class="company">
Elder</span>
<span class="location">London</span>
</div>
<div class="">
<table cellpadding="0" cellspacing="0" border="0"><tbody><tr><td class="snip">
<span class="summary">
Pass a full DBS check or have a valid check already. Access to the internet and a smartphone. At Elder, we’re looking for caring individuals to join our...</span>
</td></tr></tbody></table>
</div>
<div class="sjCapt">
<div class="result-link-bar-container">
<div class="result-link-bar"><span class=" sponsoredGray ">Sponsored</span> - <span id="tt_set_10" class="tt_set"><a id="sj_81c3e09223cbc6b3" href="#" class="sl resultLink save-job-link " onclick="changeJobState('81c3e09223cbc6b3', 'save', 'linkbar', true, ''); return false;" title="Save this job to my.indeed">save job</a></span><div id="editsaved2_81c3e09223cbc6b3" class="edit_note_content" style="display:none;"></div><script>if (!window['sj_result_81c3e09223cbc6b3']) {window['sj_result_81c3e09223cbc6b3'] = {};}window['sj_result_81c3e09223cbc6b3']['showSource'] = false; window['sj_result_81c3e09223cbc6b3']['source'] = "Indeed"; window['sj_result_81c3e09223cbc6b3']['loggedIn'] = false; window['sj_result_81c3e09223cbc6b3']['showMyJobsLinks'] = false;window['sj_result_81c3e09223cbc6b3']['undoAction'] = "unsave";window['sj_result_81c3e09223cbc6b3']['jobKey'] = "81c3e09223cbc6b3"; window['sj_result_81c3e09223cbc6b3']['myIndeedAvailable'] = true; window['sj_result_81c3e09223cbc6b3']['showMoreActionsLink'] = window['sj_result_81c3e09223cbc6b3']['showMoreActionsLink'] || false; window['sj_result_81c3e09223cbc6b3']['resultNumber'] = 10; window['sj_result_81c3e09223cbc6b3']['jobStateChangedToSaved'] = false; window['sj_result_81c3e09223cbc6b3']['searchState'] = "l=London&start=20"; window['sj_result_81c3e09223cbc6b3']['basicPermaLink'] = "https://www.indeed.co.uk"; window['sj_result_81c3e09223cbc6b3']['saveJobFailed'] = false; window['sj_result_81c3e09223cbc6b3']['removeJobFailed'] = false; window['sj_result_81c3e09223cbc6b3']['requestPending'] = false; window['sj_result_81c3e09223cbc6b3']['notesEnabled'] = false; window['sj_result_81c3e09223cbc6b3']['currentPage'] = "serp"; window['sj_result_81c3e09223cbc6b3']['sponsored'] = true;window['sj_result_81c3e09223cbc6b3']['showSponsor'] = true;window['sj_result_81c3e09223cbc6b3']['reportJobButtonEnabled'] = false; window['sj_result_81c3e09223cbc6b3']['showMyJobsHired'] = false; window['sj_result_81c3e09223cbc6b3']['showSaveForSponsored'] = true; window['sj_result_81c3e09223cbc6b3']['showJobAge'] = true;</script></div></div>
<div class="tab-container">
<div class="sign-in-container result-tab"></div>
<div class="tellafriend-container result-tab email_job_content"></div>
</div>
</div>
</div>
All cards have the same class ".clickcard" and all the relevant links have the class ".turnstileLink" but I cant seem to get consistent results when i try to page.search or page.xpath them, without having a problem matching up the data from all the different arrays correctly, besides the different number of elements I get returned.
So my question is: If I want to scrape the company name, location, job title, the url to that page and possibly another value, how would I best go about this?
I would appreciate any feedback!
Edit:
The contains() expression needs to be more complex:
contains(
concat(' ',normalize-space(#class),' '),
' turnstileLink '
)
to prevent classes like turnstileLinkerCar from matching. It's such a hassle that I would use doc.css() with a css selector like a.turnstileLink, which takes care of matching exactly the specified class name in a string that may have multiple class names.
Try:
doc.xpath('//a[contains(#class, "turnstileLink")]').each{ |e| links << e['href'] }
Or:
doc.css('a.turnstileLink').each{ |e| links << e['href'] }
Here's the problem:
require 'nokogiri'
my_html = %q{
<html>
<body>
A link
B link
C link
D link
</body>
</html>
}
doc = Nokogiri::HTML(my_html)
links = doc.xpath('//a[#class="c1"]').map{ |e| e["href"] }
p links
--output:--
["aaa"]
The class of the bbb link is "c1 c2" which is not equal to "c1".
Response to comment:
require 'nokogiri'
my_html = %q{
<html>
<body>
<div class="x">
A link
B link
C link
<div>
D link
</div>
</div>
<div class="y">
Y link
</div>
</body>
</html>
}
doc = Nokogiri::HTML(my_html)
links = doc.css('a.c1').map{ |e| e["href"] }
p links
--output:--
["aaa", "bbb", "ccc", "ddd", "yyy"]
But:
links = doc.css('div.x a.c1').map{ |e| e["href"] }
p links
--output:--
["aaa", "bbb", "ccc", "ddd"]
The same thing with xpaths:
links = doc.xpath('//div[contains(#class, "x")]//a[contains(#class, "c1")]').map{ |e| e["href"] }
plinks
--output:--
["aaa", "bbb", "ccc", "ddd"]

How to hide some text in string using CSS

Please find updated code
<html>
<title>css</title>
<head>
<style>
#st {
z-index: -114;
margin-right: -80px;
}
</style>
</head>
State Code : <span><span id="st"></span>Maharashtra - MH</span>
</html>
I got below output but i need clear overlapped text
enter image description here
the only way to approach this is using css display: none or visibility: hidden property , either one would work, i would advice display none. this is the only way CSS and HTML can hide data.
<span>State Code: <span id="st"><span style="display: none">Maharashtra - </span>MH</span></span>
You Can't do this by using CSS only here is the javascript solution for u
$("#st").html(function(){
var text= $(this).text().trim().split(" ");
var first = text.shift();
return (text.length > 0 ? "<span class='hide'>"+ first + "</span> " : first) + text.join(" ");
});
.hide {
display:none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span>State Code: <span id="st">Maharashtra - MH</span></span>
see this is HTML version but it is working fine.
<span id="span_Id">Maharashtra - MH</span>
<script>
function getSecondPart(str) {
return str.split('-')[1];
}
var span_Text = document.getElementById("span_Id").innerText;
var html = getSecondPart(span_Text);
document.getElementById("span_Id").innerHTML = html;
</script>
Update 2
Layout has significantly changed...see 2nd updated demo.
Since OP has dynamically generated text, JavaScript is needed realistically. And probably the actual text will be more than one on the page.
This demo gathers all <span> nested within a <span> (could've used #id but realistically, it should be a .class). This NodeList is converted into an array.
This array is then map()'ped on each iteration a regex is matched vs. the <span>s text.
A replace()'ment of the unwanted portion of text is overwritten and the last 2 letters remain.
Demo
var tgt = Array.from(document.querySelectorAll('span'));
tgt.map(function(s, idx) {
var str = s.textContent;
var rgx = /(State Code:).*?- (\w\w)/g;
var rep = `$1 $2`;
var res = str.replace(rgx, rep);
s.textContent = res;
});
<span>State Code: <span class="st"></span>California - CA</span><br>
<span>State Code: <span class="st"></span>New York - NY</span><br>
<span>State Code: <span class="st"></span>Oregon - OR</span><br>
<span>State Code: <span class="st"></span>Mississippi - MS</span><br>
If you use PHP... try it below..
$string = explode("-","Maharashtra - MH");
<span>State Code: <span id="st"><span style="display:none;"><?php echo $sting[0]."-"; ?></span><?php echo $string[1]; ?></span></span>

split string of spans into array of spans

I have a block of text wrapped in spans that I need to split into an array.
So currently I have
var s = `
<span class="hoverable">c</span>
<span class="hoverable">o</span>
<span class="not-hoverable">o</span>`;
I need
var s = [
"<span class="hoverable">c</span>",
"<span class="hoverable">o</span>",
"<span class="not-hoverable">o</span>"];
I've tried s.split(/<\/?span>/); to split accounting for <span> and closing </span> but
var s = [
"<span class="hoverable">c",
"<span class="hoverable">o",
"<span class="not-hoverable">o",...]
So it's not including the closing span.
As always when a regexp question wanders over into HTML or XML territory, I suggest regexp is not the right tool. Use the proper HTML parser available in the language you are using. In case of JavaScript (implied by your use of var and string template syntax):
let s = `
<span class="hoverable">c</span>
<span class="hoverable">o</span>
<span class="not-hoverable">o</span>`;
let d = document.createElement('div');
d.innerHTML = s;
let result = Array.from(d.children).map(e => e.outerHTML);
console.log(result);
You can always use the DOM if you are working in a browser and the value is inside of an element. If it is not and you have a string then you can still use DOM dynamically. Finally, you can use regular expressions.
Here's a round up:
var s = ' ' +
'<span class="hoverable">c</span>' +
'<span class="hoverable">o</span>' +
'<span class="not-hoverable">o</span> ';
var r2 = s.match(/<span(.*?)>(.*?)<\/span>/gm);
console.log("using regular expressions");
console.log(r2);
function findWithDOM() {
console.log("using DOM");
var elements = [].slice.call(document.querySelectorAll('#myDiv span'));
console.log(elements);
}
function findWithDynamicDOM() {
console.log("using Dynamic DOM");
var element = document.createElement("div");
element.innerHTML=s;
var elements = [].slice.call(element.querySelectorAll('span'));
console.log(elements);
}
<div id="myDiv"><span class="hoverable">c</span>
<span class="hoverable">o</span>
<span class="not-hoverable">o</span>
</div>
<input id='btnFind' onclick='findWithDOM()' value='Find With DOM' type="button" />
<input id='btnFind' onclick='findWithDynamicDOM()' value='Find Dynamic DOM' type="button" />

Showing previously selected items in drop down menu

Using angular and angular-xeditable I have a drop down menu with a number of options from which to select in the 'amenities' array.
Once I save the selections from the drop down and saved them, I want to make it possible for the user to come back to the page and edit previously selected items.
HTML:
<select multiple class="w-select am-dropdown" size="12" data-ng-model="Amenities"
data-ng-options="amenity.amenity for amenity in amenities" required=""></select>
JS:
$scope.amenities = [{amenity: coffee}, {amenity: beer}, {amenity: parking}];
$scope.Amenities = [];
$scope.selectedAmenities = [coffee, beer];//these are amenities saved in the
database that I want to be able to show as selected using the editable form
Have a case as same as this
Add $scope.$watch to put selected value to $scope.selectedValues as below
$scope.$watch('selectedAmenities ', function (nowSelected) {
$scope.selectedValues = [];
if (!nowSelected) {
return;
}
angular.forEach(nowSelected, function (val) {
$scope.selectedValues.push(val.amenity.toString());
});
});
And then use it like below:
select multiple ng-model="selectedValues" class="w-select am-dropdown" size="12" >
<option ng-repeat="amenity in amenities" value="{{amenity.amenity}}" ng-selected="{{selectedValues.indexOf(amenity.amenity)!=-1}}">{{amenity.amenity}}</option>
</select>
Full code at Plunker
Hope it helps you.
do u mean this?
var m = angular.module('m', []).controller('c', ['$scope',
function($scope) {
$scope.avilibleValues = ['a1', 'a2', 'a3', 'a4', 'a5'];
$scope.selected = [];
$scope.last = 'a1';
$scope.selecting = 'a1';
$scope.select = function(it) {
console.log('select:' + it);
$scope.selecting = it;
};
$scope.change = function() {
console.log($scope.last);
$scope.last && $scope.selected.push($scope.last);
$scope.last = $scope.selecting;
};
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="script.js"></script>
<div ng-app="m">
<div ng-controller="c">
<div class="row">
<label>seleted:</label>
<div>
<p ng-repeat="it in selected">
<a ng-click="select(it)">{{it}}</a>
</p>
<div>
</div>
<div class="row">
<label>selet</label>
<select ng-model="selecting" ng-options=" i for i in avilibleValues" ng-change="change()"></select>
</div>
</div>
</div>
<p>
selecting:{{selecting}}
<p>
selected:{{selected}}
<p>
last:{{last}}
<p>
</div>
</div>

Asp .Net client side dynamic text

Im learning Asp.Net, after writing a master page, I couldnt make it run on client (to actually see the animation). The thread waiting action is done on server before publishing the web page so animation is not dynamic. It shows only the final state of the page.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body bgcolor="red">
<center>
<h2>Hello w3schools!</h2>
<h4 id="aa">qq</h4>
<h3>
<p><%
for (int i = 0; i < 30; i++)
{
System.Threading.Thread.Sleep(25);
int txtLeft = 300 + (int)(100*Math.Sin(i));
int txtTop = 300+(int)(100*Math.Cos(i));
string theText = "Hello there!";
Response.Write("<div style=\"position:absolute; left: "+ txtLeft + "px; top:" + txtTop + "px; \">" + theText +"</div>");
}
%></p>
</h3>
</center>
</body>
</html>
I tried
runat="client" (near the "p" letter which is in brackets)
but it failed:
Runat must have value Server.
Take a look at this jsFiddle:
$(Start);
function Start() {
var txtLeft, txtTop, theText, theHTML;
theText = "Hello there!";
for (var i = 0; i < 30; i++) {
txtLeft = 300 + (100 * Math.sin(i));
txtTop = 300 + (100 * Math.cos(i));
theHTML = '<div style="position:absolute; left: ' + txtLeft + 'px; top:' + txtTop + 'px;">' + theText + '</div>';
$('#Demo').append(theHTML);
}
}
Basically, there's no need for server-side programming to generate the output you want; use asp.net for server work. What you can do is add this script to the page in a script tag along with the jquery reference and you're done.