Change values in <head> of HTML in Angular Dart - dart

so I am relatively new Angular Dart and Dart in general, and I am trying to create a simple webapp.
When I used to do PHP development I always had a config file that determined what environment the app was running on and decided to setup itself in different ways.
I am trying to figure how to achieve something similar in Angular Dart. Specifically as an example for the beginning I want to set different base href based on the URL that is loading the app. When you read the documentation it says that during development you should set the base href like this:
<script>
// WARNING: DO NOT set the <base href> like this in production!
// Details: https://webdev.dartlang.org/angular/guide/router
(function () {
var m = document.location.pathname.match(/^(\/[-\w]+)+\/web($|\/)/);
document.write('<base href="' + (m ? m[0] : '/') + '" />');
}());
</script>
But for distribution it should be set like this:
<base href="/">
All of this needs to be located in the <head> section of the HTML page so I would like to do some sort of an if statement here. Example how I wold do it in PHP:
<head>
<?php if(DEV) { ?>
// Do the development base href
<?php } else if(PROD) { ?>
// Do the production base href
<?php }?>
</head>
So my question basically is, is something like this possible in Angular Dart at the moment ?

You can't do binding in <head> with Angular.
I think there is still a way to pass "environment" variables to the app using -D=PROD=...
and then you could use const isProd = bool.fromEnvironment('PROD') (see also https://github.com/dart-lang/site-www/issues/404)
and then use dart:html to manipulate the DOM.
I haven't used this in web for a while and I'm not sure it's still supported in Dart 2.
(Update found https://github.com/dart-lang/build/issues/1053)
If '<base href="..."> is only for Angular routing, then it's better to use
import 'package:angular_router/angular_router.dart';
and adding
ValueProvider<String>.forToken(appBaseHref, '/'),
to Angular providers.
I'm also using a build script that copies files like
cp web/run_config_prod.dart web/run_config.dart
webdev build ...
cp web/run_config_dev/run_config.dart
to have some settings changed depending on the target environment.

Related

Need some help setting up Typescript and Highcharts

I am quite New to typescript and I have tried to set up a typescript Project in Visual studio 2015 as HTML Application With Typescript. My problem is how to import or Reference highcharts without errors. I need a short description on how to set up the easist highchart in my typescript file. The description should explain from the start
1) creating the Project, and adding highchart (npm, tsd...) to the Project,
2) setting up the index.html file and app.ts (or the name of Your typescript file),
3) adding References in the html file and app.ts, especially in app.ts where you set import or References, like using import statement or
< reference path="typings/tsd.d.ts" />
< reference path="typings/highcharts/highcharts.d.ts" />
4) Set require statements and put into a variable
(I can't get this code to work ... Please use Your way to do this
var Highcharts = require('highcharts');
// Load module after Highcharts is loaded
require('highcharts/modules/exporting')(Highcharts);
// Create the chart
Highcharts.chart('container', { /*Highcharts options*/ });
5) Finally you render the highchart either in app.ts or by using the id in the index.html file
<div id="container" style="width:100%; height:400px;"></div>
I hope somebody can help me out here. I could of course have done all this in index.html but I want to make use of the debugging possibilities in typescript.

Dropwizard Assets not serving static content outside of root path

