Use catalyst and Ajax to refresh an SVG block - javascript

I am building a web app in which I have a number of clickable maps, stored as static SVG files, that I would like to be able to swap dynamically based on a menu-click. So far, I have javascript code to call my Catalyst controller, and I would like it to return the contents of the SVG file in the response body. So far I can get the javascript to catch the menu clicks and call the controller, and in the controller I am able to get the name of the file out of my database. I am stuck at that step, though, and have been thus far unable to find out how to read the contents of that file in the controller and return it to the javascript controller. Any help would be appreciated!
UPDATE:
The (Edited) code below works, but I'm not sure if this is the best way. I would definitely be open to suggestions on ways to improve my process. Thanks!
Javascript:
$(document).on("click",".map_select", function(e){
$(document.getElementById("som_map")).load("[% c.uri_for('/maps/update_map/') %]" + this.title);
})
HTML
<svg id="som_map" class="mapmain" width="720px" height="430px">
</svg>
PERL
sub update_map :Path :Local :Args(1) {
my ( $self, $c, $map_id ) = #_;
my $fields = $c->model('DB::Map')->find($map_id);
my $map_file = $fields->get_column('map_file');
my $svg;
my $path = "root/static/svg/$map_file";
open my $fh, '<', $path;
{
local $/ = undef;
$svg = <$fh>;
}
close $fh;
$c->res->body($svg);
}
SVG files are stored in root/static/svg/

Unless you have a reason to do it, I would use your web server (Apache, nginx, ...) serve the file for you instead of handling the file I/O inside of your controller.
In your load function in javascript pass in a function that returns a URL for you:
$(document.getElementById("som_map")).load(getSVGUrl(this.title));
Then define that function to call Catalyst to get the appropriate URL for the given mapId:
function getUrl(mapId) {
var returnUrl;
jQuery.ajax({
url: "[% c.uri_for('/maps/update_map/') %]"
+ mapId,
success: function(result) {
if(result.isOk == false)
returnUrl = result.message;
},
async: false,
dataType: 'text/plain'
});
return returnUrl;
}
This function should call your application and just expect to get the URL back. It should be fast enough that making it synchronous does not matter.
Finally, your Catalyst function should just return the URL to the document:
sub update_map :Path :Local :Args(1) {
my ( $self, $c, $map_id ) = #_;
my $fields = $c->model('DB::Map')->find($map_id);
my $map_file = $fields->get_column('map_file');
$c->res->body("<appropriate URL path to document>/$map_file");
}
This will get your application out of the document handling business, trim down your controller, and allow your web server to do what it does best - serve documents.

Related

(CEP/ExtendScript) Is it possible to include a JSX file from a server?

I am developing an extension for InDesign and I would like to store the jsx file on a server. This would allow me to update the plugin if I change something in the jsx without the user having to re-download the extension.
I tried to directly do an include in the jsx that is mentioned in the manifest to try to point to the real jsx like this:
local-index.jsx :
//#include "https://server-name/adobe/addins/extendscript/server-index.jsx"
(local-index would only serve as a bridge between JavaScript and
ExtendScript)
(server-index would contain all the methods I use on
the JavaScript side with CSInterface.evalScript();)
It doesn't work and I couldn't find any information on the web. Is it possible or does the jsx file have to be local ?
Thanks in advance !
You can make AJAX request in local JS to retrieve JSX string from server
See example below
Server side PHP code be like:
<?php
//JSX Code
echo
"
alert ('Hello From Server');
file = new File('~/Desktop/fromServer.txt');
file.open('w');
file.write('Hi');
file.close();
";
//OR JSXBIN Code
//Use eval and remove line breaks from JSXBIN String
echo "eval('#JSXBIN#ES#2.0#MyBbyBn0AFJAnA.....')";
?>
JS code client side:
$.ajax({
type: "GET",
cache:false,
url: URL,
complete: function (Res) {
scr = Res.responseText;
csInterface.evalScript(scr);
},
async: false //For Synchronous Excecution
});

return PDF Doc via post via jquery/javascript

