I'm using JSON in my app to call elements from a database.
One of these elements is a text block with href links.
The JSON looks like :
"textBlock":"<a href=\"http:\/\/www.website.com\/" target=\"_blank\">Link<\/a>
In my app I call label with :
self.TextLabel.text = self.item[#"textBlock"];
[selfTextLabel sizeToFit];
Result in my app shows :
Link
Would it be possible to write / strip this link properly ?
I came across this solution to strip the html, which works fine, but my links don't work, I would like to know if I can keep my links working.
OK, so after some more searching and trying, I finally got what I needed.
I first tried to put my string in UITextView, selectable with links detection. Would have been great if I had written directly my URLs in the text.
But again, the strings I receive from JSON look like :
Link
I looked at Fancy UILabels and NSDataDetector, but it seemed like the labels were working but still showing http:// which looked not good for me.
So I figured best way was to put this string in a UIWebView, and call it like (I replaced TextLabel in the question with TextView).
[self.TextView loadHTMLString:self.item[#"textBlock"] baseURL:nil];
I finally had some last issue, as the links were opening in the UIWebView instead of Safari.
So I added self.TextView.delegate = self; in viewDidLoad.
And
-(BOOL) webView:(UIWebView *)TextView shouldStartLoadWithRequest:(NSURLRequest *)inRequest navigationType:(UIWebViewNavigationType)inType {
if ( inType == UIWebViewNavigationTypeLinkClicked ) {
[[UIApplication sharedApplication] openURL:[inRequest URL]];
return NO;
}
return YES;
}
.h file must also call UIWebViewDelegate.
And if you think UIWebView default font is ugly in this case, like I did, you can do :
NSString *nicerTextBlock = self.item[#"textBlock"];
[self.textView loadHTMLString:[NSString stringWithFormat:#"<style type='text/css'>body { font-family: Helvetica; font-size: 12 } ></style>%#", nicerTextBlock] baseURL:nil];
Hope this can spare some time for other people.
Related
I have a method to parse website with using Swiftsoup go get the price of a product:
#objc func actionButtonTapped(){
let url = "https://www.overkillshop.com/de/c2h4-interstellar-liaison-panelled-zip-up-windbreaker-r001-b012-vanward-black-grey.html"
let url2 = "https://www.asos.com/de/asos-design/asos-design-schwarzer-backpack-mit-ringdetail-und-kroko-muster/prd/14253083?clr=schwarz&colourWayId=16603012&SearchQuery=&cid=4877"
do {
let html: String = getHTMLfromURL(url: url2)
let doc: Document = try SwiftSoup.parse(html)
let priceClasses: Elements = try doc.select("[class~=(?i)price]")
for priceClass: Element in priceClasses.array() {
let priceText : String = try priceClass.text()
print(try priceClass.className())
print("pricetext: \(priceText)")
}
} catch Exception.Error(let type, let message) {
print(message)
} catch {
print("error")
}
}
The method works fine for url but for url2 it is not printing all all the classNames even though they match the regex. This is where the price actually is:
<span data-id="current-price" data-bind="text: priceText(), css: {'product-price-discounted' : isDiscountedPrice }, markAndMeasure: 'pdp:price_displayed'" class="current-price">36,99 €</span>
The output of the function is this:
product-price pricetext:
stock-price-retry-oos
pricetext:
stock-price-retry
pricetext:
It is not printing class=current-price. Is something wrong with my regex or why does it not find that class??
EDIT:
I found out that the price is not actually inside the HTML of url2. Only the classes that are actually printed out are inside. What's the reason for that and how can I solve that?
The html is not static. It can change over time. If you make a get request to the site's URL you will get the initial value of the html for that site.
But on browsers there is this thing, called javascript, that can make the page's HTML change over time. It's quite common actually:
- The site gets loaded at first with some javascript
- The javascript (developed by the site's creator) than runs and does stuff
- Content dynamically changes by calling some API by that javascript
You can't scrape that content by HTML scraping of the base URL.
If you ask me how I'd do that anyway, is by looking for the site's HTTP requests where it gets the content. Look at that API and use that API myself. Get the data, and store it in some of my servers.
Than on the client I call my server's API to get that data.
Also I'm not really sure that's legal.
But, as far as I understood by your last couple questions, you don't want to do that.
If you really need to do that on the client, you can use WKWebView, load the page, wait for the content to show up, and then get the current HTML of the page by doing something like this:
webView.evaluateJavaScript("document.documentElement.outerHTML.toString()",
completionHandler: { (html: Any?, error: Error?) in
print(html)
})
Look at this answer for more about this.
I hope this solves all of your problem, because I think I don't have much more time to help you :D
Note: This is about JavaFX WebView, not Android WebView (i. e. I have seen "Android Webview Anchor Link (Jump link) not working").
I display a generated HTML page inside a javafx.scene.web.WebView that contains anchors and links to those anchors like this:
<p>Jump to Introduction</p>
some text ...
<h1 id="introduction">Introduction</h1>
more text ...
I use this code to load the HTML into the WebView:
public void go(String location) {
try {
// read the content into a String ...
String html = NetUtil.readContent(new URL(location), StandardCharsets.UTF_8);
// ... and use loadContent()
webview.getEngine().loadContent(html);
} catch (IOException e) {
LOG.error(e);
}
}
Everything is rendered correctly, but if I click on the link named "Introduction", nothing happens.
The HTML however is correct, which I checked by instead using this code:
public void go(String location) {
// use load() to directly load the URL
webview.getEngine().load(location);
}
Now, everything worls fine.
The problem seems to be somehow because the document URL of the WebView is null when using loadContent(), but since it's a readonly property, I have no idea how to make it work.
I need to use loadContent(), because the HTML is generated on the fly, and if possible in any way, I don't want to have to write it out to a file just to make anchor links working. Is there a way to fix this?
EDIT
I filed a bug for JavaFX.
It's probably another WebEngine bug. A lot of that code is just a native libraries wrapped in api, so we can't modify it in runtime to fix some disabilities.
If you are able to change the structure of generated file you can implement scrolling to element in js:
<script>
function scrollTo(elementId) {
document.getElementById(elementId).scrollIntoView();
}
</script>
<a href='#' onclick=scrollTo('CX')>Jump to Chapter X</a>
<h2 id="CX">Chapter X</h2>
If you can't change the structure, there is some steps that I've made to try to fix it and some suggestions - at first I've set value of location by reflections after loadContent for sure:
Field locationField = WebEngine.class.getDeclaredField("location");
locationField.setAccessible(true);
ReadOnlyStringWrapper location = (ReadOnlyStringWrapper) locationField.get(engine);
location.set("local");
But in fact, keeping state of actual location is just an information for you and manipulating this changes nothing. I've also found a way to set url from js (just a long shot, we don't have any specific details why it's not working):
window.history.pushState("generated", "generated", '/generated');
Of course we can't because of:
SecurityError: DOM Exception 18: An attempt was made to break through the security policy of the user agent.
I think you should forget about loadContent(). You said that you didn't want to write generated content to file. A little dirty hack but really helpful for you could be wrapped http server on random and unused port in your application. You don't even need external libraries because Java has simple utilities like that:
HttpServer server = HttpServer.create(new InetSocketAddress(25000), 0);
server.createContext("/generated", httpExchange -> {
String content = getContent();
httpExchange.sendResponseHeaders(200, content.length());
OutputStream os = httpExchange.getResponseBody();
os.write(content.getBytes());
os.close();
});
server.setExecutor(null);
server.start();
You can also use another browser to display your page, e.g. JCEF (Java Chromium Embedded Framework).
This is a very hard question, for all of you. Maybe some of you can answer it and if you do you are a life saver. Ok so my project is an RSS Feed which displays the news and when you click on it, it takes you to the page of the article. The website I am getting this feed from has menu and the user HAS to scroll down each time to view the full article. :(
So I know in WebView you can embed code into the web view, I was wondering if there was some code in HTML of how you can actually delete this menu. I add some screen shots. Look :
It is a Wordpress website, if you could give me the HTML code it would be awesome but it would be even better if you can give me the Xcode code to do this as well.
Thanks to everyone that takes the time to read / reply.
Use css to hide the menu:
#nav_menu-2 {
display: none;
}
In your context, you can automatically apply this change by injecting a Javascript script in your webview, which will apply the css rule to your element:
- (void)webViewDidStartLoad:(UIWebView *)webView
{
NSString *js = #"document.getElementById('nav_menu-2').style.display = 'none';";
[self.webView stringByEvaluatingJavaScriptFromString:js];
}
However, this is far from perfect as the js snippet will be executed after the page has finished loading, so the user will see the menu disappear.
EDIT:
If you don't want to reference the div's id, you could use the class widget_nav_menu:
- (void)webViewDidStartLoad:(UIWebView *)webView
{
NSString *js = #"var menus = document.getElementsByClassName('widget_nav_menu');"
"for (var i = 0; i < menus.length; i++) {"
"menus[i].style.display = 'none';"
"}";
[self.webView stringByEvaluatingJavaScriptFromString:js];
}
Beware that this will hide all elements with this class (but this could be what you need).
Can you supply a link or the html for the menu?
A frontend solution would be to use javascript/jQuery with something like:
<script>
$(document).ready(function(){
$('#your-menu-id').hide();
});
</script>
i've been trying this since last week, to make the active class work on those dynamic links:
<li>{{#linkTo tag 'bw'}}Black and White{{/linkTo}}</li>
<li>{{#linkTo tag 'instax'}}Instax{{/linkTo}}</li>
<li>{{#linkTo tag 'digital'}}Digital{{/linkTo}}</li>
I put a code running here: http://jsbin.com/opuzop/1/edit so if you feel ok to help me with that would be great :D it's my photo portfolio as well.
Also, if I try to upload to the newer version of Ember, some stuff stop to work, like the JS I created on
App.GeneralView = Ember.View.extend({
didInsertElement: function() {
if(this.$() !== undefined){...
It was created to load after the view render, so I do a image resize and a body resize too, and set everything horizontal, but with the newer version it only work when accessed directly.
Also, sometimes it don't get the JSON from Tumblr and stop working.
I'm not sure, but I think it has to do with the serialization of your object, try adding something like this in your "App.TagRoute" route:
serialize: function(param) {
return {tag: param.tag}
}
Is it possible for me to add text to a uiwebview and change the text and colours in this view without having separate html files? So I define whats in the html file in a switch statement? I do this at the moment using labels, but I can't have more than one colour in a label so I need to use html, as core text looks quite complicated.
switch (counter)
{
case 0:
titleLabel.text = #"needs to be more than one colour";
break;
case 1:
titleLabel.text = #"needs to be more than one colour";
break;
and so on...
Can I in some way define whats in a html file in tags in the code in these switches rather than having seperate html files? If so how would I do this?
Cheers,
Lewis
Assuming your HTML contains a CSS class called myCssClass where you specify your colors, and a label:
<label id="myTextElement">A Label</label>
You can programmatically execute javascript to set a different CSS class using code like this:
UIWebView *webView;
.
.
.
[webView stringByEvaluatingJavaScriptFromString:#"document.getElementById(\"myTextElement\").className = \"myCssClass\";"];
though honestly if you watch the WWDC 2012 videos on CoreText you might be less intimidated...