GET URL parameter from code in DNN 7.2 - url-routing

I want to get Full URL including URL Parameter in my module code.
For example
From This URL
http://Domain/Search-Space-For-Rent/Houston
TabController.CurrentPage.FullUrl
Gives me
//Domain/Search-Space-For-Rent
only I need to get last parameter from URL (Houston)
I also tried
Globals.NavigateURL(this.TabId, this.Request.QueryString["ctl"], UrlUtils.GetQSParamsForNavigateURL());
How can I get that?

So I regenerated URL using all query string parameters.
string path = TabController.CurrentPage.FullUrl;
foreach (string key in Request.QueryString.AllKeys)
{
if (key != "TabId" && key != "language" && key != "_escaped_fragment_")
{
if (key != null)
{
path += "/" + key + "/" + Request.QueryString[key];
}
else
{
path += "/" + Request.QueryString[key];
}
}
}

Typically within DNN you would simply get from the QueryString ex:
var myParam = Request.Querystring["paramName"];
What parameter name are you using when you build that URL? I would assume you've got a custom URL provider that changing something like "&city=Houston" to be /Houston instead. If that is the case, just grab the querystring paramter called City.
Update:
To get the "Name" of the page, assuming the scenario where Houston is a page in DNN, you could do the following.
var tc = new TabController();
var ti = tc.GetTab(TabId);
var pageName = ti.TabName
TabId comes from DNN, assuming your module inherits from PortalModuleBase you should have access to it. With that, you can then get the TabInfo from the TabController, and access the properties off that TabInfo object.

Related

AngularJS Directive to modify URL

In my templates i am able to display an image from my data using
ng-style="{'background-image':'url({{f.flower.imageURL}})'}"
The imageURL always returns a hi-res image with URL such as
https://s3.amazonaws.com/images/FlowerImages/Rose_1920.jpg
However the endpoint also has smaller images such as
https://s3.amazonaws.com/images/FlowerImages/Rose_320.jpg
https://s3.amazonaws.com/images/FlowerImages/Rose_480.jpg
https://s3.amazonaws.com/images/FlowerImages/Rose_1024.jpg
How would i create a directive to traverse back through the URL up to the underscore and pass in a size i want (depending on the view) to update between the underscore and the .jpg?
Based on you example, I don't think you need a directive. Just add a function to your controller.
Instead of
ng-style="{'background-image':'url({{f.flower.imageURL}})'}"
do
ng-style="{'background-image':'url({{generateImageUrl(f.flower.imageURL, 320)}})'}"
And your controller would have standard javascript to manipulate the url:
function generateImageUrl(url, size) {
var n = url.lastIndexOf("_");
var beforeUnderscore = url.substring(0, n);
var afterUnderscore = url.substring(n+1);
var suffix = afterUnderscore.split('.')[1];
return beforeUnderscore + "_" + size + "." + suffix;
}
The same function could work for image as well
<img ng-src="{{generateImageUrl(f.flower.imageURL, 320)}}">
Note: ng-src is used instead of src to prevent the browser from requested the url before angular has bootstrapped.

Inserting image into visualforce email template (without hard-coding IDs)

