iOS UIWebView totally fails to understand more than one #font-face? - ios

Notice this simple css/html which is being displayed in a local UIWebView:
there's the simulator showing it...
Notice there are two #font-face definitions.
But ... only the second one works. If you swap them around, only the second one works.
So here ...
#font-face {
font-family:'aaa';
src: local('SourceSansPro-Regular'),
url('SourceSansPro-Regular.ttf') format('truetype');
}
#font-face {
font-family:'bbb';
src: local('SourceSansPro-BoldIt'),
url('SourceSansPro-BoldItalic.ttf') format('truetype');
}
only "bbb" works, the other one seems to be "cancelled". Then here ..
#font-face {
font-family:'bbb';
src: local('SourceSansPro-BoldIt'),
url('SourceSansPro-BoldItalic.ttf') format('truetype');
}
#font-face {
font-family:'aaa';
src: local('SourceSansPro-Regular'),
url('SourceSansPro-Regular.ttf') format('truetype');
}
only "aaa" works, the other one seems to be "cancelled".
Here's how to do it in Swift,
// load a simple UIWebView (say, an "about" or "legal" screen)
// base is in template.html
import UIKit
import WebKit
class MinorWebView:UIViewController
{
#IBOutlet var wv:UIWebView!
#IBInspectable var filename:String = "?"
// for example, "about" for "about.html"
...
func makeHtml()
{
print("making html for ... " ,filename)
let ourSize = grid.yourSizeDecisionMechanism
let sizeString = String(format:"%.0f", ourSize)
let p1 = NSBundle.mainBundle().pathForResource("template", ofType: "html")
var html:String = try! NSString(contentsOfFile:p1!, encoding:NSUTF8StringEncoding) as String
let p2 = NSBundle.mainBundle().pathForResource(filename, ofType: "html")
let content:String = try! NSString(contentsOfFile:p2!, encoding:NSUTF8StringEncoding) as String
html = html.stringByReplacingOccurrencesOfString("STUFF", withString:content)
html = html.stringByReplacingOccurrencesOfString("SIZEPOINTS", withString:sizeString)
print("Made html like this ---\n" ,html ,"\n------")
wv.loadHTMLString(html as String, baseURL:nil)
}
}
Simply drag "template.html" and "about.html" in to the project (just as you would with an image); ensure they have target membership.

You have an error in the <style> block: it starts with a <meta> element. This will throw the parser off; apparently it thinks that everything up until the first } is bad and needs to be discarded.
Solution: take the <meta> out of the <style>.

Related

Bullet points and alphabets are missing when converting html to pdf using jsPDF

I try to convert from html to pdf using jsPDF.
I could not get the pdf as the original html.
ordered list and unordered list bullet points are missing in the pdf file.
ordered-list-in-html
ordered-list-in-pdf
unordered-list-in-html
unordered-list-in-pdf
function BlazorDownloadFile(filename, text) {
let parser = new DOMParser();
let doc = parser.parseFromString(text, "text/html");
console.log(doc.body);
const element = doc.body;
var opt = {
margin: 1,
filename: filename,
html2canvas: { scale: 2 },
jsPDF: { unit: "cm", format: "a4", orientation: "portrait" },
};
// Choose the element that our invoice is rendered in.
html2pdf().set(opt).from(element).save();
}
Please help me to fix this issue.
Here is a workaround for bullet points in scss you can use to overcome this issue:
ul li {
list-style-type: none;
&:before {
content: '• ';
margin-left: -1em;
}
}

Insert CSS into loaded HTML in UIWebView / WKWebView

