MVC Bundling and Minification: converts embedded images to to URL paths - css

In my MVC5.1 project I'm using bundling and minification with CSS rewriting transformation:
styleBundle.Include("~/Content/Site.css", new CssRewriteUrlTransform());
bundles.Add(styleBundle);
CssRewriteUrlTransform converts image paths relative to the root of the site. But, when I images embedded into css:
span.file {
background-image: url(data:image/png;base64,iVBORw0KGg+...2AAAAElFTkSuQmCC);
}
this is getting translated into
span.file {
background-image: url(http://localhost:52253/Content/data:image/png;base64,iVBORg...mCC);
}
And obviously ~/Content/data:image/png;base64... does not exist.
Any way to stop this happening, other than update CSS files to not include embedded images? Or separate into different CSS files, where with actual URL are used and URL-transform this files. And another css with only embedded images.

Scrap that question. This is a known bug. Currently work around is to separate your css into embedded images and images via url.
Vote for these work-items: https://aspnetoptimization.codeplex.com/workitem/88 and https://aspnetoptimization.codeplex.com/workitem/108

Checkout my workaround which I've 'bundled' nicely into a NuGet package. https://github.com/benmccallum/AspNetBundling
Otherwise just upgrade to grunt/gulp ;)

If you don't want to extract the embedded images to actual files and you can't wait for a new version of the Microsoft.AspNet.Web.Optimization nuget, you can use the following class.
It's a verbatim copy of CssRewriteUrlTransform except it ignores (crudely ;)) URL's with the data URI syntax.
Gist: https://gist.github.com/janv8000/fa69b2ab6886f635e3df
/// <remarks>Part of Microsoft.AspNet.Web.Optimization.1.1.3, forked to ignore data-uri</remarks>
public class CssRewriteUrlTransformIgnoringDataUri : IItemTransform
{
internal static string RebaseUrlToAbsolute(string baseUrl, string url)
{
if (string.IsNullOrWhiteSpace(url) || string.IsNullOrWhiteSpace(baseUrl) || url.StartsWith("/", StringComparison.OrdinalIgnoreCase))
return url;
if (!baseUrl.EndsWith("/", StringComparison.OrdinalIgnoreCase))
baseUrl = baseUrl + "/";
return VirtualPathUtility.ToAbsolute(baseUrl + url);
}
internal static string ConvertUrlsToAbsolute(string baseUrl, string content)
{
if (string.IsNullOrWhiteSpace(content))
{ return content; }
return new Regex("url\\(['\"]?(?<url>[^)]+?)['\"]?\\)").Replace(content, match =>
{
var format = match.Groups["url"].Value;
if (format.StartsWith("data:image", StringComparison.CurrentCultureIgnoreCase))
{
return format;
}
return "url(" + RebaseUrlToAbsolute(baseUrl, format) + ")";
});
}
public string Process(string includedVirtualPath, string input)
{
if (includedVirtualPath == null)
{
throw new ArgumentNullException("includedVirtualPath");
}
return ConvertUrlsToAbsolute(VirtualPathUtility.GetDirectory(includedVirtualPath.Substring(1)), input);
}
}