The "official" solution for including images in visualforce email templates suggests hard coding IDs in your template to reference an image file stored as a document.
https://help.salesforce.com/HTViewHelpDoc?id=email_template_images.htm&language=en_US
Is there a better way that avoids hard coding instance ID and OID? I tried using the partner URL to grab the instance ID, but I got the following error
Error Error: The reference to entity "oid" must end with the ';' delimiter.
Using:
{!LEFT($Api.Partner_Server_URL_140,FIND(".com/",$Api.Partner_Server_URL_140)+3)/
to replace "https://na2.salesforce.com/"
in
"na2.salesforce.com/servlet/servlet.ImageServer?id=01540000000RVOe&oid=00Dxxxxxxxxx&lastMod=1233217920"
Should I use a static resource instead?
I've arrived here looking for an answer for this question related to hardcoded ID and OID in Visualforce e-mail templates. Well, I found a workaround for that.
First I needed to create a Visualforce Component:
<apex:component access="global" controller="LogomarcaController">
<apex:image url="{!LogoUrl}" />
</apex:component>
In the respective controller class, I've created a SFInstance property to get the correct URL Salesforce Instance, LogoUrl property to concatenate SFInstance and IDs... And Finally I've used Custom Settings (Config_Gerais__c.getInstance().ID_Documento_Logomarca__c) to configurate the ID of Image (in my case, Document Object) on Sandbox or Production:
public class LogomarcaController {
public String LogoUrl {
get {
id orgId = UserInfo.getOrganizationId();
String idDocumentoLogomarca = Config_Gerais__c.getInstance().ID_Documento_Logomarca__c;
return this.SfInstance + '/servlet/servlet.ImageServer?id=' + idDocumentoLogomarca + '&oid=' + orgId ;
}
}
public String SfInstance
{
get{
string SFInstance = URL.getSalesforceBaseUrl().toExternalForm();
list<string> Dividido = SFInstance.split('.visual', 0);//retira o restante a partir de .visual
SFInstance = dividido[0];
dividido = SFInstance.split('://',0);//retira o https://
SFInstance = dividido[1];
if(!SFInstance.contains('sybf')) //managed package prefix, if you need
{
SFInstance = 'sybf.'+ SFInstance;
}
return 'https://'+SFInstance;
}
}
}
And finally, I've added the component in Visualforce template:
<messaging:emailTemplate subject="Novo OfĂ­cio - {!relatedTo.name}" recipientType="User" relatedToType="Oficio__c" >
<messaging:htmlEmailBody >
<c:Logomarca />
</messaging:htmlEmailBody>
<messaging:plainTextEmailBody >
</messaging:plainTextEmailBody>
</messaging:emailTemplate>
PS: Some of my variables, properties and comments are in my native language (portuguese). If you have some problems understanding them, please ask me!
We ran into a similar problem and after trying various solutions, the following worked for us. In our case the image is uploaded as a content asset(https://help.salesforce.com/articleView?id=000320130&type=1&language=en_US&mode=1)
Solution:
<img src="{!LEFT($Api.Partner_Server_URL_260,FIND('/services',$Api.Partner_Server_URL_260))}/file-asset-public/<Image_Name_Here>?oid={!$Organization.Id}&height=50&width=50"/>

Angularjs appended $resource paramDefaults with special charaters

I have the following code
var resource = $resource('https://api.mongolab.com/api/1/databases/' + DB_NAME + '/collections/' + collectionName + '/:id',
{ apiKey:API_KEY, id:'#_id.$oid'},{update:{ method:'PUT' } }
);
when i call
$scope.projects = Project.query({q:"+"});
referencing
Each key value in the parameter object is first bound to url template if present and then any excess keys are appended to the url search query after the ?.
I append the Get request with the string in the {}. I cannot however include special charaters. Is this a feature and how can I implement special characters?
I believe you should urlencode values as long as you are sending them in url query

Using query strings in backbone (1.0.0)

i have a situation here that i can't seem to figure out. Please if anybody knows how to resolve this i would love to hear suggestions.Thanks
I have a "global view" that is visible on a subnavbar in the app, that is a calendar, this calendar serves as a global calendar throughout the application, so almost all the views use the calendar view & model to set show data according to the date selected.
This calendar view/model should have some way to store in history each time the date is changed, this (i think) is done using a single URL or query string parameters each time the date is changed, something like
webapp/view1?date=20120301
and when the date is changed, so its the query string.
I would like to use query string parameters for this so i don't have to specify on each route the (/:date) optional parameter.
THE THING IS backbone stopped firing a route change or a history event when query strings are changed, they simply ignore query strings on the Backbone.History implementation, this is breaking all my implementation cause i can't track each time the querystring is changed, so the "back" button will not fire a change event and therefore i can't change the date on the model that would change the date on the calendar.
I know a simple solution to this would be just using "pretty URL" and adding that date parameter to each view, but im trying to avoid that.
Any suggestions?
Thanks in advance
UPDATE
I ended up using "pretty URLs" like the Backbone documentation suggests, cause using query strings would bring me a lot of trouble for tracking the URL change and history, also wouldn't work as expected when using hashchange instead of pushState.
So, my code ended up like this:
Attaching somewhere in your router, view, controller, something, to the "route" event of your router, to check the URI for the date and set this date to the calendar picker:
this.listenTo(myRouter, "route", this.routeChanged);
Then, this method would do something like:
checkURIdateParameter: function (route, arr) {
var found = false;
for (var i = 0; i < arr.length ; i++) {
if (arr && arr[i] && arr[i].indexOf("date=") != -1) {
if (app.models.dateControl) {
var dateFromParameter = new Date(arr[i].substring("date=".length).replace(/\$/g, ":"));
dateFromParameter = (isNaN(dateFromParameter.getTime())) ? app.models.dateControl.defaults.date : dateFromParameter;
app.models.dateControl.set("date", dateFromParameter);
found = true;
}
}
}
if (!found) app.models.dateControl.set("date", app.models.dateControl.defaults.date, {changeURI:false});
}
This serves as the function that will read params from the URI and reflect those changes on the dateControl.
There should be another method that will be the one in charge of updating the URI to a new one each time the date is changed (so that the params are in sync with the view) and the link can be copied and pasted with no problems.
Somewhere on your router, view, controller:
this.listenTo(app.models.dateControl, "change:date", this.updateURIdateParameter);
This is a method that is attached to a model that has the current date, this model is updated by the calendar picker (the UI control) or the method that was linked with the route event (routeChanged, look above).
This method should do something like this:
, updateURIdateParameter: function (a, b, c) {
if (c && c.changeURI == false) return; //this is in case i don't want to refresh the URI case the default date is set.
var currentFragment = Backbone.history.fragment;
var newFragment = "";
var dateEncoded = app.models.dateControl.get("date").toJSON().replace(/\:/g, "$");
newFragment = currentFragment.replace(/\/date=([^/]+)/, "") + "/date=" + dateEncoded;
if (newFragment != currentFragment) {
app.router.navigate(newFragment, false);
}
}
This method gets the currentDate selected from the corresponding model, parses it, then takes the URL from the Backbone.history.fragment, execs a nice regexp against it that will replace the old date parameter (if exists) and then appends the new encoded date.
Then navigates to this route in silent mode so that the method that checks the route is not called (this prevents annoying loops).
I hope this helps.
I would suggest using "Pretty URL".
FYI Page URL in the browser bar will blink in this example.
Somewhere inside your Backbone.Router:
this.route('*action', function() {
console.log('404');
});
this.route(/^(.*?)\?date=(\d+)$/, function(route, date) {
// same current route (with ?date)
var fragment = Backbone.history.fragment;
// navigate to main route (to create views etc.)
this.navigate(route, {trigger:true, replace:true});
// silent change hash
this.navigate(fragment);
});
this.route('any', function() {
// need wait for hash change
_.defer(function() {
console.log('parse date here and do what you want', window.location.hash.match(/^(.*?)\?date=(\d+)$/));
});
});
this.route('route', function() {
// need wait for hash change
_.defer(function() {
console.log('parse date here and do what you want', window.location.hash.match(/^(.*?)\?date=(\d+)$/));
});
});

Ideas on how to implement CMS for language specific page

I'm building a web shop and I'm implementing language selection as well as a CMS. I also have to provide an administrator of the site with the means to be able to edit a page through the CMS.
Therein doesn't lay the problem.
The problem is how I should build up my tables for these pages. I've made my database design but didn't think the web pages part through.
I already have the following table structure for the info that is equal throughout all languages for a page (called Webpages) and for language or culture specific info (called Webpages_local).
Which attributes could I add or remove so that I can easily and dynamically perform the CRUD actions?
I'm using MVC4 with razor syntax with the following url structure:
url: "{language}/{controller}/{action}/{id}"
My main concern is now that I'm not sure on how to show the language specific content of a page when a visitor presses, for example, the link to the About page.
Maybe use the controller part of the url and save it as a key in my Webpages table and filter on that as well as the selected language?
So when a visitor goes to http://example.com/nl/About, I in my AboutController I retrieve "nl" and "about", of course filter them first and then with a query to the database select the correct nl content?
How should I go about this technically?
I would use OnActionExecuting to handle the retrieve lang process, something like:
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
#region set Language
var lang = string.Empty;
if (filterContext.RouteData.Values["lang"] != null && !string.IsNullOrWhiteSpace(filterContext.RouteData.Values["lang"].ToString()))
{
// set the culture from the route data (url {lang})
lang = filterContext.RouteData.Values["lang"].ToString();
switch (lang)
{
case "es":
break;
case "en":
break;
default:
lang = "es";//default language
filterContext.RouteData.Values["lang"] = lang;
filterContext.HttpContext.Response.Redirect("/");
break;
}
}
else
{
//set default language
lang = "es";
filterContext.RouteData.Values["lang"] = lang;
}
Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(lang);
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(lang);
#endregion
base.OnActionExecuting(filterContext);
}
Then anywhere in your code you just read the Thread.CurrentThread.CurrentCulture (this will be your global lang indicator) to show the correct language.
UPDATE - know I understand your point =)
If the pages will be dynamically created then you wont have an ActionResult per page, you need just one ActionResult like:
public ActionResult ShowPage(int id,string slug)
{
//Use the slug to check for url attacks and ensure 301 redirections to the correct url
var page = db.Webpages_local.First(p=> p.id == id
&& p.culture.name == Thread.CurrentThread.CurrentCulture);
return View(page);
}
For SEO reasons i would suggest you define a route like:
routes.MapRoute(
name: "LocalizedPages",
url: "{lang}/p/{slug}/{id}",
defaults: new { controller = "Page", action = "Show", id = UrlParameter.Optional },
constraints: new { lang = #"(es|en|fr|nl)" }
);
That give you urls like:
/nl/p/about/1 //the p is just an identifier for 'page', to differentiate this routes from others
I would add a column called language or similar to your table instead of having multiple tables.
Then your controller can fetch the right page after finding the requested language key in your menu table and then it can read the content in your webpages table.

Resources