MVC Bundling breaking my calc CSS statements by removing spaces? - asp.net-mvc

I have css statements like this:
margin-left: calc(50% - 480px);
Which work fine unminified but as soon as I begin minifying, the statement gets changed to:
margin-left: calc(50%- 480px);
Rendering all calc statements broken. Similar things happen with width, max-width, min-width, etc. Is there any way I can change the behavior of the bundle to leave those CSS properties alone?
Currently I'm just using bundles.Add(new Bundle()) to prevent minification entirely, but it would be nice if I could minify correctly.

This is an issue of the optimizer.
To avoid the miniffier to remove the whitespaces, group the affected element with parenthesis. That workarrounds the issue.
margin-left: calc((50%) - 480px);

In addition to the answer above:
if you use:
margin-left: calc((50%) + 480px);
You should rewrite it as:
margin-left: calc((50%) - -480px);
Since it didn't seem to fix (50%)+ for me.

If the default css minification is not doing what you need, you can always use a third party one.
bundling allows you to use your own transformations using IBundleTransform
var bundle = new Bundle("~/Content/css", myCustomCssTransform);
there are many different bundlers - nuget
for example you could use YUI compressor:
using System.IO;
using System.Web.Optimization;
using Yahoo.Yui.Compressor;
namespace Bundler.Utilities
{
public enum contentType
{
javascript,
css
}
public class YUITransform : IBundleTransform
{
readonly string _contentType = string.Empty;
public YUITransform(contentType contentType)
{
if (contentType == contentType.css)
{
this._contentType = "text/css";
}
else
{
this._contentType = "text/javascript";
}
}
public void Process(BundleContext context, BundleResponse bundle)
{
bundle.ContentType = this._contentType;
string content = string.Empty;
foreach (FileInfo file in bundle.Files)
{
using (StreamReader fileReader = new
StreamReader(file.FullName)) {
content += fileReader.ReadToEnd();
fileReader.Close();
}
}
bundle.Content = Compress(content);
}
string Compress(string content) {
if (_contentType == "text/javascript")
{
return JavaScriptCompressor.Compress(content);
}
else
{
return CssCompressor.Compress(content,
CssCompressionType.StockYuiCompressor
);
}
}
}
}

This is totally normal as referring to CSS Values and Units Module it states
The following features are at-risk and may be dropped during the CR
period: ‘calc()’, ‘toggle()’, ‘attr()’."
If you could skip the spaces there, that wouldn't be a complete minifying. An option is replacing spaces with unicode caracter \00A0

No idea why but calc((50%) - 480px) didnt work for me, however the following worked:
subtraction:
margin-left: calc(((100%) - (480px)))
addition:
margin-left: calc((100%) - -480px)

Beware of using variables in calc. You can end up with another CssMinify() bug:
#myVariable: 0em;
margin-left: calc((50%) - #myVariable);
is compressed and unit is cut off:
margin-left: calc((50%) - 0);
and it is not valid calc() call too!

It seems the issue has been fixed in the version 2.4.9 of YUI Compressor, which can be accessed from here https://mvnrepository.com/artifact/com.yahoo.platform.yui/yuicompressor?repo=bsi-business-systems-integration-ag-scout. I have used this css file:
body{
font-size: calc(50% - 3px);
font-size: calc(50% + 3px);
font-size: calc(50% + +3px);
font-size: calc((50%) + (3px));
font-size: calc(50% + (+3px));
font-size: calc(50% + (3px));
font-size: calc(50% - (-3px));
font-size: calc(50% - -3px);
}
and running this command:
java -jar yuicompressor-2.4.9-BSI-2.jar --line-break 0 -o process.css.min.gz file.css
generates this output, which looks good:
body{font-size:calc(50% - 3px);font-size:calc(50% + 3px);font-size:calc(50% + +3px);font-size:calc((50%)+(3px));font-size:calc(50% + (+3px));font-size:calc(50% + (3px));font-size:calc(50% - (-3px));font-size:calc(50% - -3px)}

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;
}
}

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.

Can I make a bookmarklet put some text into the clipboard?