We were facing the same issue for asp.net mvc with angular project. Issue was for ag-grid base 64 image which was not showing in prod environment.
As a workaround we have removed CssRewriteUrlTransform() & changed the virtual path to match with actual physical path.
Old code
bundles.Add(new StyleBundle("~/bundles/styles").Include("~/Content/Site.css", new CssRewriteUrlTransform());
New code change
bundles.Add(new StyleBundle("~/dist/styles").Include("~/Content/Site.css");
Initially base64 image was looking for bundles folder which was not existing.
Old
background: transparent url(data:image/svg+xml;base64,PHN2ZyB3a...)
was translated to
background: transparent url(/dist/data:image/svg+xml;base64,PHN2ZyB3a...)
After making the mentioned changes base 64 image was not appended with any path.

Related

Prestashop 1.6.1.4 - Add CSS to CMS Page of Module

I am making a module that adds new tab in product edit page. The installation is Prestashop 1.6.1.4. The module adds a tab with some input fields that send data to mysql tables, but what I want to do is to style the fields a little bit, so that they look good. I am adding this in my module.php file:
public function install() {
if ($this->psversion() == 5 || $this->psversion() == 6)
{
if (parent::install() == false or !$this->registerHook('displayHeader') or !$this->registerHook('productFooter') or !$this->registerHook('displayAdminProductsExtra') or !$this->registerHook('actionProductUpdate') or !$this->registerHook('displayBackOfficeHeader'))
{
return false;
}
}
return true;
}
Then below this I put this code:
public function hookDisplayBackOfficeHeader($params) {
$this->context->controller->addCSS($this->_path.'views/css/adminsportsnutritionfadd.css');
}
But can't make the .css file appear. The file is in the right location, it has proper permissions and the owner of the file is www-data:www-data so this shouldn't be a permission issue. I have disable css combining in Prestashop as well as caching. Before reloading the page I am also deleting Prestashop's cache just in case, as well as I am deleting my brower's cache. Can somebody give me a hand in this?
Do like this:
public function hookBackOfficeHeader()
{
$this->context->controller->addCSS($this->_path.'views/css/adminsportsnutritionfadd.css');
}
For me it works like this:
$this->context->controller->addCSS($this->_path . 'views/css/back.css');
So the only difference is the css file name.
Not sure if you got this sorted or not, but...
I use this function within most of my modules to add
jQuery, Font-awesome, CSS & JS, then have it show ONLY on that module page...
public function hookDisplayBackOfficeHeader($params)
{
if(!(Tools::getValue('controller') == 'AdminModules'
&& Tools::getValue('configure') == 'MyModuleName')
){
return;
}
else
{
if ( method_exists($this->context->controller, 'addJquery') )
{
$this->context->controller->addJquery();
$this->context->controller->addCss('//maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css');
$this->context->controller->addCss($this->_path.'views/css/back.css');
$this->context->controller->addJs($this->_path.'views/js/back.js');
}
}
}

SPA from url not on root (and including a filename.aspx) routing and refresh

I have a SPA, I want to use routing for ng-view.
I have the code included in a page at domain.com/folder/dashboard.aspx
This is just a piece of that existing page, I can't move it elsewhere.
When I use route /list it alters my url to domain.com/folder/list/ which works, but breaks the ability to refresh the page (and gives a 404 since dashboard.aspx is not a default page, nor can it be)
How can I keep the url as domain.com/folder/dashboard.aspx/list?
I did try to setup my routes as dashboard.aspx/list and other various similar adjustments, but didn't have any luck.
Just like what #Claies said, it should be handled in your server config, just gonna drop my route config here in case you haven't tried this yet
var routeWithoutResolving = function (template: string, title?: string, style?: string) {
var name;
var slashIdx = template.indexOf('/');
if (slashIdx !== -1) {
name = template.substring(0, slashIdx);
template = template.substring(slashIdx + 1);
} else {
name = template;
}
var templateUrl = '/folder/' + template + '.aspx/';
return {
templateUrl: templateUrl,
title: title,
style: style,
area: _.capitalize(name),
page: template,
reloadOnSearch: false
}
}
Usage
.when('/domain.com/folder/dashboard.aspx/list', routeWithoutResolving ('folder/dashboard.aspx'))
I figured it out.
You can't use HTML5 mode, you have to be using Hashbang.
I set my routes as normal, /list and /list/item
For my links, I just used full urls, with the Dashboard.aspx#!/list/item and /list
I also removed the base tag from the html page

How to minify css in a folder ASP.net

I have CSS files in a folder and I am planning to minify them usign cassette
So far
I have created a class
public class CSSBundleHelper : IConfiguration<BundleCollection>
{
public void Configure(BundleCollection bundles)
{
var BundlePath = ConfigurationManager.AppSettings["CSSBundleFolder"];
var path = ConfigurationManager.AppSettings["CMSSitesPath"];
bundles.AddPerSubDirectory<StylesheetBundle>(path);
}
}
}
What should I pass for the bundle Collection?
List item
Since the CSS files are
in a folder , do I need to pass them using absolute path or a
relative path ?
Since the files are in a folder, i do not have an Idea how to call to this function and do the bundling . I will be happy if someone can guide me
If your css files are in one folder, just pass an application-relative path to bundles.Add(path-to-css-folder)
Then to use this bundle i.e. in Razor: add #Bundles.RenderStyleSheets()

ASP.NET MVC4 Bundling with Twitter Bootstrap

I'm trying to use the new bundling feature in MVC 4 with Twitter bootstrap and it seems to me like the paths to the glyphicons png-files int the css get's messed up in some way. Heres my code:
bundles.Add(new StyleBundle("~/bundles/publiccss").Include(
"~/Static/Css/bootstrap/bootstrap.css",
"~/Static/Css/bootstrap/bootstrap-padding-top.css",
"~/Static/Css/bootstrap/bootstrap-responsive.css",
"~/Static/Css/bootstrap/docs.css"));
bundles.Add(new ScriptBundle("~/bundles/publicjs").Include(
"~/Static/Js/jquery-1.7.2.js",
"~/Static/Js/bootstrap/bootstrap.js",
"~/Static/Js/cookie/jquery.cookie.js"));
I'm not seeing any icons on buttons and likewise. Am I doing something wrong here? Any suggestions?
The issue is most likely that the icons/images in the css files are using relative paths, so if your bundle doesn't live in the same app relative path as your unbundled css files, they become broken links.
We have rebasing urls in css on our todo list, but for now, the easist thing to do is to have your bundle path look like the css directory so the relative urls just work, i.e:
new StyleBundle("~/Static/Css/bootstrap/bundle")
Update: We have added support for this in the 1.1beta1 release, so to automatically rewrite the image urls, you can add a new ItemTransform which does this rebasing automatically.
bundles.Add(new StyleBundle("~/bundles/publiccss").Include(
"~/Static/Css/bootstrap/bootstrap.css",
"~/Static/Css/bootstrap/bootstrap-padding-top.css",
"~/Static/Css/bootstrap/bootstrap-responsive.css",
"~/Static/Css/bootstrap/docs.css", new CssRewriteUrlTransform()));
The 'CssRewriteUrlTransform' works just fine for applications that DON'T run on top of a virtual directory.
So, if your app runs on http://your-site.com/ it runs just fine, but if it runs on http://your-site.com/your-app/ you'll have 404 for all your images because the default 'CssFixRewriteUrlTransform' is referencing your images with a '/'.
To solve this issue, I have implemented my own version of 'CssRewriteUrlTransform' like this:
public class CssFixRewriteUrlTransform : IItemTransform {
private static string ConvertUrlsToAbsolute(string baseUrl, string content) {
if (string.IsNullOrWhiteSpace(content)) {
return content;
}
var regex = new Regex("url\\(['\"]?(?<url>[^)]+?)['\"]?\\)");
return regex.Replace(content, match => string.Concat("url(", RebaseUrlToAbsolute(baseUrl, match.Groups["url"].Value), ")"));
}
public string Process(string includedVirtualPath, string input) {
if (includedVirtualPath == null) {
throw new ArgumentNullException("includedVirtualPath");
}
var directory = VirtualPathUtility.GetDirectory(includedVirtualPath);
return ConvertUrlsToAbsolute(directory, input);
}
private static string RebaseUrlToAbsolute(string baseUrl, string url) {
if (string.IsNullOrWhiteSpace(url) || string.IsNullOrWhiteSpace(baseUrl) || url.StartsWith("/", StringComparison.OrdinalIgnoreCase)) {
return url;
}
if (!baseUrl.EndsWith("/", StringComparison.OrdinalIgnoreCase)) {
baseUrl = string.Concat(baseUrl, "/");
}
return VirtualPathUtility.ToAbsolute(string.Concat(baseUrl, url));
}
}
UPDATE: thanks to superjos who pointed out that there was another solution out there:
public class CssRewriteUrlTransformWrapper : IItemTransform
{
public string Process(string includedVirtualPath, string input)
{
return new CssRewriteUrlTransform().Process("~" + VirtualPathUtility.ToAbsolute(includedVirtualPath), input);
}
}
What you can do is you can go to the customize page and change #iconSpritePath and #iconWhiteSpritePath in the Sprites section and, of course, download the new style.
I've put my images in the folder Content/Images folder and I've changed the path in:
/Content/Images/glyphicons-halflings.png
/Content/Images/glyphicons-halflings-white.png
Another alternative is to download all the LESS files from github, change the same variables in the variables.less file and recompile the bootrap.less file with a tool like SimpLESS.
Fix for this now added to my AspNetBundling NuGet package which resolves a bunch of other issues in the standard transformer, particularly around using data-uris. Open-sourced on GitHub too.
Just do:
Install-Package AspNetBundling
Replace CssRewriteUrlTransform with CssRewriteUrlTransformFixed

Is it possible to load JavaScript based on theme?

I'm developing a site for a client that has 3 themes available. I'm using the app_themes system to enable the user to change the style. Each theme uses a few different JavaScript files to load custom fonts. What would be the best approach to load these JavaScript files based on the chosen themes?
As far as I can tell, Kentico uses the same app themes system as default ASP.net webforms.
Ideally I would like to be able to add the appropriate JavaScript files to the corresponding App_Theme folder and let ASP add the tags to the document head. If this isn't an option I've considered writing a ScriptLoader JavaScript that will inspect the style sheet tags to determine which theme is being used. It would be better if I could just add the theme name as a class attribute on the body element and just look at that and pull in appropriate scripts.
I think I found a solution that involves making a webPart or control if you aren't using Kentico.
public static void AddScriptToHead(HtmlHead h, string script, bool AddScriptTags)
{
Literal l = new Literal();
if (AddScriptTags)
l.Text = "<script type=\"text/javascript\" src=\""
+ script +
"\"></script>";
else
l.Text = script;
h.Controls.Add(l);
}
protected void SetupControl()
{
if (this.StopProcessing)
{
// Do nothing
}
else
{
string theme = Page.Theme;
if (theme != null)
{
if (theme.Equals("Card"))
{
AddScriptToHead(Page.Header, "~/App_Themes/Cardamon/js/cufon-colors-classic.js", true);
AddScriptToHead(Page.Header, "~/App_Themes/Cardamon/js/Charis_SIL_700.font.js", true);
}
else if (theme.Equals("CardamonWave"))
{
AddScriptToHead(Page.Header, "~/App_Themes/Cardamon/js/cufon-colors-wave.js" ,true);
AddScriptToHead(Page.Header, "~/App_Themes/Cardamon/js/Lobster_14_400.font.js",true);
}
else if (theme.Equals("CardamonAncient"))
{
AddScriptToHead(Page.Header, "~/App_Themes/Cardamon/js/cufon-colors-ancient.js", true);
AddScriptToHead(Page.Header, "~/App_Themes/Cardamon/js/Charis_SIL_700.font.js", true);
}
else
{
//Y U no theme?
}
}
}
}
I'd like to extend this to accept Scripts and themes as properties in the future but this will work for now.

Resources