I have some content (html) that is being encoded as a result of this javascript (from this page) and sent to my rails application:
function encode_utf8_b64(string) {
return window.btoa(unescape(encodeURIComponent(string)));
}
The correspond js code to get it back to original is this:
function decode_utf8_b64(string) {
return decodeURIComponent(escape(window.atob(string)));
}
My question is, is there an equivalent in ruby of decodeURIComponent()? So far I have this that gets it part of the way out, but I'm missing the last step of decodeURIComponent:
CGI::escape(Base64.decode64(string))
URI.unescape could probably help:
def decode_utf8_b64(string)
URI.unescape(CGI::escape(Base64.decode64(string)))
end
you have to add the necessary rubygem too:
require 'uri'
I've tested this on ruby 1.9.2.
Related
I actually work on a tool named jedox. With this tool I can make macro(like excel) but in PHP. Jedox provide some example of macro and in one of these example there is this code:
function test()
{
return array(array('eval', "(function(){
console.log('salut')
}())"));
}
It's a PHP code that run JS code. But the problem is I don't know how this code work, the only thing I know about it is that it execute JS code but can't return anything, so if you put return in the code it will not return any value. I have no way to retrieve the value returned.
So my question is how should I supposed to retrieve a value from this ?
PS: if I try to investigate about the value returned by test() I get an array nested with another array with those 2 values 'eval' and the function.
PS2: Apparently you can't run this code correctly with traditional tool. So to help me you should have jedox, I guess :/ ...
On the client side, someone must be getting those two strings and executing them. The PHP code ("host side") is not actually doing that.
You may could put the Javascript code into a file. Then execute the file using NodeJS and get the value.
For example:
function test() {
file_put_contents('test.js', <<< TEXT
(function(){
console.log('salut')
}())
TEXT);
return shell_exec('node test.js');
}
echo test(); // Return: sault
Also notice that in most shared hosts and servers shell_exec function is disabled by default. You can enable it through you php.ini.
Mid development I decided to switch to server-side rendering for a better control amongst other benefits. My web application is completely AJAX based, no url redirecting, so the idea here is a website that builds itself up
I just couldn't figure out the proper way to send javascript events/functions along with the html string, or should all the necessary javascript always be preloaded in the static files?
Let's say client clicks a pre-rendered button 'open table'
The server will make a query, build the html table and send it back, but this table also needs javascript triggers and functions to work properly, how are these sent, received and executed?
There are a couple of articles that mention to not use eval() in Javascript, is there any way around this? I don't want to have to preload unnecessary events for elements that don't yet exist
The server is Python and the Client is Javascript/JQuery
Theoretical example :
Client Base Javascript :
$("body").on("click", "#open_table", function() {
$.getJSON('/get_table', function(response){
$("#table_div").append(response.html);
eval(response.javascript()); //??
}
});
Python Server(views.py) :
def get_table(request):
data = {}
#String containing rendered html
data['html'] = get_render_table()
#String containing Javascript code?
data['javascript'] = TABLE_EVENTS_JAVASCRIPT
return HttpResponse(json.dumps(data),content_type='json')
Worth noting my question comes from an experimental/learning perspective
Update:
You can use jQuery.getScript() to lazy load JS. I think this solution is as close as you can get to run JS without using eval().
See this example:
jQuery.getScript("/path/to/script.js", function(data, textStatus, jqxhr) {
/* Code has been loaded and executed. */
console.log( data ); // Data returned
console.log( textStatus ); // Success
console.log( jqxhr.status ); // 200
console.log( "Load was performed." );
});
and "/path/to/script.js" could be a string returned from $.getJOSN response.
Also, the documentation for getScrippt() has examples on how to handle errors and cache files.
Old Answer:
Using .on() attaches events to current and future DOM elements.
You can either attache events prior to DOM insertion or attache event after DOM insertion.
So in your example you can do something like:
$("body").on("click", "#open_table", function() {
$.getJSON('/get_table', function(response){
var code = $(response.html);
code.find(".elementToFind").on("click", function (){
// Code to be executed on click event
});
$("#table_div").append(code);
}
});
I did not test the code but I think it should work.
Assuming you can't just set up an event-binding function and then call it from the main script (the JavaScript you need can't be guessed ahead of time, for example) then one really easy way is just to append the JavaScript to the bottom of the returned HTML content within script tags. When it's appended along with the HTML, the script should simply execute, with no eval() required.
I can't swear that this would work in old browsers, but it's a trick I've used a couple of times, and I've had no problems with it in Firefox, Chrome, or any of the later IE versions.
I think I see what you're asking here, from my understanding you want to send the new "page" asynchorously, and render the new javascript and html. It looks like you already got your request/response down, so i'm not gonna go and talk about sending JSON objects, and the whole "how-to" of sending html and javascript because it looks like you got that part. To do what you want and to dynamically add your javascript in, this stackoverflow question looks like it has what you need
Is there a way to create a function from a string with javascript?
So pertaining to your example, here is how it would look when you recieve the JSON string from your python script:
$("body").on("click", "#open_table", function() {
$.getJSON('/get_table', function(response){
$("#table_div").append(response.html);
/* Create function from string */
var newFunction = Function(response.javascript['param_1'], response.javascript['param_2'], response.javascript['function']);
/* Execute our new function to test it */
newFunction();
}
});
*Your actual function contents would be the string: response.javascript['function']
*Your parameter names if any would be in separate strings ex: response.javascript['param_1']
That is almost a direct copy of the "String to function" code that you can see in the linked question, just replaced it with your relevant code. This code is also assuming that your object is sent with the response.javascript object containing an array with your actual function content and parameter names. I'm sure you could change the actual name of the var too, or maybe put it in an associative array or something that you can keep track of and rename. All just suggestions, but hopefully this works for you, and helps you with your problem.
I am also doing similar work in my project where I had to load partial html using ajax calls and then this partial HTML has elements which requires events to be attached. So my solution is to create a common method to make ajax calls and keep a js method name to be executed post ajax call in html response itself. For example my server returns below html
<input type="hidden" data-act="onPartialLoad" value="createTableEvents" />
<div>.........rest of html response.....<div>
Now in common method, look for input[type='hidden'][data-act='onPartialLoad'] and for each run the method name provided in value attribute (value="createTableEvents")
Dont Use Eval() method as it is not recommended due to security
issues. Check here.
you can run js method using window["method name"]...so here is a part of code that I use.
$.ajax(options).done(function (data) {
var $target = $("#table_div");
$target.fadeOut(function () {
$target.html(data);
$target.fadeIn(function () {
try {
$('input[data-act="onPartialLoad"]', $target).each(function () {
try {
//you can pass parameters in json format from server to be passed into your js method
var params = $(this).attr('params');
if (params == undefined) {
window[$(this).val()]();
}
else {
window[$(this).val()]($.parseJSON(htmlutil.htmlDecode(params)));
}
} catch (e) {
if (console && console.log) {
console.log(e.stack);
console.log($(this).val());
}
}
});
}
catch (e) {
console.log(e.stack);
}
});
});
});
use jQuery.getScript() (as suggested by Kalimah Apps) to load the required js files first.
I need to call a controller function from javascript on my gsp.
I have read different solutions from hundreds of places but none worked.
The problem which I found closest to mine was this.
But I am not repeating the same mistake as this and thus the solution didn't help.
I have a tag like this which calls the javascript function
<g:select name="poNumber" noSelection="['':'Select PO Number']" from="${com.rerq.PurchaseOrder.list()}"
onchange="getProject(this.value)" />
And the javascript function looks like this
function getProject(poNumber){
var projectName = document.getElementById("projectName");
var newData = ${remoteFunction(controller: 'sow', action: 'getProject', params: ['poNumber':poNumber])};
}
And the function I need to call is
def getProject(String poNumber) {
String projectName = Sow.find("from Sow as s where s.poNumber=?", [poNumber])
return projectName
}
The controller function might have mistakes as I am completely new to groovy and grails. But my understanding is that the control isn't reaching here so this should not be the cause of any problem.
I am getting below exception
No signature of method: remoteFunction() is applicable for argument types: (java.util.LinkedHashMap) values: [[controller:sow, action:getProject, params:[poNumber:null]]]
I tried using remoteFunction() in g:select itself but it threw another exception which said
Attribute value quotes not closed ...
even though they were.
Any help is greatly appreciated.
To use remoteFunction with Grails 3 you need to add the ajax-tags plugin: org.grails.plugins:ajax-tags:1.0.0
Actually you can have your gsp recognize some Grails functions inside your js if the script is inside the gsp and anything you need for your js is created on the server side. In your case it seems you want to do an ajax call so you could have the following.
project.gsp (Consider that you already loaded jQuery)
<g:select name="poNumber" noSelection="['':'Select PO Number']" from="${com.impetus.rerq.PurchaseOrder.list()}"
onchange="getProject(this.value)" />
And in the same file you have
<script type="text/javascript">
function getProject(poNumber){
jQuery("#yourTarget").load("${createLink(action: 'getProject')}",{poNumber: poNUmber},function(response, status, xhr ){
if ( status == "error" ) {
alert("No data loaded.")
}
});
}
</script>
As you see a gstring in load("${}",... is used because it will be parsed in the server and at client side your actual js it will parse to load("yourcontrollerName/getProject",..... Why not code the url directly in the js? Because by using createLink() it is less likely to make reference mistakes.
EDIT
If you want to do this but using an external js file, you would need a way to pass the url, to the js, and use a simple load function. So something like this will be helpful
<g:select name="poNumber" noSelection="['':'Select PO Number']" from="${com.impetus.rerq.PurchaseOrder.list()}"
onchange="getProject(this.value, \'${createLink(action:'getProject')}\')" />
Once on the server onchange="getProject(this.value,\'${createLink(action:'getProject')}\')"would be parsed to onchange="getProject(this.value,'yourController/getProject')". Be wary that I might have messed up the ""s and ''s so verify your html output.
And you would need a js function that accepts the uri
function getProject(value, targetUri){
....
}
What you need to review is when is your function needed, on the server o in the client;if the functions are inside a gsp or not; And if not available, how could you pass data to them.
You cannot access grails's controller from javascript. I haven't tested it but this might work.
<g:createLink controller="sow" action="getProject", params="['poNumber':poNumber]"/>
Also, if you use Google Chrome's developer's tool, you will see how your javascript code is displayed. Make sure it is in right syntax.
I am storing a response in javascript variable. This is inside a .html.erb file.
var file = response.data.files[0];
I first made a call using
var f = "<%=link_onedrive%>"
This successfully calls a method link_onedrive
Then I made this call
var f = "<%=link_onedrive(%>file<%=)%>"
It throws an error
wrong number of arguments (0 for 1)
My question is how to make a ruby method call with argument from a erb.
edited
here's my link_onedrive
def link_onedrive(file)
uri = URI.parse("https://api.onedrive.com/v1.0")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Post.new("https://api.onedrive.com/v1.0/drive/items/file.link/action.createLink)
req.content_type = "application/json"
req.body = '{"type" : "view"}'
response = http.request(req)
arr = JSON.parse(response.body)
arr["link"]["webUrl"]
end
ok... first you need to realise how erb works.
At the end of a controller action: Rails parses the erb and runs all the ruby first and uses it to generate some html+js code... at this point, the bit that says <%= link_onedrive %> gets completely overwritten by the result of calling the link_onedrive method... it's not there in the html anymore.
This html+js then gets sent to the browser and the browser (on the client's machine) runs the js that has already been created at this point.
You can't call the ruby from the javascript, because by that stage, there is no ruby left... just javascript.
If you want to call ruby methods from your javascript - you probably need to set up an ajax-post that posts to a controller that runs the ruby, and then returns a result that the javascript does something with.
or we need to help you rewrite the two bits of code... to get what you actually want some other way (but to do that we probably need to see what link_onedrive actually does)
What I am trying to do is pretty simple: yet something has clearly gone awry.
On the Front-End:
function eval() {
var x = 'Unchanged X'
$.get("/", { entry: document.getElementById('entry').value },
function(data){
x = data;
}
);
$("#result").html(x);
}
On the Back-End:
class MainHandler(webapp.RequestHandler):
def get(self):
path = os.path.join(os.path.dirname(__file__), 'index.html')
if self.request.get('entry') != '':
#self.response.out.write({'evalresult': self.request.get('entry')})
self.response.out.write(request.get('entry'))
else:
self.response.out.write(template.render(path, {'result': 'Welcome!!'}))
def main():
application = webapp.WSGIApplication([('/', MainHandler)],
debug=True)
wsgiref.handlers.CGIHandler().run(application)
Yet, apparently the function is never being called and #result gets set to 'Unchanged X'. What am I missing?
NOTE: The callback is NOT being called. I have verified this by placing an alert("Test") within the callback function. Any ideas anyone?
$("#result").html(x); goes in the get() callback
If the callback is not running you can try changing the $.get into a $.ajax() call, and adding an error callback, to see if the server is returning an error.
Or better yet, check in the "net" panel in firebug to see what the server response is, which might help you track down what the issue is on the back end.
Also once the issue is fixed, you might want to replace the $.get with a simple $().load which would take the data and place it into the div automatically:
$('#result').load('/', { entry: document.getElementById('entry').value });
EDIT: I suppose the following would be a more jQueryish way of writing it:
$('#result').load('/', { entry: $('#entry').val() });
First we have the silly mistake:
<font size="3" face="Trebuchet MS">Speak Your Mind: </font><input type="text"
size="60" id="entry"/> <img valign="bottom" src='/assets/cognifyup.png'
onMouseOver="over()" onMouseOut="out()" onMouseDown="out(); evaluate();"
onMouseUp="over()"><br><br>
Semicolons are required after the calls to over() and out() (roger that? --- sorry couldn't resist)
Secondly (the much more subtle problem):
If we ever need intend to translate the get() into a getJSON() call, (which you might have noted was my original intent from the commented python code that returns a dict), then we need to wrap a str() call around self.request.get('entry'). Hence,
self.response.out.write({'evalresult': self.request.get('entry')})
becomes:
self.response.out.write({'evalresult': str(self.request.get('entry'))})
As strings from an HTML field translate to unicode text in Python, at the back-end, we apparently need to convert it to a Python string (as getJSON() apparently doesn't like Python's representation of a unicode string -- any ideas why this this is the case anyone?).
At any rate, the original problem has been solved. In conclusion: any JSON object with a Python unicode string will not be accepted as a valid JSON object and will fail silently -- a nasty gotcha that I can see biting anyone using JQuery with Python on the server-side.