Here's my Dropwizard (0.8.5) app's basic project structure:
myapp/
src/main/groovy/
org/example/myapp/
MyApp.groovy
<lots of other packages/classes>
controllers/
site/
SiteController.groovy
dashboard/
DashboardController.groovy
org/example/myapp/views
site/
SiteView.groovy
dashboard/
DashboardView.groovy
src/main/resources/
assets/
images/
mylogo.png
org/example/myapp/views/
site/
header.ftl
index.ftl
dashboard/
dashboard.ftl
Where the gist of each of those classes is:
class MyApp extends Application<MyAppConfiguration> {
#Override
void initialize(Bootstrap<MyAppConfiguration> bootstrap) {
bootstrap.addBundle(new AssetsBundle('/assets/images', '/images', null, 'images'))
bootstrap.addBundle(new ViewBundle())
}
// etc...
}
#Path('/')
#Produces('text/html')
class SiteController {
#GET
SiteView homepage() {
new SiteView()
}
}
#Path('/app/dashboard')
#Produces('text/html')
class DashboardController {
#GET
DashboardView dashboard() {
new DashboardView()
}
}
header.ftl (dropwizard-views-freemarker)
=========================================
<!DOCTYPE html>
<html>
<head> <!-- lots of stuff omitted here for brevity --> </head>
<body>
<div class="well">
<img src="images/mylogo.png" />
<br/>This is the header!
</div>
index.ftl
=========
<#include "header.ftl">
<p>
Homepage!
</p>
</body>
</html>
dashboard.ftl
=============
<#include "../site/header.ftl">
<p>
Dashboard!
</p>
</body>
</html>
So you can see I'm using DW as an actual web app/UI, and that I'm utilizing both Dropwizard Views (Freemarker binding) as well as Dropwizard Assets.
When I run this, the app starts up just fine and I am able to visit both my homepage (served from / which maps to index.ftl) as well as my dashboard page (served from /app/dashboard which maps to dashboard.ftl).
The problem is that both pages use the header.ftl, which pulls in my assets/images/mylogo.png, but only my homepage actually renders the logo. On my dashboard page, I do see the "This is the header!" message, so I know the header is being resolved and included with my dashboard template. But, I get a failed-to-load-image "X" icon, and when I open my browser's dev tools I see that I'm getting HTTP 404s on the image.
So it seems that DW is unable to find my image asset from a view/URL not directly living under root (/).
On the Dropwizard Assets page (link provided above) there's a peculiar warning:
Either your application or your static assets can be served from the root path, but not both. The latter is useful when using Dropwizard to back a Javascript application. To enable it, move your application to a sub-URL.
I don't entirely understand what this means, but suspect it is the main culprit here. Either way, anyone see where I'm going awry, and what I can do (exact steps!) to fix this?
You need to add / before your URI:
<img src="/images/mylogo.png" />
this can be explained from the examples in RFC 3986 URI Generic Syntax, I pulled out the relevant examples.
5.4. Reference Resolution Examples
Within a representation with a well defined base URI of
http://a/b/c/d;p?q
a relative reference is transformed to its target URI as follows.
5.4.1. Normal Examples
"g" = "http://a/b/c/g"
"g/" = "http://a/b/c/g/"
"/g" = "http://a/g"
"../g" = "http://a/b/g"
"../../g" = "http://a/g"
Putting in the preceding / makes the URI begin from the domain name regardless of the referring URI, which allows you to do precisely what you want.
Load both pages up (the one that works, and the one that doesn't), and use Firebug or Chrome dev tools to inspect the logo element. What path is it trying to get to? I suspect on your index page it's going to http://some.thing/images/mylogo.png whereas on your dashboard it's trying to load http://some.thing/app/dashboard/images/mylogo.png
Try putting an additional / in front of the path in your template, and it should resolve from anywhere.
(Originally answered here: Dropwizard-user Google Group)

Can the document.location.protocol value be changed in a WinRT webview?

I'm currently having an issue with the WebView control used in a Universal WinRT app (Windows 8.1/Windows Phone 8.1).
I currently load the following piece of JavaScript into the WebView using the NatigateToString method:
<html>
<head>
<base href='MY_BASE_URL'>
</head>
<body>
<script>
var idcomments_acct = 'MY_ACC_ID';
var idcomments_post_id='POST_ID';
var idcomments_post_url='POST_URL';
</script>
<span id='IDCommentsPostTitle' style='display:none'></span>
<script type='text/javascript' src='http://www.intensedebate.com/js/genericCommentWrapperV2.js'></script>
</body>
</html>
This is the piece of code for the IntenseDebate generic install that can be found here.
The issue is with this line of code in the referenced IntenseDebate code:
load_js(document.location.protocol+"//connect.facebook.net/en_US/all.js")
This piece of code fails because document.location.protocol is set to about: in the WebView, leading to a 404 error on this call.
On the Android/iOS webviews simply setting the base URI to a http: or https: based address using their loadDataWithBaseUrl methods worked fine, but the WinRT WebView is missing a similar method. And setting the Base url in the HTML itself (like shown in the piece of code above) does work for resolving image url's and sortlike, but this method doens't change the document.location values.
Since I can't modify the referenced JS file and putting the above piece of HTML on a server isn't an option in this apps usecase, is there any way you can force the document.location.protocol to be a certain value in the WinRT webview? Or is there any other way to get this bit of HTML to work in a webview?
There isn't a direct way to do this. WebView doesn't provide any interface to override the document.location . If branching off of the protocol is a common pattern then this may be a good feature to request on http://wpdev.uservoice.com .
I'm not familiar enough with HTML/JavaScript best practices to say for sure, but most of the references I find searching for document.location.protocol warn against assuming that the protocol will always be http: or https. This may be something that IntenseDebate should fix.
That said, you may be able to get past this by injecting code into your page which finds the problem location in the DOM and changing it live. You can't change just the protocol, but you may be able to find where it is referenced and change that there. I assume it gets loaded into the commentScript.src from genericCommentWrapper2.php referenced in genericCommentWrapper2.cs and then added to the document's head.

Link rel='import' breaks Router

I'm experimenting with dart-polymer apps and have run into a few issues.
Is there a way to inject template declaration of a custom element through code? The docs currently specify the following method:
<link rel="import" href="my_element.html">
I'm trying to use the Route package (specifically 'package:route/client.dart'), and importing an html module via this method seems to break the router, so:
main() {
var router = new Router()
..addHandler(homeUrl, showHome)
..addHandler(signinUrl, showSignin)
..listen();
}
fails to execute the handlers when I navigate to the Url specified. If I remove the html import, the Router works fine.
Any way around this?

Autoversioning CSS/JS in ASP.NET MVC?

So I was reading this stackoverflow post about "autoversioning" in ASP.NET MVC for CSS/JS files and was wondering what the "best" strategy is to do this.
The solution provided inserts an assembly number - which means everytime you publish - it will change EVERY SINGLE file which is not ideal because if you make modifications to just 1 *.css or *.js then it will change each and every file.
1) How can it be done just for "single files" instead of using site wide assembly using modification date or something on IIS7 ?
2) Also if I have some sort of "static" asset like - http://static.domain.com/js/123.js - how can I use rewrite to send the latest file for a request if someone has integrated this static link onto their site ?
i.e. http://static.domain.com/js/123.js is the link and when a request comes for this - check and send latest file ?
ASP.NET 4.5+ comes with a built-in bundling & minification framework
which is designed to solve this problem.
If you absolutely need a simple roll-your-own solution you can use the answer below, but I would always say the correct way is to use a bundling & minification framework.
You can modify the AssemblyInfo.cs file like so:
Change
[assembly: AssemblyVersion("1.0.0.0")]
to
[assembly: AssemblyVersion("1.0.*")]
This means that every time the project is built, it will have a new assembly version which is higher than the previous one. Now you have your unique version number.
Create an UrlHelperExtension class that will help get this information when needed in the views:
public static class UrlHelperExtensions
{
public static string ContentVersioned(this UrlHelper self, string contentPath)
{
string versionedContentPath = contentPath + "?v=" + Assembly.GetAssembly(typeof(UrlHelperExtensions)).GetName().Version.ToString();
return self.Content(versionedContentPath);
}
}
You can now easily add a version number to your views in the following manner:
<link href="#Url.ContentVersioned("style.css")" rel="stylesheet" type="text/css" />
When viewing your page source you will now have something that looks like
<link href="style.css?v=1.0.4809.30029" rel="stylesheet" type="text/css" />
UPDATE: The previous version did not work on Azure, I have simplified and corrected below. (Note, for this to work in development mode with IIS Express, you will need to install URL Rewrite 2.0 from Microsoft http://www.iis.net/downloads/microsoft/url-rewrite - it uses the WebPi installer, make sure to close Visual Studio first)
If you would like to change the actual names of the files, rather than appending a querystring (which is ignored by some proxies / browsers for static files) You can follow the following steps: (I know this is an old post, but I ran across it while developing a solution:
How to do it: Auto-increment the assembly version every time the project is built, and use that number for a routed static file on the specific resources you would like to keep refreshed. (so something.js is included as something.v1234.js with 1234 automatically changing every time the project is built) - I also added some additional functionality to ensure that .min.js files are used in production and regular.js files are used when debugging (I am using WebGrease to automate the minify process) One nice thing about this solution is that it works in local / dev mode as well as production. (I am using Visual Studio 2015 / Net 4.6, but I believe this will work in earlier versions as well.
Step 1: Enable auto-increment on the assembly when built
In the AssemblyInfo.cs file (found under the "properties" section of your project change the following lines:
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
to
[assembly: AssemblyVersion("1.0.*")]
//[assembly: AssemblyFileVersion("1.0.0.0")]
Step 2: Set up url rewrite in web.config for files with embedded version slugs (see step 3)
In web.config (the main one for the project) add the following rules in the <system.webServer> section I put it directly after the </httpProtocol> end tag.
<rewrite>
<rules>
<rule name="static-autoversion">
<match url="^(.*)([.]v[0-9]+)([.](js|css))$" />
<action type="Rewrite" url="{R:1}{R:3}" />
</rule>
<rule name="static-autoversion-min">
<match url="^(.*)([.]v[0-9]+)([.]min[.](js|css))$" />
<action type="Rewrite" url="{R:1}{R:3}" />
</rule>
</rules>
</rewrite>
Step 3: Setup Application Variables to read your current assembly version and create version slugs in your js and css files.
in Global.asax.cs (found in the root of the project) add the following code to protected void Application_Start() (after the Register lines)
// setup application variables to write versions in razor (including .min extension when not debugging)
string addMin = ".min";
if (System.Diagnostics.Debugger.IsAttached) { addMin = ""; } // don't use minified files when executing locally
Application["JSVer"] = "v" + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString().Replace('.','0') + addMin + ".js";
Application["CSSVer"] = "v" + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString().Replace('.', '0') + addMin + ".css";
Step 4: Change src links in Razor views using the application variables we set up in Global.asax.cs
#HttpContext.Current.Application["CSSVer"]
#HttpContext.Current.Application["JSVer"]
For example, in my _Layout.cshtml, in my head section, I have the following block of code for stylesheets:
<!-- Load all stylesheets -->
<link rel='stylesheet' href='https://fontastic.s3.amazonaws.com/8NNKTYdfdJLQS3D4kHqhLT/icons.css' />
<link rel='stylesheet' href='/Content/css/main-small.#HttpContext.Current.Application["CSSVer"]' />
<link rel='stylesheet' media='(min-width: 700px)' href='/Content/css/medium.#HttpContext.Current.Application["CSSVer"]' />
<link rel='stylesheet' media='(min-width: 700px)' href='/Content/css/large.#HttpContext.Current.Application["CSSVer"]' />
#RenderSection("PageCSS", required: false)
A couple things to notice here: 1) there is no extension on the file. 2) there is no .min either. Both of these are handled by the code in Global.asax.cs
Likewise, (also in _Layout.cs) in my javascript section: I have the following code:
<script src="~/Scripts/all3bnd100.min.js" type="text/javascript"></script>
<script src="~/Scripts/ui.#HttpContext.Current.Application["JSVer"]" type="text/javascript"></script>
#RenderSection("scripts", required: false)
The first file is a bundle of all my 3rd party libraries I've created manually with WebGrease. If I add or change any of the files in the bundle (which is rare) then I manually rename the file to all3bnd101.min.js, all3bnd102.min.js, etc... This file does not match the rewrite handler, so will remain cached on the client browser until you manually re-bundle / change the name.
The second file is ui.js (which will be written as ui.v12345123.js or ui.v12345123.min.js depending on if you are running in debug mode or not) This will be handled / rewritten. (you can set a breakpoint in Application_OnBeginRequest of Global.asax.cs to watch it work)
Full discussion on this at: Simplified Auto-Versioning of Javascript / CSS in ASP.NET MVC 5 to stop caching issues (works in Azure and Locally) With or Without URL Rewrite (including a way to do it WITHOUT URL Rewrite)
1)
Use file modification time instead. Here's an example:
public static string GeneratePathWithTime(string cssFileName)
{
var serverFilePath = server.MapPath("~/static/" + cssFileName);
var version = File.GetLastWriteTime(serverFilePath).ToString("yyyyMMddhhmmss");
return string.Format("/static/{0}/{1}", version, cssFileName);
}
This will generate a path like "/static/201109231100/style.css" for "style.css" (assuming the your style.css is located in the static directory).
You'll then add a rewrite rule in IIS to rewrite "/static/201109231100/style.css" to "/static/style.css". The version number will only be changed when the css file has been modified and only applies to modified files.
2)
You can handle the request to 123.js via an HttpModule and send the latest content of it, but I don't think you can guarantee the request gets the latest version. It depends on how the browser handles its cache. You can set an earlier expiration time (for example, one minute ago) in your response header to tell the browsers to always re-download the file, but it's all up to the browser itself to decide whether to re-download the file or not. That's why we need to generate a different path for our modified files each time we updated our files in your question 1), the browser will always try to download the file if the URL has never been visited before.
I wrote a Url Helper which does the CacheBusting for me.
public static string CacheBustedContent(this UrlHelper helper, string contentPath)
{
var path = string.Empty;
if (helper.RequestContext.HttpContext.Cache["static-resource-" + contentPath] == null)
{
var fullpath = helper.RequestContext.HttpContext.Server.MapPath(contentPath);
var md5 = GetMD5HashFromFile(fullpath);
path = helper.Content(contentPath) + "?v=" + md5;
helper.RequestContext.HttpContext.Cache.Add("static-resource-" + contentPath, path, null, System.Web.Caching.Cache.NoAbsoluteExpiration, new TimeSpan(24, 0, 0), System.Web.Caching.CacheItemPriority.Default, null);
}
else
{
path = helper.RequestContext.HttpContext.Cache["static-resource-" + contentPath].ToString();
}
return path;
}
You could replace the GetMD5HashFromFile() with CRC or any other sort of call which generates a unique string based on the contents or last-modified-date of the file.
The downside is this'll get called whenever the cache is invalidated. And if you change the file on live somehow, but don't reset the application pool, you'll probably need to touch the web.config to get it to reload correctly.
You might want to have a look at Dean Hume's Blogpost MVC and the HTML5 Application Cache. In that post, he points out an elegant way of automatically handling versioning per request, using a class library of #ShirtlessKirk:
#Url.Content("~/Content/Site.css").AppendHash(Request)
This question is really old now, but if anyone stumbles upon it, here's to my knowledge the current state of the art:
In ASP.NET Core you can use TagHelpers and simply add the asp-append-version attribute to any <link> or <script> tag:
<script src="~/js/my.js" asp-append-version="true"></script>
For both ASP.NET Core and Framework there is a NuGet Package called WebOptimizer (https://github.com/ligershark/WebOptimizer). It allows for both bundling and minification, and will also append a content-based version string to your file.
If you want to do it yourself, there is the handy IFileVersionProvider interface, which you can get from your IServiceProvider in .NET Core:
// this example assumes, you at least have a HttpContext
var fileVersionProvider = httpContext.RequestServices.GetRequiredService<IFileVersionProvider>();
string path = httpContext.Content("/css/site.css");
string pathWithVersionString = fileVersionProvider.AddFileVersionToPath(httpContext.Request.PathBase, path);
For .NET Framework, you can get the FileVersionProvider source from here: https://github.com/dotnet/aspnetcore/blob/main/src/Mvc/Mvc.Razor/src/Infrastructure/DefaultFileVersionProvider.cs
You will have to do some work, like replacing the Cache with MemoryCache.Default or a ConcurrentDictionary or something, but the 'meat' is there.

Resources