Say I wanted to have bit of text (actually 4 different addresses) that I'd like to be able to easily (and frequently) paste. Is there a way I can make a bookmarklet that will put those addresses into the clipboard?
I'd like to be able to click the appropriate one, then right click + Paste.
Yes it's possible, have a look at zeroclipboard (note: requires flash). Also see this previous question.
Try building a Firefox extension instead of a bookmarklet. Mozilla XUL (extension language) lets you do copy-paste. Another option is a Java Applet.
http://brooknovak.wordpress.com/2009/07/28/accessing-the-system-clipboard-with-javascript/
Method with no third-party libraries
While zeroclipboard could potentially work, this method will allow you to visually select an element and automatically copy the inner text to your clipboard without having to download any third-party libraries. It is based on this function by Arne Hartherz and modified to work both in HTTPS and HTTP contexts.
Readable version:
var overlay = document.createElement('div');
Object.assign(overlay.style, {
position: 'fixed',
top: 0,
left: 0,
width: '100vw',
height: '100vh',
zIndex: 99999999,
background: 'transparent',
cursor: 'crosshair'
});
document.body.append(overlay);
function copyToClipboard(textToCopy) {
// navigator clipboard api needs a secure context (https)
if (navigator.clipboard && window.isSecureContext) {
// navigator clipboard api method'
return navigator.clipboard.writeText(textToCopy);
} else {
// text area method
let textArea = document.createElement("textarea");
textArea.value = textToCopy;
// make the textarea out of viewport
textArea.style.position = "fixed";
textArea.style.left = "-999999px";
textArea.style.top = "-999999px";
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
return new Promise((res, rej) => {
// here the magic happens
document.execCommand('copy') ? res() : rej();
textArea.remove();
});
}
};
function getElement(event) {
overlay.style.pointerEvents = 'none';
var element = document.elementFromPoint(event.clientX, event.clientY);
overlay.style.pointerEvents = 'auto';
return element;
}
document.addEventListener('mousemove', function(event) {
var element = getElement(event);
if (!element) return;
var position = element.getBoundingClientRect();
Object.assign(overlay.style, {
background: 'rgba(0, 128, 255, 0.25)',
outline: '1px solid rgba(0, 128, 255, 0.5)',
top: '' + position.top + 'px',
left: '' + position.left + 'px',
width: '' + position.width + 'px',
height: '' + position.height + 'px'
});
});
overlay.addEventListener('click', function(event) {
var element = getElement(event);
var text = element.textContent || element.value;
text = text.replace(/\n[ \n]+\n/g, "\n").replace(/\n\n+/g, "\n\n").replace(/^\n+|\n+$/g, '');
if (!text.match("\n")) text = text.replace(/^ +| +$/, '')
copyToClipboard(text);
document.body.removeChild(overlay);
});
Minified version for use in bookmarklet:
javascript:void function(){function a(a){if(navigator.clipboard&&window.isSecureContext)return navigator.clipboard.writeText(a);else{let b=document.createElement("textarea");return b.value=a,b.style.position="fixed",b.style.left="-999999px",b.style.top="-999999px",document.body.appendChild(b),b.focus(),b.select(),new Promise((a,c)=>{document.execCommand("copy")?a():c(),b.remove()})}}function b(a){c.style.pointerEvents="none";var b=document.elementFromPoint(a.clientX,a.clientY);return c.style.pointerEvents="auto",b}var c=document.createElement("div");Object.assign(c.style,{position:"fixed",top:0,left:0,width:"100vw",height:"100vh",zIndex:99999999,background:"transparent",cursor:"crosshair"}),document.body.append(c);document.addEventListener("mousemove",function(a){var d=b(a);if(d){var e=d.getBoundingClientRect();Object.assign(c.style,{background:"rgba(0, 128, 255, 0.25)",outline:"1px solid rgba(0, 128, 255, 0.5)",top:""+e.top+"px",left:""+e.left+"px",width:""+e.width+"px",height:""+e.height+"px"})}}),c.addEventListener("click",function(d){var e=b(d),f=e.textContent||e.value;f=f.replace(/\n[ \n]+\n/g,"\n").replace(/\n\n+/g,"\n\n").replace(/^\n+|\n+$/g,""),f.match("\n")||(f=f.replace(/^ +| +$/,"")),a(f),document.body.removeChild(c)})}();

Resources