For some reason when I try running the following code:
var casper = require('casper').create();
var x = require('casper').selectXPath;
var links = [];
casper.start('http://www.website.com');
function getLinks() {
var links = document.querySelectorAll(x('//*[#id="horizontalList"]/li[#class="paddingRight6"]/a');
return Array.prototype.map.call(links, function(e) {
return e.getAttribute('href')
});
}
casper.then(function() {
links = this.evaluate(getLinks);
this.echo(links);
}
casper.run();
Returns a null object, but when I use the very same xpath selector in conjunction with the thenClick method, everything works fine and the url changes. Why on earth is that?
So, it turns out that the querySelectorAll method doesn't actually support XPath. In fact it doesn't come from casperjs at all, and is supported by the browser, which is why it accepts CSS3 selectors, and not XPath. It was tough for me to figure that out so I figured I would put this up in case anyone else had this problem. You have to use CSS3 selectors for this within casperjs so the line:
var links = document.querySelectorAll(x('//*[#id="horizontalList"]/li[#class="paddingRight6"]/a');
Needs to be changed to:
var links = document.querySelectorAll('ul#horizontalList li.paddingRight6 a');
Happy hacking
The below function works for me with Xpath.
function getLinks() {
var links =__utils__.getElementsByXPath('//*[#id="horizontalList"]/li[#class="paddingRight6"]/a');
return Array.prototype.map.call(links, function(e) {
return e.getAttribute('href');
});
}
Related
I'm now using casperjs for web crawling. Almost everything is good, but I faced some trouble. First, my code is like below.
casper.start().each(SOME_URLS, function(self, URL) {
self.thenOpen(URL, function() {
self.then(function() {
var getDatas = function() {
var title = $('SOME_SELECTOR').map(function() {
return $(this).text();
}).get();
return {
title: title
};
}
data = self.evaluate(getDatas);
console.log(JSON.stringify(data));
});
});
}).run();
I want to get some data from webpage to 'data' variable. Sometimes data is perfectly good(on console.log), but sometimes, data is empty!
Why this happening? What did I wrong?
The problem is you cant call casper.start more than once. Your loop needs to inside the casper.start function or inside a casper.then
See this excellent SO answer to help you do this.
Basically only call casper.start once and place your loop inside a casper.then
Can anyone help me translate this to prototype
var btn = $('#onestepcheckout-button-place-order');
var btnTxt = $('#onestepcheckout-button-place-order span span span');
var fewSeconds = 10;
btn.click(function(){
btn.prop('disabled', true);
btnTxt.text('Even geduld A.U.B.');
btn.addClass('disabled');
setTimeout(function(){
btn.prop('disabled', false);
btnTxt.text('Bestelling plaatsen');
btn.removeClass('disabled');
}, fewSeconds*1000);
});
Prototype is confusing the sh*t out of me
Try this:
var btn = $('onestepcheckout-button-place-order');
var btnTxt = $$('onestepcheckout-button-place-order span span span')[0];
var fewSeconds = 10;
Event.observe(btn, 'click', function(){
btn.setAttribute('disabled', 'disabled');
btnTxt.innerHTML = 'Even geduld A.U.B.';
btn.addClassName('disabled');
setTimeout(function(){
btn.removeAttribute('disabled');
btnTxt.innerHTML = 'Bestelling plaatsen';
btn.removeClassName('disabled');
}, fewSeconds*1000);
});
I haven't tested it though.
I'm not going to give you the direct copypasta snippet for your problem but you only probably just need to do the following swaps:
$(selector) with $($$(selector))
prop to attr
addClass to addClassName
I'm omitting one more replacement so you can look for it yourself, for added challenge! Protip: search google for "Prototype to jQuery equivalent". So many resources!
Alternatively, you can just use jQuery in jQuery.noConflict mode and wrap the above in a jQuery closure.
(function($) {
// your code above goes here.
})(jQuery)
$('.collapse').each(function() {
var title= $(this).siblings('.accordion-heading').find('a');
$(this).on('show hide', function (e) {
if(!$(this).is(e.target))return;
title.parent().toggleClass('active', 300);
title.parent().hasClass('active') ? $('input.party').prop('value', '') : $('input.party').val(title.siblings('.delete').prop('id'));
var id = title.siblings('.delete').prop('id');
var data = {id: id};
$.post("times.php", data, function(result) {
if(title.parent().hasClass('active')){
$('.times').html('');
} else {
$('.times').html($.parseJSON(result));
}
})
})
})
So I am adding a new accordion-group to my html by adding a new party and I wan't all this to work on the newly added elements as well. I didn't find topics that could help me since it is a bit more specific than any random each function (I think).
This future elements thing is new to me, so I would appreciate some explanations or a good link to a place other that the jquery website which I already checked.
Thank you for your time!
Basically what I want to do this replace $(this).on('show hide', function (e) { with something like $(document).on('show hide', $(this), function (e) {. What I just wrote doesn't work though.
If it is just about the event handler, then you can use event delegation to capture the event on dynamically created elements as well.
There is not reason why you have to use .each here, so just omit it:
$(document.body).on('show hide', '.collapse', function() {
var title = $(this).siblings('.accordion-heading').find('a');
if(!$(this).is(e.target))return;
// rest of the code...
});
this will apply on any new objects matching selector
jQuery(document).on('show hide', '.accordion-heading a', function(event){
...
});
I use jQuery UI Autocomplete.
Part of script is:
$("input[data-autocomplete]").each(function () {
var availableTags = ["first", "second"];
And it works -autocomplete with "first" and "second"
Now i want to assign avalibleTags dinamicly like something like:
var availableTags = #Viewbag.Something
or
var availableTags = #Url.Action('Tags","Home")
It is possible? How to do it in a good way?
In your view you can do:
<script type="text/javascript">
$(function () {
var MyTags = $.getJSON('#Url.Action("Tags","Home")' function (MyList) {
// Do something with List
// var avaliableTags = MyList;
});
});
</script>
(This uses JQuery)
Would work. Where the action is in controller like:
[AcceptVerbs(HttpVerbs.Get)]
public JsonResult Tags()
{
var MyList == YOUR TAGS
return Json(MyList , JsonRequestBehavior.AllowGet);
}
Note, the use of the attribute and JSON to allow Javascript communication.
Edit: woops, used key words.
Sure, just make sure to JSON encode it:
var availableTags = #Json.Encode(ViewBag.Something);
and since I hate ViewBag and recommend you always using view models and strongly typed views:
var availableTags = #Json.Encode(Model.Something);
This assumes that Something is an array of strings property on your view model so that when the page is rendered you will get:
var availableTags = ["first", "second"];
and will be able to use it with the autocomplete plugin.
I've successfully implemented a bit of code that strips all HTML from a pasted string using stripTags(). My next goal is to mark a few tags with white flags so they get ignored on 'paste' event using .wrap() to augment the function.
I'm using prototype.js as a framework and have slowly been working through the growing pains of learning both the framework and javascript, but this issue has presented a bit of a roadblock.
I've googled around a bit and found what looks like two great solutions, but I don't seem to be implementing them correctly.
Found solutions:
http://perfectionkills.com/wrap-it-up/ (function to indicate tags to remove)
and
http://pastebin.com/xbymCFi9 (function to allow tags to keep)
I pretty much copied and pasted from the latter.
If I pull the 'br' from the code, then the regex is ignored and all html is stripped. If I leave it, nothing gets pasted.
Here is what I've pieced together (and I feel silly for not being able to figure this out!).
String.prototype.stripTags = String.prototype.stripTags.wrap(
function(proceed, allowTags) {
if (allowTags) {
if (Object.isString(allowTags)) allowTags = $w(allowTags)
this.gsub(/(<\/?\s*)([^\s>]+)(\s[^>]*)?>/, function(match) {
if (allowTags.include(match[2].toLowerCase()))
return match[1] + match[2] + match[3] + '>'
})
} else {
// proceed using the original function
return proceed();
}
});
WysiHat.Commands.promptLinkSelection = function() {
if (this.linkSelected()) {
if (confirm("Remove link?"))
this.unlinkSelection();
} else {
var value = prompt("Enter a URL", "http://www.alltrips.com/");
if (value)
this.linkSelection(value);
}
}
document.on("dom:loaded", function() {
var editor = WysiHat.Editor.attach('event_desc');
var toolbar = new WysiHat.Toolbar(editor);
editor.observe("paste", function(event) {
var el = $(this);
setTimeout(function() {
var pText = el.innerHTML.stripTags('br');
//alert(pText);
$('event_desc_editor').update(pText);
$('event_desc').setValue(pText);
}, 0);
});
(You may recognize the WysiHat code from 37Signals text editor)
note: you can see the alert commented out. If I do alert the ptext, I get 'undefined' returned.
So I've given up on and moved to a regex solution:
el.innerHTML.replace(/<(?!\s*\/?\s*p\b)[^>]*>/gi,'')