I have a page that uses an external javascript file. That file requires variables that are different in Dev, QA and production environments, causing me to need to maintain multiple copies of the same script file for each environment.
I'd prefer to maintain the values of these variables in web.config (perhaps appSettings section), and resolve these values at runtime, before streaming the .js file to the browser. Is there a way to do this?
asp.net Can I inject configuration settings into javascript?
Sample Java Script
<script language="javascript" type="text/javascript">
var Publicvalue = abc();
function abc() {
Publicvalue = <%=MyProperty%>
alert(Publicvalue);
return Publicvalue;
}
</script>
Sample HTML
<asp:Button ID="btn" runat="server" Text="efeded" OnClientClick="return abc();" OnClick="btn_Click" />
Sample Code Behind
public int MyProperty
{
get
{
return 1;
}
}
Related
I use CreateTemplateFromFile and push a variable inside my template. My template file is including another file, but I'm not able to push this variable in the second file embedded.
Here below what I've tried:
index.html:
<!DOCTYPE html>
<html>
<?!= include('header'); ?>
<?!= include('style'); ?>
<body>
...
</body>
<?!= include('script'); ?>
</html>
the script part of the index.html in a separate file:
<script>
function getData() {
$("#loadingMessage").html('Loading');
console.log('myContent:', <?= data ?>);
...
}
</script>
The doGet part of the Google apps script code:
var template = HtmlService.createTemplateFromFile('index');
template.data = myContent;
return template.evaluate()
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
the variable is correctly pushed in index.html but not reach the script part.
Any idea ? Maybe to include the script file as a template also ?
How to pass variables between Apps Script and Javascript.
Google Apps Script features the method google.script.run that can be called from the JS part of a Web App. The methods allows to pass parameters to an Apps Script function and to assign the return value of the GAS function back to a JS function.
Sample:
.gs file
function doGet() {
var template = HtmlService.createTemplateFromFile('index');
return template.evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function myContent(input) {
var myContent="foo"+input;
return myContent;
}
HTML/js file
<html>
<head>
<base target="_top">
</head>
<body onload="getData()">
<script>
function getData() {
google.script.run.withSuccessHandler(proceedData).myContent("bar");
...
}
function proccedData(returnValue) {
var data = returnValue;
}
</script>
</body>
</html>
If you want to use scriptlets
The documentation specifies:
Remember, however, that because template code executes before the page is served to the user, these techniques can only feed initial content to a page. To access Apps Script data from a page interactively, use the google.script.run API instead.
Because scriptlet code executes before the page is served, it can only run once per page; unlike client-side JavaScript or Apps Script functions that you call through google.script.run, scriptlets can't execute again after the page loads.^
scriptlets can call functions defined in other code files, reference global variables, or use any of the Apps Script APIs.
In your case, if you want to use scriptlets, you either have to call a function or make your variable dataglobal, e.g.:
//global variable
var data=myContent;
function doGet() {
var temp=HtmlService.createTemplateFromFile("index.html");
return temp.evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
Also keep in mind:
Templates can be challenging to debug because the code you write is not executed directly; instead, the server transforms your template into code, then executes that resulting code.
I have several WebSockets endpoints such as,
wss://localhost:8181/ContextPath/Push
All of such endpoint URLs are hard-coded in separate, external JavaScript files (.js). These JavaScript files are included in respective XHTML files as and when required. The host name and the context path should be evaluated programmatically instead of hard-coding all over the place where they are required.
The host name (localhost:8181) can be obtained in JavaScript using document.location.host but there is no standard/canonical way in JavaScript to obtain a context path where the application runs.
I am doing something like the following.
A global JavaScript variable is declared on the master template as follows.
<f:view locale="#{bean.locale}" encoding="UTF-8" contentType="text/html">
<f:loadBundle basename="messages.ResourceBundle" var="messages"/>
<ui:param name="contextPath" value="#{request.contextPath}"/>
<ui:insert name="metaData"></ui:insert>
<h:head>
<script type="text/javascript">var contextPath = "#{contextPath}";</script>
</h:head>
<h:body id="body">
</h:body>
</f:view>
</html>
The JavaScript files in which the host name and the context path are hard-coded are included in respective template clients or any of sections of the template north, south, east and west as follows.
<html lang="#{bean.language}"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:form>
<h:outputScript library="default" name="js/websockets.js" target="head"/>
</h:form>
For the sake of viewpoint only, websockets.js looks like the following (you can simply ignore it).
if (window.WebSocket) {
// The global variable "contextPath" is unavailable here
// because it is declared afterwards in the generated HTML.
var ws = new WebSocket("wss://"+document.location.host + contextPath + "/Push");
ws.onmessage = function (event) {
// This handler is invoked, when a message is received through a WebSockets channel.
};
$(window).on('beforeunload', function () {
ws.close();
});
} else {}
Now, the global JavaScript variable contextPath declared in the master template is expected to be available in the included JavaScript file namely websockets.js. This is however untrue.
What happens is that the included JavaScript file namely websockets.js where the global variable contextPath is attempted to be accessed, is placed before the hard-coded <script> tag in the generated HTML <head> tag in the master template.
In other words, the global JavaScript variable contextPath is actually attempted to use in the included file websockets.js before being declared.
Anyway, how to get rid of hard-coding the context path in external JavaScript files?
The sole purpose of doing this is that unlike CSS files, EL isn't evaluated in external JavaScript files. Therefore, #{} thing will not work unless it is placed in an XHTML file.
What happens is that the included JavaScript file named websockets.js where the global variable contextPath is attempted to be accessed, is placed before the hard-coded <script> tag in the generated HTML <head> tag in the master template
This is unexpected. You declared the <h:outputScript> referring websockets.js file inside <h:body> with target="head". This is supposed to end up after all other script resources already declared in <h:head>. See also a.o. How to reference CSS / JS / image resource in Facelets template? After all, this appears to be caused by PrimeFaces bundled HeadRenderer which is intented to auto-include some CSS resources and take care of the <facet name="first|middle|last">.
This is worth an issue report to PF guys (if not already done). In the meanwhile, your best bet is to turn off it by explicitly registering the JSF implementation's own HeadRenderer back as below in faces-config.xml (provided that you're using Mojarra).
<render-kit>
<renderer>
<component-family>javax.faces.Output</component-family>
<renderer-type>javax.faces.Head</renderer-type>
<renderer-class>com.sun.faces.renderkit.html_basic.HeadRenderer</renderer-class>
</renderer>
</render-kit>
And explicitly include the PrimeFaces theme-specific theme.css as below in <h:head>:
<h:outputStylesheet library="primefaces-aristo" name="theme.css" />
Coming back to the real question,
Anyway, how to get rid of hard-coding the context path in external JavaScript files?
Either set it as base URI (note: relative path isn't supported in HTML4 / IE6-8).
<h:head>
<base href="#{request.contextPath}/" />
...
</h:head>
var baseURI = $("base").attr("href");
Or set it as data attribute of HTML root element.
<!DOCTYPE html>
<html lang="en" data-baseuri="#{request.contextPath}/" ...>
...
</html>
var baseURI = $("html").data("baseuri");
Unrelated to the concrete problem, as a word of advice, to transparently cover both http+ws and https+wss, consider using location.protocol instead of a hardcoded wss.
var ws = new WebSocket(location.protocol.replace("http", "ws") + "//" + location.host + baseURI + "Push");
Is the following an option for you?
Define a hidden html-tag in the master template, something like :
<span id="pageContextPath" data="#{contextPath}" style="display:none;"></span>
Change your JavaScript Code to something like :
jQuery(document).ready(function ($) {
if (window.WebSocket) {
contextPath = $("#pageContextPath").attr("data");
var ws = new WebSocket("wss://" + document.location.host + contextPath + "/Push");
//...
} else {}
});
I used here jQuery. You may rewrite it in plain JavaScript. But it should be done after "document ready" to ensure that the hidden tag has been rendered. otherwise js won't find that element.
Good morning!
I have been working on a client side browser based app using JavaScript that (all of a sudden) needs the capability to save and load files locally.
The saved files are plain text (.txt) files.
I have managed to get JavaScript to read existing text files. However, I am unable to find reliable information on how to create and edit the contents of these files.
Based on what I see online, I am under the impression that you can't do this with JavaScript alone.
I found out from another source that the best way to do this is outsource the file writing/editing to a Java file and let Java do the work.
I found a code snippet and tweaked it around a bit, but it is not working and I seem to be at a loss:
JAVASCRIPT
<!Doctype html>
<html>
<OBJECT ID="Test" height=0 width=0
CLASSID="CLSID:18F79884-E141-49E4-AB97-99FF47F71C9E" CODEBASE="JavaApplication2/src/TestJava.java" VIEWASTEXT>
</OBJECT>
<script language="Javascript">
var Installed;
Installed = false;
try
{
if (Test==null)
Installed = false;
else
Installed = true;
}
catch (e)
{
Installed = false;
}
alert ("Installed :- " + Installed);
TestStr = Test.SendStr("Basil");
alert (TestStr);
</script>
</html>
JAVA
import javax.swing.*;
public class TestJava {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
}
public String SendStr(String lStr)
{
return lStr + "!!!";
}
}
If someone could point me in the right direction or even just explain why this isn't working, I would appreciate it.
I believe the sandbox issue prevents all browsers from performing any and all local file writing, without an enormous amount of working around the access restrictions. It is easier to write files remotely on the server than to write them locally to the client. This is true across all browsers.
So while it may be possible to perform the load function, you cannot perform the 'save' function on the local machine.
I'd like to have different versions of .js javascript files in my ASP.NET WebForms application (VS 2008):
the full-blown version, which comments and so on
the minified version, for production
Is there a way to automatically get the full-blown version while debugging and the minified version when the application is deployed to production? I don't mind if the answer is a hack.
Is it possible in VS 2010?
Of course it is possible, but the question here is "how you going to set it up."
I start with the key here that is the DEBUG definition. So let say that you like to set it up on the page.
So on page you can do something like:
<% #if DEBUG %>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js"></script>
<% #else %>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<% #endif %>
Alternative, you can use a Literal and make this switch on code behind.
<asp:Literal runat="server" ID="txtScripts" EnableViewState="false" />
and
protected void Page_Load(object sender, EventArgs e)
{
#if DEBUG
txtScripts.Text = "<script type=\"text/javascript\" src=\"http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js\"></script>";
#else
txtScripts.Text = "<script type=\"text/javascript\" src=\"http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js\"></script>";
#endif
}
Other way is to use a handler and read all the javascript files and make minified using code, and use again the same key DEBUG to send the one or the other version.
Personally I use the MS Ajax MInified
http://www.asp.net/ajaxlibrary/AjaxMinDocumentation.ashx
I read all my javascript files, make them one file, and use this parameters to minified them or not.
Minifier MyMin = new Minifier();
CodeSettings cs = new CodeSettings();
#if DEBUG
cs.MinifyCode = false;
cs.OutputMode = OutputMode.MultipleLines;
cs.PreserveFunctionNames = true;
cs.RemoveFunctionExpressionNames = false;
cs.RemoveUnneededCode = false;
cs.StripDebugStatements = false;
#else
cs.MinifyCode = true;
cs.OutputMode = OutputMode.SingleLine;
#endif
Write(MyMin.MinifyJavaScript(AllMyJavascript, cs))
I like using the SquishIt library.
Download : https://github.com/jetheredge/SquishIt/downloads
Walkthrough : http://www.codethinked.com/squishit-the-friendly-aspnet-javascript-and-css-squisher
Allows you to keep your CSS and JavaScript in multiple files for local development and publishes a single minified file for production.
EDIT: This tool allows to define programmatically a list of files to minify. The code that defines this list is embedded in code blocks in the .aspx file or MVC view. At run time two things happen:
a minifed file is dynamically created
a link to the dynamically created minified file is created in the final rendered HTML
But, if #debug is defined, instead of doing so, the code renders the links to the original files in the output, so that the original version of the files can be used for debugging.
It supports CSS and javascript minfication.
For further info, follow the above links.
Is there a way to have Expression Language (EL) expressions included JavaScript files be evaluated by JSF?
I was hoping that Seam might have a way around this, but no luck so far. All I want is to be able to use localized messages in my JavaScript functions which are shared across pages.
Five ways:
Declare it as global variable in the parent JSF page.
<script type="text/javascript" src="script.js"></script>
<script type="text/javascript">
var messages = [];
<ui:repeat value="#{bean.messages}" var="message">
messages['#{message.key}'] = '#{message.value}';
</ui:repeat>
</script>
Or, if it's in JSON format already.
<script type="text/javascript" src="script.js"></script>
<script type="text/javascript">var messages = #{bean.messagesAsJson};</script>
Put the whole <script> in a XHTML file and use ui:include to include it.
<script type="text/javascript" src="script.js"></script>
<ui:include src="script-variables.xhtml" />
Pass *.js through the JspServlet (only if it's enough to evaluate only the ${} expressions). E.g. in web.xml (the <servlet-name> of JspServlet can be found in web.xml of the servletcontainer in question, it's usually jsp).
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
Make use of "good old" JSP with a modified content type. Rename script.js to script.jsp and add the following line to top of JSP (only if it's enough to evaluate only the ${} expressions):
<%#page contentType="text/javascript" %>
Let JS obtain the data ajaxically during load. Here's a jQuery targeted example.
$.getJSON('json/messages', function(messages) {
$.each(messages, function(key, value) {
$.messages[key] = value;
});
});
Since I don't like techniques that won't let the browser cache the localized Strings, I used the following technique to localize JavaScript alerts, etc. It seems a good fit if the Strings that you need in your JavaScript code are different from the ones needed by the Web server:
<h:head>
<h:outputScript library="javascript" name="#{fw.JsFwStrings}" />
...
I then assign the resource string JsFwStrings to the filename of the JavaScript file defining the localized strings for the given language.
For example, the fw_en.properties file contains the entry
JsFwStrings=JsFwStrings_en.js
And the JsFwStrings_en.js file contains
var TosFramework = TosFramework || {};
TosFramework.Strings = {
UnSavedChangesWarning : 'You have unsaved changes.',
CancelConfirmQuestion : 'Are you sure you want to cancel?'
}