I am successfully able to get HTML content and display into my UIWebView.
But want to customize the content by adding an external CSS file. I can only change the size of text and font. I tried every possible solution to make changes but it does not work - it shows no changes.
Below is my code
HTMLNode* body = [parser body];
HTMLNode* mainContentNode = [body findChildWithAttribute:#"id" matchingName:#"main_content" allowPartial:NO];
NSString *pageContent = [NSString stringWithFormat:#"%#%#", cssString, contentHtml];
[webView loadHTMLString:pageContent baseURL:[NSURL URLWithString:#"http://www.example.org"]];
-(void)webViewDidFinishLoad:(UIWebView *)webView1{
int fontSize = 50;
NSString *font = [[NSString alloc] initWithFormat:#"document.getElementsByTagName('body')[0].style.webkitTextSizeAdjust= '%d%%'", fontSize];
NSString *fontString = [[NSString alloc] initWithFormat:#"document.getElementById('body').style.fontFamily=\"helvetica\""];
[webView1 stringByEvaluatingJavaScriptFromString:fontString];
[webView1 stringByEvaluatingJavaScriptFromString:font];
}
Please help me get the css stylesheet in my view.
You can do it like this:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
NSString *cssString = #"body { font-family: Helvetica; font-size: 50px }"; // 1
NSString *javascriptString = #"var style = document.createElement('style'); style.innerHTML = '%#'; document.head.appendChild(style)"; // 2
NSString *javascriptWithCSSString = [NSString stringWithFormat:javascriptString, cssString]; // 3
[webView stringByEvaluatingJavaScriptFromString:javascriptWithCSSString]; // 4
}
What this code does:
// 1 : Define a string that contains all the CSS declarations
// 2 : Define a javascript string that creates a new <style> HTML DOM element and inserts the CSS declarations into it. Actually the inserting is done in the next step, right now there is only the %# placeholder. I did this to prevent the line from becoming too long, but step 2 and 3 could be done together.
// 3 : Combine the 2 strings
// 4 : Execute the javascript in the UIWebView
For this to work, your HTML has to have a <head></head> element.
EDIT:
You can also load the css string from a local css file (named "styles.css" in this case). Just replace step //1 with the following:
NSString *path = [[NSBundle mainBundle] pathForResource:#"styles" ofType:#"css"];
NSString *cssString = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
As another option you can just inject a <link> element to the <head> that loads the CSS file:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
NSString *path = [[NSBundle mainBundle] pathForResource:#"styles" ofType:#"css"];
NSString *javascriptString = #"var link = document.createElement('link'); link.href = '%#'; link.rel = 'stylesheet'; document.head.appendChild(link)";
NSString *javascriptWithPathString = [NSString stringWithFormat:javascriptString, path];
[webView stringByEvaluatingJavaScriptFromString:javascriptWithPathString];
}
This solution works best for large CSS files. Unfortunately it does not work with remote HTML files. You can only use this when you want to insert CSS into HTML that you have downloaded to your app.
UPDATE: WKWebView / Swift 3.x
When you are working with a WKWebView injecting a <link> element does not work because of WKWebView's security settings.
You can still inject the css as a string. Either create the CSS string in your code //1 or put it in a local file //2. Just be aware that with WKWebView you have to do the injection in WKNavigationDelegate's webView(_:didFinish:) method:
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
insertCSSString(into: webView) // 1
// OR
insertContentsOfCSSFile(into: webView) // 2
}
func insertCSSString(into webView: WKWebView) {
let cssString = "body { font-size: 50px; color: #f00 }"
let jsString = "var style = document.createElement('style'); style.innerHTML = '\(cssString)'; document.head.appendChild(style);"
webView.evaluateJavaScript(jsString, completionHandler: nil)
}
func insertContentsOfCSSFile(into webView: WKWebView) {
guard let path = Bundle.main.path(forResource: "styles", ofType: "css") else { return }
let cssString = try! String(contentsOfFile: path).trimmingCharacters(in: .whitespacesAndNewlines)
let jsString = "var style = document.createElement('style'); style.innerHTML = '\(cssString)'; document.head.appendChild(style);"
webView.evaluateJavaScript(jsString, completionHandler: nil)
}
Since UIWebView is deprecated in iOS 12, I'll only answer for WKWebView.
I've implemented CSS loading like it was described in the accepted answer. The problem was that sometimes the transition from HTML with no CSS applied to HTML with CSS was visible.
I think a better approach is to use the WKUserScript to inject the CSS like this:
lazy var webView: WKWebView = {
guard let path = Bundle.main.path(forResource: "style", ofType: "css") else {
return WKWebView()
}
let cssString = try! String(contentsOfFile: path).components(separatedBy: .newlines).joined()
let source = """
var style = document.createElement('style');
style.innerHTML = '\(cssString)';
document.head.appendChild(style);
"""
let userScript = WKUserScript(source: source,
injectionTime: .atDocumentEnd,
forMainFrameOnly: true)
let userContentController = WKUserContentController()
userContentController.addUserScript(userScript)
let configuration = WKWebViewConfiguration()
configuration.userContentController = userContentController
let webView = WKWebView(frame: .zero,
configuration: configuration)
return webView
}()
You can read more about this approach in this blog post.
Instead of applying css with style tag it's better to apply it with the link tag:
func insertContentsOfCSSFile2(into webView: WKWebView) {
guard let path = Bundle.main.path(forResource: "resource", ofType: "css") else { return }
let csFile = "var head = document.getElementsByTagName('head')[0];var link = document.createElement('link'); link.rel = 'stylesheet';link.type = 'text/css';link.href = '\(path)';link.media = 'all';head.appendChild(link);"
webView.evaluateJavaScript(csFile) {(result, error) in
if let error = error {
print(error)
}
}
}
I have tested it.
it is working fine.
You need to add this header before apple style to HTML
let fontName = UIFont.systemFont(ofSize: 17.0).fontName
let htmlContent = """
<header>
<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no'>
</header>
<style type='text/css'>
img{max-height: 100%; min-height: 100%; height:auto; max-width: 100%; width:auto;margin-bottom:5px;}
p{text-align:left|right|center; line-height: 180%; font-family: '\(fontName)'; font-size: 17px;}
iframe{width:100%; height:250px;}
</style> \(html)
"""
webView.loadHTMLString(htmlContent, baseURL: Bundle.main.bundleURL)
I tried Amer Hukic answer. But did not work just the way it is. I added below code between my html head tags.
<link rel="stylesheet" href="style.css">
See #joern's accepted answer for more complete details. I'm adding this answer because I ran into a weird edge case. My particular use case needed to add styling to a div with a class="dialog". For some reason styling using .dialog and div weren't working though other types of styling were working. In the end I used the following to set the width of the dialog
let width = Int(webView.bounds.width)
let script = "document.getElementsByClassName(\"dialog\")[0].style.width = \"\(width)px\""
webView.evaluateJavaScript(script)

Custom fonts with CKeditor and Rails

In my Rails 4.2 app,I am trying to add new fonts to the CKeditor Toolbar, what I did is the following :
As the documentation says to customize ckeditor I added 2 files :
app/assets/javascripts/ckeditor/config.js
app/assets/javascripts/ckeditor/contents.css
in te config.js I have this code :
CKEDITOR.editorConfig = function(config) {
config.contentsCss = 'contents.css';
config.font_names = 'Open Sans;' + config.font_names;
config.toolbar = [
['Styles', 'Format', 'Font', 'FontSize']
];
}
in the contents.css I have this code :
#font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
src: local('Open Sans'), local('OpenSans'), url(http://fonts.gstatic.com/s/opensans/v10/cJZKeOuBrn4kERxqtaUH3T8E0i7KZn-EPnyo3HZu7kw.woff) format('woff');
}
Here the 'Open Sans' is added to the fonts in the toolbar's drop-down, but when i try to apply the 'Open Sans' font to a text it doesn't work !
For now I get this error in the firebug console :
"NetworkError: 404 Not Found - http://members.lvh.me:3000/posts/assets/contents.css"
I tried to change the above : config.contentsCss = 'contents.css'; to config.contentsCss = '/assets/javascripts/ckeditor/contents.css'; but it still shows the same 404 Not Found error !!
Also I think even if I fix that it will still don't apply the font ! Is here anyone who know the solution ?
Update :
I replaced the config.contentsCss = 'contents.css'; with config.contentsCss = '/assets/ckeditor/contents.css'; and the error disappear, but when I try to apply the font to a text, there is no change !
After a full day of research I finally found a solution which work well for my need, I hope this can help someone in the same situation (so you don't have to struggle like I did )
just add the following code to your app/assets/javascripts/ckeditor/config.js
CKEDITOR.editorConfig = function(config) {
// .....
// .....
// an array of fonts from "google fonts", I listed 3 fonts here
myFonts = ['Architects Daughter', 'Open Sans', 'Dancing Script'];
config.font_names = 'sans serif';
for(var i = 0; i<myFonts.length; i++){
config.font_names = config.font_names+';'+myFonts[i];
myFonts[i] = 'http://fonts.googleapis.com/css?family='+myFonts[i].replace(' ','+');
//assuming you use jquery
$("head").append("<link rel='stylesheet' href='"+ myFonts[i] +"'>");
}
}
just to mention that this solution is founded here : http://ckeditor.com/forums/CKEditor-3.x/CKE-and-Google-Fonts-Api, thanks to 'naveenram'

accessing pseudo-element property values through getComputedStyle in dart

I wish to detect what media query is active - I'm using Bootjack, so hence I am using the default breakpoints
I expected to be able to use getComputedStyle() to get hold of the value of the 'content' property in the example below - but I don't seem to get the syntax correct. I can happily get the value of an element - say the font-famly on the body, but not pseudo-elements...
Here's what I am doing:
Given this css..
/* tablets */
#media(min-width:768px){
body::after {
content: 'tablet';
display: none;
}
}
#media(min-width:992px){
body::after {
content: 'desktop';
display: none;
}
}
#media(min-width:1200px){
body::after {
content: 'large-screen';
display: none;
}
}
I have this in my dart file:
String activeMediaQuery = document.body.getComputedStyle('::after').getPropertyValue('content');
but activeMediaQuery is always empty.
I've tried ('after') and (':after') and anything else weird and wonderful but to no avail.
String activeMediaQuery = document.body.getComputedStyle().getPropertyValue('font-family');
sets the variable activeMediaQuery to the value of the font-family that I am using (not much use to me though!)
What should I be doing?
You can also subscribe to MediaQuery change events
for more details see https://github.com/bwu-dart/polymer_elements/blob/master/lib/polymer_media_query/polymer_media_query.dart
There is a bug in Dart and the workaround uses dart-js-interop.
This is the code from the polymer-media-query element. I don't know if the comments not suppored in Dart yet are still valid. It's a few months since I tried it.
Here is an example page that shows how to use the element.
https://github.com/bwu-dart/polymer_elements/blob/master/example/polymer_media_query.html
var _mqHandler;
var _mq;
init() {
this._mqHandler = queryHandler;
mqueryChanged(null);
if (_mq != null) {
if(context['matchMedia'] != null) {
_mq.callMethod('removeListener', [_mqHandler]);
}
// TODO not supported in Dart yet (#84)
//this._mq.removeListener(this._mqHandler);
}
if (mquery == null || mquery.isEmpty) {
return;
}
if(context['matchMedia'] != null) {
_mq = context.callMethod('matchMedia', ['(${mquery})']);
_mq.callMethod('addListener', [_mqHandler]);
queryHandler(this._mq);
}
// TODO not supported in Dart yet (#84)
// Listener hast to be as MediaQueryListListener but this is and abstract
// class and therefor it's not possible to create a listner
// _mq = window.matchMedia(q);
// _mq.addListener(queryHandler);
// queryHandler(this._mq);
}
void queryHandler(mq) {
queryMatches = mq['matches'];
//fire('polymer-mediachange', detail: mq);
}
This worked for me with the CSS you provided in your question but only when the window was wider than 768 px. You might miss a rule with max-width: 768px
import 'dart:html' as dom;
void main () {
dom.window.onResize.listen((e) {
var gcs = dom.document.body.getComputedStyle('::after');
print(gcs.content);
});
}

Extracting Image Link from a rss feed on windows phone

I have a question.
How can I extract an url from an rss-feed?
The string which I need to extract is something like this:
><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="screen2" src="http://hereisthelink/screen2.png" alt="screen2" width="261" height="434" border="0" />
This is on the rss feed of my self hostet wordpress-blog, within the <content:encoded> section.
I want to fetch the first Image of an entry to get it together with the title (this works) in my ListBox.
However I tried many things to achieve this, but nothing works.
I am working with the Syndication.dll of Silverlight 3 to extract the feed items.
At the moment I am standing really in front of a wall for this to solve.
I am open to any suggestions.
You can use HTML Agility pack http://htmlagilitypack.codeplex.com/ There's a version for Windows Phone (HAPPhone in the trunk). After getting a Document from the content of the post you can get the first img element child of them.
var firstimage = document.DocumentNode.Descendants("img").FirstOrDefault();
Something like this should work for you:
var document = XDocument.Parse(html);
var items = new List<Item>();
var channel = (XContainer) document.Root.FirstNode;
foreach (XElement item in channel.Nodes())
{
try
{
var item = new Item();
var nodes = item.Nodes().ToArray();
foreach (XElement keyValue in nodes)
{
var value = keyValue.Value.Trim('\r', '\t', '\n', ' ').ToLower();
switch (keyValue.Name.LocalName)
{
case "title": item.Title = value; break;
case "content:encoded": item.Content = value; break;
// TODO: add more fields
}
}
var match = Regex.Match(item.Content, "<img(.*?) src=\"(.*?)\"[^>]*>");
item.FirstImageUrl = match.Groups[2].Value;
}
catch
{
// TODO: handle exception
}
}
return items;
You only have to finish the switch statement and create the Item class.

Resources