I am working in Spring 3, Java, JSP, javascript, and jquery, using Ajax occasionally. I have server functions that generate a PDF; I have a new requirement to show a "preview" of a PDF document.
I have code that generates the PDF document, that works fine. I can show it by hacking my source to display it in the place we normally show the un-watermarked completed document, so I know the generation of the PDF is working.
What I now want to do is display that PDF in its own tab as the result of clicking on a button (or link) on our web page. There are a few restrictions:
I have a bunch of data to pass up to the controller from the web page, data that it needs to generate the PDF. We have code that does this through a POST method, and use Ajax to post the necessary data.
It would be inconvenient for the PDF to show up in the same window as the button clicked to show the PDF; a popup asking if the user wants to download or view elsewhere is fine. The users aren't sophisticated enough to depend on theiri knowledge of the 'back' button here. So we want the PDF to show up elsewhere, preferably on another tab in the window but another entire window would be ok.
I have the following in my controller at the moment:
response.setContentLength(pdfGenerated.length);
response.setContentType("application/pdf");
response.setHeader("Expires", "0");
response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
response.setHeader("Pragma", "public");
response.setHeader("Content-Disposition", "attachment;filename=\"Preview.pdf\"");
ServletOutputStream out = response.getOutputStream();
out.write(pdfGenerated); // (encodedPdf);
out.flush();
out.close();
The ajax call looks like this:
$("#generatePDFPreview").live("click", function() {
var gridData = getCorrectedGridData();
var valid = validateContractContent(gridData);
if (valid) {
// the call below saves the contract data and then generates its PDF
$.ajax({
url: getModelObject("generatePDFPreviewURL")
,type:'POST'
,data: {'editedContents':JSON.stringify(gridData)}
,datatype: "application/pdf"
,async: false
,success: function(data) {
if(data != null && data.length>0 && data != "Error") {
//data must be contract id...use it to build the complete URL.
//window.location.href = getModelObject("deliveryScreenURL") + data;
window.open("data:application/pdf;base64, " + data);
} else {
alert("PDF preview not generated...Data returned is not ok. Please try again or contact Sales Support.");
}
}
});
}
});
I have tried different things here; I have left off the 'success' function entirely; I have tried encoding the data (base64) and returning that, and using data:application/pdf, etc., but that failed -- I have some evidence that the PDF data was too long for this, but am not sure (it was 85k-90k, the URL string stopped at something like 32784).
I am not worried about whether my user has the PDF reader installed. They must have it installed to use this and other parts of the application.
It is frustrating to be so close; all evidence is that we have most of the pieces in place, it's should just be a matter of telling the browser that we want it to use the PDF Reader to handle these bytes.
Can someone point us to a method, or point out what's wrong with what we've got now?

PHP Get Rendered Javascript Page

I'm developing application using AngularJS. Everything seems to be nice until I meet something that leads me to headache: SEO.
From many references, I found out that AJAX content crawled and indexed by Google bot or Bing bot 'is not that easy' since the crawlers don't render Javascript.
Currently I need a solution using PHP. I use PHP Slim Framework so my main file is index.php which contains function to echo the content of my index.html. My question is:
Is it possible to make a snapshot of rendered Javascript in HTML?
My strategy is:
If the request query string contains _escaped_fragment_, the application will generate a snapshot and give that snapshot as response instead of the exact file.
Any help would be appreciated. Thanks.
After plenty of times searching and researching, I finally managed to solve my problem by mixing PHP with PhantomJS (version 2.0). I use exec() function in PHP to run phantomJS and create Javascript file to take get the content of the targeted URL. Here are the snippets:
index.php
// Let's assume that you have a bin folder under your root folder directory which contains phantomjs.exe and content.js
$script = __DIR__ ."/bin/content.js";
$target = "http://www.kincir.com"; // target URL
$cmd = __DIR__."/bin/phantomjs.exe $script $target";
exec($cmd, $output);
return implode("", $output);
content.js
var webPage = require('webpage');
var system = require('system');
var page = webPage.create();
var url = system.args[1]; // This will get the second argument from $cmd, in this example, it will be the value of $target on index.php which is "http://www.kincir.com"
page.open(url, function (status) {
page.onLoadFinished = function () { // Make sure to return the content of the page once the page is finish loaded
var content = page.content;
console.log(content);
phantom.exit();
};
});
I recently published a project that gives PHP access to a browser. Get it here: https://github.com/merlinthemagic/MTS. It also relies on PhantomJS.
After downloading and setup you would simply use the following code:
$myUrl = "http://www.example.com";
$windowObj = \MTS\Factories::getDevices()->getLocalHost()->getBrowser('phantomjs')->getNewWindow($myUrl);
//now you can either retrive the DOM and parse it, like this:
$domData = $windowObj->getDom();
//this project also lets you manipulate the live page. Click, fill forms, submit etc.

Modify <div> container on click of a button, insert HTML from GET request

