I'm using jQuery FileTree. After a file upload via javascript ajax (old school javascript xmlhttp request, not jQuery), I invoke the fileTree using the following code:
$('#jstree').fileTree({
script: '/ajax/file_tree2/' + path,
multiFolder: true,
expandSpeed: 250,
collapseSpeed: 250
});
...which produces a nice graphic file tree that I can click around in (the path variable is the new folder, being used as a URI segment variable, and I've simply copied the server-side connector jQueryFileTree.php code into a public function in a CodeIgniter controller class. This is extra information that I don't think has anything to do with the problem, just FYI).
But, for some reason when I make a second call by uploading a new file (without having to reload the page), the file tree doesn't update or refresh. I want to refresh the tree structure when I upload new files for different folders.
I've tried to clear the #jstree element itself, using a loader gif:
$('#jstree').html('<img src=\"'+$("#base_url").html()+'/assets_/images/loading/loading36.gif\" />');
...or even just clearing the html:
$('#jstree').html('');
I've tried commands that are part of other widget-type libraries, like 'destroy' or 'refresh':
$('#jstree').fileTree.destroy();
$('#jstree').fileTree({
refresh: true,
script: '/ajax/file_tree2/' + path,
multiFolder: true,
expandSpeed: 250,
collapseSpeed: 250
});
These either do nothing or return a js error.
I downloaded the raw source of v2.1.4 (467904a3ab5c13df094ffe01ddb0d0fea24c5d6a) and modified line 203 from:
if (!data) {
to
if (!data || (Object.prototype.toString.call(args) === '[object Object]' && args.reload)) {
Now, if I want to reload the fileTree, I just pass "reload: true" in the arguments array.
Related
I'm using EPUB.js and Vue to render an Epub. I want to display the cover images of several epub books so users can click one to then see the whole book.
There's no documentation on how to do this, but there are several methods that indicate that this should be possible.
First off, there's Book.coverUrl() method.
Note that I'm setting an img src property equal to bookCoverSrc in the Vue template. Setting this.bookCoverSrc will automatically update the src of the img tag and cause an image to display (if the src is valid / resolves).
this.book = new Epub(this.epubUrl, {});
this.book.ready.then(() => {
this.book.coverUrl().then((url) => {
this.bookCoverSrc = url;
});
})
The above doesn't work. url is undefined.
Weirdly, there appears to be a cover property directly on book. So, I try:
this.book = new Epub(this.epubUrl, {});
this.book.ready.then(() => {
this.coverSrc = this.book.cover;
});
this.book.cover resolves to OEBPS/#public#vhost#g#gutenberg#html#files#49010#49010-h#images#cover.jpg, so at least locally when I set it to a src results in a request to http://localhost:8080/OEBPS/#public#vhost#g#gutenberg#html#files#49010#49010-h#images#cover.jpg, which 200s but returns no content. Probably a quirk of webpack-dev-server to 200 on that, but if I page through sources in Chrome dev tools I also don't see any indicate that such a URL should resolve.
So, docs not helping. I googled and found this github question from 2015. Their code is like
$("#cover").attr("src", Book.store.urlCache[Book.cover]);
Interesting, nothing in the docks about Book.store.urlCache. As expected, urlCache is undefined, though book.store exists. I don't see anything on there that can help me display a cover image though.
Using epub.js, how can I display a cover image of an Epub file? Note that simply rendering the first "page" of the Epub file (which is usually the cover image) doesn't solve my problem, as I'd like to list a couple epub files' cover images.
Note also that I believe the epub files I'm using do have cover images. The files are Aesop's Fables and Irish Wonders.
EDIT: It's possible I need to use Book.load on the url provided by book.cover first. I did so and tried to console.log it, but it's a massive blog of weirdly encoded text that looks something like:
����
So I think it's an image straight up, and I need to find a way to get that onto the Document somehow?
EDIT2: that big blobby blob is type: string, and I can't atob() or btoa() it.
EDIT3: Just fetching the url provided by this.book.cover returns my index.html, default behavior for webpack-dev-server when it doesn't know what else to do.
EDIT4: Below is the code for book.coverUrl from epub.js
key: "coverUrl",
value: function coverUrl() {
var _this9 = this;
var retrieved = this.loaded.cover.then(function (url) {
if (_this9.archived) {
// return this.archive.createUrl(this.cover);
return _this9.resources.get(_this9.cover);
} else {
return _this9.cover;
}
});
return retrieved;
}
If I use this.archive.createUrl(this.cover) instead of this.resources.get, I actually get a functional URL, that looks like blob:http://localhost:8080/9a3447b7-5cc8-4cfd-8608-d963910cb5f5. I'll try getting that out into src and see what happens.
The reason this was happening to me was because the functioning line of code in the coverUrl function was commented out in the source library epub.js, and a non-functioning line of code was written instead.
So, I had to copy down the entire library, uncomment the good code and delete the bad. Now the function works as it should.
To do so, clone down the entire epub.js project. Copy over the dependencies in that project's package.json to your own. Then, take the src, lib, and libs folders and copy them somewhere into your project. Find a way to disable eslint for the location you put these folders into because the project uses TAB characters for spacing which caused my terminal to hang due to ESLINT exploding.
npm install so you have your and epub.js dependencies in your node_modules.
Open book.js. Uncomment line 661 which looks like
return this.archive.createUrl(this.cover);
and comment out line 662 which looks like
// return this.resources.get(this.cover);
Now you can display an image by setting an img tag's src attribute to the URL returned by book.coverUrl().
this.book = new Epub(this.epubUrl, {});
this.book.ready.then(() => {
this.book.coverUrl().then((url) => {
this.bookCoverSrc = url;
});
})
I have some Ajax that makes a Cross Origin Resource call
$("#inductive1").click(function (event) {
$.post(
"https://www.mysite.co.uk/folder/tests/Inductive/Test1/index.phtml",
function (data) {
$('.stage2').html(data);
}
);
});
within the index.phtml file I have some Script that calls exam.xml
Script inside index.phtml
( function($, undefined) {
$(function() {
var test = new Test({
testName: "Inductive Test 1",
dataURL : "/getresultshtml.php",
sendEmailURL: "/sendresultsbyemail.php",
contentFolder : "./",
solutionURL: "../../../content/f/id/10/",
userID: 0,
courseItemID: 25,
XMLFile: "exam.xml",
isStandalone: false
});
test.start();
});
}(jQuery));
However the xml file is trying to be called from the other server,
EG
https://server1.com/exam.xml
it should be
https://myserver.com/exam.xml
I have tried changing the JS to direct path as in
XMLFile: "htttps:/myserver.com/exam.xml"
but it is being read as
https://server1.com/myserver.com/exam.xml
how do I change the javascript so that it changes the root URL to myserver.com and not server1.com
Looks like some plugin you are using is changing document's base URL,
you can try putting this at the beginning of index.phtml
<base href="https://myserver.com">
If that doesn't work you might need to dynamically change the base property through JavaScript just before the ajax call
document.write("<base href='http://myserver.com/'>");
I'm not sure how the Test will use the XMLFile. But per the jquery.ajax documentation, passing the complete url (with the protocol) in the url parameter should be enough.
Maybe the test.start() is doing some manipulation?
The only other possible issue that I found is that you are declaring your protocol with an extra t and a missing /
XMLFile: "htttps:/myserver.com/exam.xml"
Try using
XMLFile: "https://myserver.com/exam.xml"
Summary
I am attempting to find out why the wl.download function will not download more than one file even though the Microsoft examples seem to indicate that they can.
And, the code seems to be called for each file you attempt to download, but only the one file is actually downloaded.
Details
Here are the details of how you can see this problem which I've tried in IE 11.x and Chrome 30.x
If you will kindly go to :
http://isdk.dev.live.com/dev/isdk/ISDK.aspx?category=scenarioGroup_skyDrive&index=0
You will be able to run an example app which allows you to download files from your skydrive.
Note: the app does require you to allow the app to access your skydrive.
Once you get there you'll see code that looks like this on the right side of the page:
Alter One Value: select:
You need to alter one value: Change the
select: 'single'
to
select: 'multi'
which will allow you to select numerous files to download to your computer. If you do not make that one change then you won't be able to choose more than one file in the File dialog.
Click the Run Button to Start
Next, you'll see a [Run] button to start the app (above the code sample).
Go ahead and click that button.
Pick Files For Download
After that just traverse through your skydrive files and choose more than one in a folder and click the [Open] button. At that point, you will see one of the files actually downloads, and a number of file names are displayed in the bottom (output) section of the example web page.
My Questions
Why is it that the others do not download, even though wl.download is called in the loop, just as the console.log is called in the loop?
Is this a known limitation of the browser?
Is this a known bug in skydrive API?
Is this just a bug in the example code?
The problem here is that the call to wl.download({ "path": file.id + "/content" }) stores some internal state (among other things, the file being downloaded and the current status thereof). By looping over the list of files, that state is in fact overwritten with each call. When I tried downloading three text files at once, it was always the last one that was actually downloaded and never the first two.
The difficulty here is that the downloads are executed in the traditional fashion, whereby the server adds Content-Disposition: attachment to the response headers to force the browser to download the file. Because of this, it is not possible to receive notification of any kind when the download has actually completed, meaning that you can't perform the downloads serially to get around the state problem.
One approach that I thought might work is inspired by this question. According to the documentation, we can get a download link to a file if we append /content?suppress_redirects=true to its id. Using this approach, we can set the src property of an IFrame and download the file that way. This works OK, but it will only force a download for file types that the browser can't natively display (zip files, Exe files, etc.) due to the lack of the Content-Disposition: attachment response header.
The following is what I used in the Interactive Live SDK.
WL.init({ client_id: clientId, redirect_uri: redirectUri });
WL.login({ "scope": "wl.skydrive wl.signin" }).then(
function(response) {
openFromSkyDrive();
},
function(response) {
log("Failed to authenticate.");
}
);
function openFromSkyDrive() {
WL.fileDialog({
mode: 'open',
select: 'multi'
}).then(
function(response) {
log("The following file is being downloaded:");
log("");
var files = response.data.files;
for (var i = 0; i < files.length; i++) {
var file = files[i];
log(file.name);
WL.api({
path: file.id + "/content?suppress_redirects=true",
method: "GET"
}).then(
function (response) {
var iframe = document.createElement("iframe");
iframe.src = response.location;
iframe.style.display = "none";
document.body.appendChild(iframe);
},
function (responseFailed) {
log("Error calling API: " + responseFailed.error.message);
}
);
}
},
function(errorResponse) {
log("WL.fileDialog errorResponse = " + JSON.stringify(errorResponse));
}
);
}
function log(message) {
var child = document.createTextNode(message);
var parent = document.getElementById('JsOutputDiv') || document.body;
parent.appendChild(child);
parent.appendChild(document.createElement("br"));
}
Did you try to bind some events to the WL.download() method? According to the documentation:
The WL.download method accepts only one parameter:
The required path parameter specifies the unique SkyDrive file ID of the file to download.
If the WL.download method call is unsuccessful, you can use its then method's onError parameter to report the error. In this case, the WL.download doesn't support the onSuccess and onProgress parameters. If the WL.download method call is successful, the user experience for actually downloading the files will differ based on the type of web browser in use.
Perhaps you are getting some errors in your log to identify the problem.
For me, one suggestion without having checked the documentation, I can think of the fact that you are not waiting for each download to end. Why not change your loop in such a manner that you call WL.download() only if you know no other download is currently running ( like calling the next WL.download only in the success/complete event ):
WL.download({ "path": file.id + "/content" }).then(
function (response) {
window.console && console.log("File downloaded.");
//call the next WL.download() here <!-----------------
},
function (responseFailed) {
window.console && console.log( "Error downloading file: " + responseFailed.error.message);
}
);
I have a simple html file in which there's javascript code referring to google charts.
The code I use is this (I'll show the important part):
function drawChart(){
var data = google.visualization
.arrayToDataTable([ ['Label', 'Value'],['Temp', 22.75],]);
// etc...
}
I use a bash command (sed) to replace that 22.75 value with a new one from the last line of a .txt file. However, this throws some errors which I haven't been able to neither correct nor ever identify.
So is there any javascript code that takes that file, extracts the last value and simply displays it on the right place of the code?
UPDATE:
Sorry for the lack of info in this question, I really appreciate all the people that took the time on reading my question. I'll try to fill with more information in the next minutes.
I am able to extract the last line of the .txt file, extract the value on the right part of the '-' symbol and store it in a variable. Then that value is taken to update the html file with a sed command. The error comes when the value is updated but with no value. I guess that happends due to a failed record of temperature in the txt file, then the extracted value is a null. Finally is the html fiel with javascrit code happens to be like this:
(...)['Temp', ],]);
Then the updater can't update the value since due to the way that sed command is written I guess there's no way that it can detect a no-number-value in there. So the html remains without a value all the time.
TXT File structure:
(...)
20:25:03-23.312
20:26:02-23.312
20:27:03-23.375
20:28:03-23.375
20:29:02-23.375
20:30:02-23.312
Bash script:
# (...code...)
lastRecord=`cat /home/pi/scripts/temp_control/logs/"$today".log | awk 'END{print}'`
function rightNow {
lastTemp=`echo $lastRecord | cut -d'-' -f2`
timeOfTemp=`echo $lastRecord | cut -d'-' -f1` # Not used yet
#Command used to update
sed -i "s/['Temp', [0-9]\{1,2\}.[0-9]\{1,3\}]/$lastTemp]/" /var/www/rightnow.html
}
rightNow
You cud get your file just like any other ajax request.
Using javascript
var request = new XMLHttpRequest();
request.open('GET', 'public_path_to_file.txt', false);
request.send();
var textFileContent = request.responseText
Using jQuery
var textFileContent;
$.get('public_path_to_file.txt', function(data) {
textFileContent = data;
});
Whats left is to get the right part from textFileContent. Dependent of the structure of the file we can do this in different ways. Without an example file you are on your own but here is some examples.
If you need the last line
var lines = textFileContent.split("\n");
var lastLine = lines[lines.length - 1];
If you need to use regex
var regex = //* some regex to get your content*//gm;
var result = regex.exec(textFileContent);
// result should now the content who matches your regex
First I'll assume that you ultimately want to read a local file with your browser and your current workflow is something like a local 'bash-script' that
first updates/modifies an inline piece of javascript (inside a locally stored html
file) with the last occurring value retrieved from a local txt-file (using sed)
opens the (just modified html-) file (via commandline) inside a common browser.
Then I assume the sed-route once worked but now doesn't work anymore (probably because the html file has changed?) and now you'd like the inline javascript (in the html file) to fetch that value from the textfile itself and subsequently use it (thus without the need for the 'bash-script'/sed solution.
Thus, the answer (based on above assumptions) to your final question: 'is there any javascript code that takes that file, extracts the last value and simply displays it on the right place of the code?', depends on your final requirement:
are you ok with a file-input where you select the text-file every time you view the html-file?
If your answer is YES, then, (depending on the browser you use) you can read a local file (and work your magic on it's contents).
In modern browsers, using the File API (which was added to the DOM in HTML5) it's now possible for web content to ask the user to select local files, then read the contents of those files.
For example, using FireFox's 'FileReader' you could do:
html:
<input type="file" id="fileinput" multiple />
javascript:
function readAllFiles(evt){
var files = evt.target.files, i = 0, r, f;
if(files){
for(; f = files[i++]; ){
r = new FileReader();
r.onload = (function(f){
return function(e){
alert(e.target.result);
};
})(f);
r.readAsText(f);
}
} else {
alert("Error loading files");
}
}
document.getElementById('fileinput')
.addEventListener('change', readAllFiles, false);
Note that for accessing local files in Chrome you must start Chrome with this switch: chrome --disable-web-security
However,
if the answer is NO (so you want to specify the file, and more importantly it's path, inside the 'code', so you don't have to select the text-file every time your local app runs) then you (usually) can't (because you can't get/set the path, thank the great maker)...
Unless you choose a specific older/unpatched browser (specifically for this task) where you know of a (hack) way to do this anyway (like the IE xml vulnerability or the XMLHTTP vulnerability or etc... you get the picture..).
Some alternative solutions (that don't require you to select the correct textfile over and over again)
Setup a fullblown web (LAMP) server (to use the XMLHttpRequest way as used in aross answer, but this might feel like shooting at a mosquito with a cannon..)
Explore different script languages (but effectively still do the same as your now broken sed-solution)
Combine 1 and 2, choosing from php (the latest version has a small webserver included, you might start/stop it when needed (even in the bash-script workflow) OR using node.js (which is 'javascript' and where you can program/control a small task-specific server in just a couple of lines).
Hope this helps!
Update:
Based on your updated question, comments and request for recommendation, I'd like to suggest to use PHP to dynamically fetch the value from your log txt file and have it generate your html code with inline javascript on the fly (every time you visit the page).
The browser will never see the php code, only what php inserted to your page (in this example the last found value or 0).
You'd rename the rightnow.html file to rightnow.php and modify it (something like) this:
<!DOCTYPE html>
<html><head>
<!-- your header code -->
<script type="text/javascript">
//parts of your javascript
<?php // start php script
$logFile= '/pathToYour/logFile.log'; // <-Modify
if( $fp= #fopen($logFile, "r") ){ // if logfile succesfully opened,
fseek($fp, -30, SEEK_END); // set pointer 30 chars from EOF
$val= array_pop(explode("-", rtrim(fread($fp, 30)))); //get last value
fclose($fp); // close file
}
?> // end php script
function drawChart(){
var data=google.visualization
.arrayToDataTable([ ['Label', 'Value'],
['Temp', <?php echo $val? $val : "0"; ?>],
]); // ^php above inserts value or 0
// etc...
}
//parts of your javascript
</script>
</head><body>
<!-- your body code -->
</body></html>
Note that fopen in combination with setting the filepointer via fseek and sequentially fread-ing from the pointer to EOF does not load the complete logfile (60min * 24hour=1440 lines of 16 bytes=22.5kB at the end of the day) into memory (good for this purpose), but only the last 30 chars (as in this example).
The variable to your logfile and path must still be modified to your situation (I don't know the format of your $today variable).
Depending on your further needs you might want to perform some extra checks/logic on the array of values that explode returns (instead of popping the last value). Or what about modifying the html a little so you could also include the last temperature's time reading, etc. (But this tested piece of code should get you started and explains the procedure of going the php way).
Update:
Since you have chosen to place the last known value of your logfile as in textfile placed inside your public www-root (with a bash script I assume, every minute of the day?), you can now indeed go the 'ajax' way, as answered by aross!
However I want to hint that the code/solutions in all current answers here could be mixed (since you now also have ajax working): instead of ajax-ing (loading) a txt file, you could have php fetch and send this value to the browser on-the-fly/on-demand!
So, instead of requesting http://url_to_my_rpi/file_to_download.txt, you could request http://url_to_my_rpi/read_last_temperature.PHP which should fetch the last known value out of the log-file (set proper security/access) and send it to the browser (set proper headers), just like your text-file did. You wouldn't have to change anything in the html/javascript except the url you request.
The advantage would be (depending on how your current bash-scripts works) that your PI now only does this 'work' (of getting the last value of your logfile) when you are viewing your monitor-page. And that you are not writing that file in your www-root every minute of every day (as I suspect).
The solution achieved, finally, was like this:
I did it with a jQuery statement and reusing the javascript code of Google Charts.
First I added javascript and jQuery tags in the html file:
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script type='text/javascript' src='https://www.google.com/jsapi'></script>
Then I merged jquery code and javascript code that I had in one script:
<script type='text/javascript'>
// Needed this var so that I could use it in other places of the code
var t;
jQuery.get('http://url_to_my_rpi/file_to_download.txt',function(data){
console.log(data)
t=data;
},'text');
google.load('visualization', '1', {packages:['gauge']});
google.setOnLoadCallback(drawChart);
function drawChart() {
t=eval(t);
var data = google.visualization.arrayToDataTable([
['Label', 'Value'],
['Temp', t],]);
// (... more javascript with Google Charts options, display parameters..)
</script>
Finally, and even if it's not listed as the main question, be sure to enable *mod_headers* on your apache and add Header set to apache2.conf file (In my case: /etc/apache2/apache2.conf)
1) Enable the module:
a2enmod headers
2) Add the line on your configuration file
Header set Access-Control-Allow-Origin "*"
3) Restart apache 2
4) In case the 3 steps above didn't work, follow the instrcutions by entering in this website or reinstall apache2.
When I'm using controller function with parameters the rendered view just seems to forget every included .js files.
public function view($id = null) {
if(!$id) {
throw new NotFoundException(__('Invalid post'));
}
$post = $this->Post->findById($id);
if(!$post) {
throw new NotFoundException(__('Invalid post'));
}
$this->set('post', $post);
}
If I take parameters away and put variable '$id = 1' on function the view with postID 1 renders okay in 'posts/view'.
I included javascript files to default.ctp in traditional way:
echo "script type='text/javascript' SRC='../js/jquery-1.9.1.min.js'></script>";);
(it includes '<' but this text editor won't me type it for safety reasons I guess)
I don't have knowledge about 'js helpers' of cakePHP. Can't I use javascript in traditional way?
Site renders okay in every other view (e.g. posts/add) and .js files are included in source code of 'posts/view/1'
The problem
You're using relative paths to the javascript;
<script src='../js/jquery-1.9.1.min.js'></script>
In this url, ../ means '1 directory up from the current location`, so when you're currently visiting this URL;
http://mysite.com/home/
Then your browser will correctly try to load the script from;
http://mysite.com/js/jquery-1.9.1.min.js
However, if you're visiting this url;
http://mysite.com/home/and/some/more/
Then the browser will look for the JavaScript here:
http://mysite.com/home/and/some/js/jquery-1.9.1.min.js
How to fix the problem
Use absolute paths for all 'assets' (CSS, JavaScript, Images);
src='/js/jquery-1.9.1.min.js'
Output the script-tags using CakePHP Helpers (after all, that's what they are meant for: to simplify your work :), e.g. echo $this->Html->script('jquery-1.9.1.min');