I have a website developed using ASP.Net MVC. Now I want to based on the request(based on the country) I want to change the web site theme.
Ex: for USA - theme 1
for Canada - theme 2
If the request is not matching to any theme I want to display default (my current theme).
How can I achieve this dynamically.
Do I need to rewrite my css again or Is there a better way to this?
Please share your ideas
Thanks in Advance :)
You should define a global css file for common styles. Assuming you have some kind of helper method for accessing the current country, you can conditionally load the country specific stylesheet, or load a stylesheet based on a rule e.g. stylesheet with the same name as the country (following code is untested):
<link rel="stylesheet" type="text/css" href="css/global.css">
// conditional
#if (SiteHelper.CurrentCountry == "USA") {
<link rel="stylesheet" type="text/css" href="css/usa.css">
}
// or assume a css file exists with the country name
<link rel="stylesheet" type="text/css" href="css/#(SiteHelper.CurrentCountry).css">
I would generally recommend using a different layout page for each country/theme as it gives you much more control. Essentially you would move the above logic into _ViewStart.cshtml and set the Layout based on the current country.
Not sure if this is the best approach but this is what I am doing. I have a folder structure similar to this:
/Content
layout.css
/Content/Images
/Content/Themes/ThemeUSA
layout.css
/Content/Themes/ThemeUSA/Images
Then I use Helper Extensions to return the correct path for example for an image:
<img src="#Url.Image(Model.EnhImg)" alt="#Model.EnhImgAlt" />
where
public static string Image(this UrlHelper helper, string fileName)
{
string sLocation = Content() + "images/" + fileName;
return helper.Content(sLocation);
}
private static string Content()
{
string sLocation = "~/content/";
string sTheme = (string)HttpContext.Current.Session["Theme"];
if (!String.IsNullOrEmpty(sTheme))
{
sLocation += "themes/" +sTheme + "/";
}
return sLocation;
}
Images in the theme folders have the same name as in the default folder. Same thing for stylesheets.
Related
Is possible to change between 2 CSS files?
For example: I have the default Bootstrap theme, but I want to make a dropdown list with a list of themes, so the user can select the theme that he wants. Searching I find that you can have something like that:
<link type="text/css" rel="stylesheet" href="../Content/bootstrap.min.css" title="default"/>
<link type="text/css" rel="alternate stylesheet" href="../Content/bootstrap.min.cosmo.css" title="cosmos"/>
And you can change with a JavaScript function:
<script>
function setActiveStyleSheet(title) {
var i, a, main;
for (i = 0; (a = document.getElementsByTagName("link")[i]) ; i++) {
alert(a.href);
if(a.getAttribute("rel").indexOf("style") != -1
&& a.getAttribute("title")) {
a.disabled = true;
if(a.getAttribute("title") == title) a.disabled = false;
}
}
}
</script>
But when I click a button, I think that the page refresh and returns to the default theme.
Is there any way to permanently change the theme?
Yes you can! You must get the url of the css file and add it to the BundleConfig and refresh the page. If you need some reference to workout with it take a look of this link
You need to persist which is the active stylesheet on client side. Probably via cookies.
I was hoping anyone could give some input on this,
I'm creating a meteor app in which I would like to use bootstrap to creating the admin environment, but have the visitor facing side using custom css. When I add the bootstrap package to my app using meteor it's available on every page, is there a way to restrict the loading of bootstrap to routes that are in '/admin' ?
When you add bootstrap package it's not possible. You can, however, add bootstrap csses to public directory and then load them in a header subtemplate that will only be rendered when you're in the dashboard.
EDIT
But then how would you go about creating seperate head templates?
Easy:
<head>
...
{{> adminHeader}}
...
</head>
<template name="adminHeader">
{{#if adminPage}}
... // Put links to bootstrap here
{{/if}}
</template>
Template.adminHeader.adminPage = function() {
return Session.get('adminPage');
}
Meteor.router.add({
'/admin': function() {
Session.set('adminPage', true);
...
}
});
DISCLAIMER: I am unsure of a 'meteor way' to do this, so here is how I would do it with plain JS.
jQuery
$("link[href='bootstrap.css']").remove();
JS - Credit to javascriptkit
function removejscssfile(filename, filetype){
var targetelement=(filetype=="js")? "script" : (filetype=="css")? "link" : "none" //determine element type to create nodelist from
var targetattr=(filetype=="js")? "src" : (filetype=="css")? "href" : "none" //determine corresponding attribute to test for
var allsuspects=document.getElementsByTagName(targetelement)
for (var i=allsuspects.length; i>=0; i--){ //search backwards within nodelist for matching elements to remove
if (allsuspects[i] && allsuspects[i].getAttribute(targetattr)!=null && allsuspects[i].getAttribute(targetattr).indexOf(filename)!=-1)
allsuspects[i].parentNode.removeChild(allsuspects[i]) //remove element by calling parentNode.removeChild()
}
}
removejscssfile("bootstrap.css", "css")
However, doing that would complete remove it from the page. I am not sure whether meteor would then try to readd it when a user goes to another page. If that does not automatically get readded, then you have an issue of bootstrap not being included when someone goes from the admin section to the main site, which would break the look of the site.
The way I would get around that would be to disable and enable the stylesheets:
Meteor.autorun(function(){
if(Session.get('nobootstrap')){
$("link[href='bootstrap.css']").disabled = true;
}else{
$("link[href='bootstrap.css']").disabled = false;
}
});
There my be other bootstrap resources which may need to be removed, take a look at what your page is loading.
To use jQuery in the same way but for the javascript files, remember to change link to script and href to src
From my tests, Meteor does not automatically re-add the files once they have been removed so you would need to find some way of re-adding them dynamically if you want the same user to be able to go back and forth between the main site and the admin site. Or simply if the http referrer to the main site is from the admin, force reload the page and then the bootstrap resources will load and everything will look pretty.
P.s. make sure you get the href correct for the jQuery version
If somebody is interested in including any js/css files, I've written a helper for it:
if (Meteor.isClient) {
// dynamic js / css include helper from public folder
Handlebars.registerHelper("INCLUDE_FILES", function(files) {
if (files != undefined) {
var array = files.split(',');
array.forEach(function(entity){
var regex = /(?:\.([^.]+))?$/;
var extension = regex.exec(entity)[1];
if(extension == "js"){
$('head').append('<script src="' + entity + '" data-dynamicJsCss type="text/javascript" ></script>');
} else if (extension == "css"){
$('head').append('<link href="' + entity + '" data-dynamicJsCss type="text/css" rel="stylesheet" />');
};
});
}
});
Router.onStop(function(){
$("[data-dynamicJsCss]").remove();
});
}
Then simply use:
{{INCLUDE_FILES '/css/html5reset.css, /js/test.js'}}
in any of your loaded templates :)
EPiServer only:
Our clients are trying to add custom attributes to a div-tag in the TinyMCE editor - they switch to HTML mode, makes the changes and save the page. Then the attributes are removed. Washing HTML like this is standard behaviour of TinyMCE, and it is possible to configure it to allow custom tag attributes.
My question is how do I configure TinyMCE in EPiServer to allow custom HTML attributes? I don't see where I would be able to hook into the inititialization of TinyMCE. And adding div to the list of "safe" tags in episerver.config doesn't see to work either (see uiSafeHtmlTags).
Example:
<div class="fb-like" data-href="http://oursite" data-send="false"></div>
Becomes just
<div class="fb-like"></div>
From the TinyMCE documentation, on how to add custom attributes to tags: http://www.tinymce.com/wiki.php/Configuration:extended_valid_elements
I have this class
using EPiServer.Editor.TinyMCE;
namespace SomeNamespace
{
[TinyMCEPluginNonVisual(
AlwaysEnabled = true,
EditorInitConfigurationOptions = "{ extended_valid_elements: 'iframe[src|frameborder=0|alt|title|width|height|align|name]' }")]
public class ExtendedValidElements { }
}
and this in episerver.config:
<episerver>
....
<tinyMCE mergedConfigurationProperties="valid_elements, extended_valid_elements, invalid_elements, valid_child_elements" />
</episerver>
in a recent project. It should work the same if you change the iframe part to div[data-href|data-send].
You have 2 options:
First
[TinyMCEPluginNonVisual(EditorInitConfigurationOptions = "{ extended_valid_elements: 'div[title|data-test]' }")]
will allow title and data-test in div tag.
div[*] will allow all attribute in div tag.
Second
make your TinyMCE plugin inherits from IDynamicConfigurationOptions
implement function like this:
public IDictionary<string, object> GetConfigurationOptions(){
var customSettings = new Dictionary<string, object>();
customSettings.Add("extended_valid_elements", "div[*]");
return customSettings;
}
No need to configure anything in .config file (with EPiServer's default value, they are all fine).
Here are some helpful links to this question
http://www.kloojed.com/2010/05/customize-the-tiny-mce-editor-options-in-episerver-cms-6
http://krompaco.nu/2010/05/alter-default-initoptions-for-tinymce-in-episerver-6/
http://world.episerver.com/Modules/Forum/Pages/thread.aspx?id=45795
The following worked for me:
[TinyMCEPluginNonVisual(AlwaysEnabled = true, EditorInitConfigurationOptions = "{ extended_valid_elements: 'div[*]' }", PlugInName = "ExtendedValidElements", ServerSideOnly = true)]
public class TinyMceExtendedValidElements
{
}
No changes in config.
I have an app setup that runs on a server where the url is rewritten to the app. it goes servername.com/myapp
I routed the app as follows:
routes.MapRoute(
"Default", // Route name
"myapp/{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
So that it will always begin with "myapp" otherwise the server will redirect the url. Now the content can't be found. I've tried putting the urls in manually but it doesn't work.
Here's what my view looks like:
<link href="#Url.Content("~/Content/themes/Site.css")" rel="stylesheet" type="text/css" />
Nothing strange about this so I don't see why it shouldn't work. Perhaps the server is rewriting the urls for content as well, so is there any way to set Url.Content() to map accordingly?
I recently had the same problem. Here is what I used to solve it, although someone may find a somewhat easier way.
On the development webserver, it used the server's root which resolved as "/" and it resolved to "/appname" on the deployment webserver. I could hardcode to link to one, but it obviously failed for the other. The answer is to create strings that find it programmatically.
#{
string rootpath = HttpContext.Current.Request.ApplicationPath;
if(rootpath != "/") { rootpath = rootpath + "/"; }// add closing slash if missing
string contentpath = rootpath + "Content/themes/Site.css";
}
<link href="#contentpath" rel="stylesheet" type="text/css" />
I put the rootpath code into a static function in a separate class since I used it on every page with links or images.
I'm developing a web part which needs some custom CSS files. So I'm using the CssRegistration class to add them to the page header.
The code registers 4 CSS files which got deployed to the layouts folder by the web part feature. A fifth CSS files is optionally registered when there's a path to it set in the web part's property AdditionalCss. The CSS files should be inserted in the header after all SharePoint CSS files and should be sorted in the order they were added by code.
The code I used is the following:
var contentCss = new CssRegistration
{ Name = "/_layouts/MyWebPart/css/content.css",
RevealToNonIE = true };
if (SPContext.Current.Web.UIVersion == 4)
contentCss.After = "corev4.css";
else
contentCss.After = "core.css";
Controls.Add(contentCss);
var customCss = new CssRegistration
{ Name = "/_layouts/MyWebPart/css/cn_custom.css",
After = contentCss.Name, RevealToNonIE = true };
Controls.Add(customCss);
var styleCss = new CssRegistration
{ Name = "/_layouts/MyWebPart/css/styles.css",
After = customCss.Name, RevealToNonIE = true };
Controls.Add(styleCss);
var colorsCss = new CssRegistration
{ Name = "/_layouts/MyWebPart/css/colors.css",
After = styleCss.Name, RevealToNonIE = true};
Controls.Add(colorsCss);
if (!string.IsNullOrEmpty(AdditionalCss))
{
var webPartCustomCss = new CssRegistration
{ Name = AdditionalCss,
After = colorsCss.Name,
RevealToNonIE = true };
Controls.Add(webPartCustomCss);
}
When I add the web part to a page all CSS files are added to the page as expected. Except the files are sorted in the wrong order.
Without the custom CSS file the order is: (link's rel- and type-attribute were removed for a better overview)
...
<link href="/_layouts/1033/styles/Themable/corev4.css"/>
<link href="/_layouts/MyWebPart/css/colors.css"/>
<link href="/_layouts/MyWebPart/css/content.css"/>
<link href="/_layouts/MyWebPart/css/cn_custom.css"/>
<link href="/_layouts/MyWebPart/css/styles.css"/>
With the custom CSS file the order is:
...
<link href="/_layouts/1033/styles/Themable/corev4.css"/>
<link href="/_layouts/MyWebPart/css/cn_custom.css"/>
<link href="/sites/mysite/Style%2520Library/de-de/test.css"/>
<link href="/_layouts/MyWebPart/css/styles.css"/>
<link href="/_layouts/MyWebPart/css/content.css"/>
<link href="/_layouts/MyWebPart/css/colors.css"/>
As you can see both cases provide a totally different order and the CSS files were never sorted in the order they were added by code.
With this strange behavior the whole CssRegistration class is not very useful as you cannot
relay that the CSS files are always in the same order. This makes designing with CSS nearly impossible.
Have you looked at the "After" property of the CssRegistration control? I think that if you don't specify an order using this property then the results are in alphabetical order in your source. This doesn't exactly match what you see but there may be something else going on that is causing your inconsistent behavior.
http://www.wictorwilen.se/Post/What-is-new-with-the-CssRegistration-control-in-SharePoint-2010.aspx