Prerequisites
I have a Website, that displays a page with an input and a button. On the other end is a server that exposes a very basic HTTP API. The API is called like this:
http://127.0.0.1/api/arg1/arg2/arg3
where argX are the arguments. It returns raw HTML. This HTML code needs to be inserted into the Website (another domain). There is a
<div id="container5"></div>
on the website. The HTML needs to be inserted into this container. The code returned by the API is specifically made to be inserted into this container, as it uses CSS classes and scripts from the website, i.e.: the code is not valid for it self.
The Goal
Here is what I have: I've got the API to return what I want, and I got a small JavaScript to run on the website to change the contents of the container:
var element = document.getElementById("container5");
element.innerHTML = "New Contents";
This works so far. Now I need a way to get the HTML from the API to the page. By reading numerous SO questions, it quickly became clear that reading HTML from another URL is close to impossible in JavaScript, due to security constraints.
Is there an easy way to do this with JavaScript or do I need rethink the whole process somehow? One last constraint on my side is that I can only insert JS into the website, I can't - for example - upload a new file to the server.
Edit 1: Workaround!
I solved this for me by using a PHP intermediate file on the requesting server:
<?php
echo file_get_contents('http://example.com');
?>
This will generate a site using the HTML content of any URL. Now the requesting site can read this by using JavaScript:
var getHTML = function ( url, callback ) {
// Feature detection
if ( !window.XMLHttpRequest ) return;
// Create new request
var xhr = new XMLHttpRequest();
// Setup callback
xhr.onload = function() {
if ( callback && typeof( callback ) === 'function' ) {
callback( this.responseXML );
}
}
// Get the HTML
xhr.open( 'GET', url );
xhr.responseType = 'document';
xhr.send();
};
This modifies any element:
var element = document.getElementById("resultpage");
getHTML( 'http://localserver.org/test.php', function (response) {
element.innerHTML = response.documentElement.innerHTML;
});
Checkout CORS https://en.wikipedia.org/wiki/Cross-origin_resource_sharing
also JSONP in same article.

Ajax, asp.net mvc3 routes and relative urls

I have an ASP.NET MVC3 application published to a url like this:
http://servername.com/Applications/ApplicationName/
In my code, I am using jquery ajax requests like this:
$.get(('a/b/c'), function (data) {}, "json");
When I run the application locally, the ajax request goes directly to the correct page (being an mvc route) because the local page ends with a "/" (localhost/a/b/c).
However, when I publish to http://servername.com/Applications/ApplicationName/, the trailing "/" is not always present. The url could be http://servername.com/Applications/ApplicationName, which then causes the ajax request to try to load http://servername.com/Applications/ApplicationNamea/b/c, which fails for obvious reasons.
I have already looked into rewriting the url to append a trailing slash, but A) It didn't work, and B) I feel like it's a poor solution to the problem, and that it would be better to configure the javascript urls to work properly regardless of the local folder setup.
I did try "../a/b/c" and "/a/b/c", but neither seemed to work.
Thanks in advance for the help!
Personally I tend to use a global variable of the relative URL of the server in my view like:
var BASE_URL = '#Url.Content("~/")';
Then you can do things like :
$.get(BASE_URL + 'a/b/c'), function (data) {}, "json");
I would like to add that if you want it to be totally global, you could add it to your /Views/Shared/_Layout.cshtml instead.
I ran into the same problem, and ended up creating two JavaScript functions that mirror the functionality of the MVC Url helper methods Url.Action and Url.Content. The functions are defined in the _Layout.cshtml file, so are available on all views, and work regardless of whether the application is in the root of the localhost or in a subfolder of a server.
<script type="text/javascript">
function UrlAction(action, controller) {
var url = ('#Url.Action("--Action--","--Controller--")').replace("--Action--", action).replace("--Controller--", controller);
return url;
}
function UrlContent(url) {
var path = "#Url.Content("~/--file--")";
path = path.replace("--file--", url.replace('~/', ''));
return path;
}
</script>
These can then be called like so:
var url = UrlAction('AvailableAssetClasses', 'Assessment');
var url2 = UrlContent('~/Images/calendar.gif');
Always use Url helpers when generating urls in an ASP.NET MVC application and never hardcode them. So if this script is directly inside the view:
<script type="text/javascript">
var url = '#Url.Action("a", "b")';
$.get(url, function (data) {}, "json");
</script>
And if this script is inside a separate javascript file (as it should be) where you don't have access to server side helpers, you could simply put the url in some related DOM element. For example using HTML5 data-* attributes:
<div data-url="#Url.Action("a", "b")" id="foo">Click me</div>
and then in your javascript file:
$('#foo').click(function() {
var url = $(this).data('url');
$.get(url, function (data) {}, "json");
});
and if you are unobtrusively AJAXifying an anchor or a form, well, you already have the url:
$('a#someAnchor').click(function() {
var url = this.href;
$.get(url, function (data) {}, "json");
return false;
});

Categories