windows 8 javascript app print fragment doesnt print picture from a <div> - javascript

I have this problem: ( i will attach code below ) I have a split screen template windows 8 app. In the right side of the screen I have a recipe with a picture in the top part. and a description in lower part. Both these 2 parts are in the same block . The picture and the text are shown from an array in data.js file. For example the picture is shown from var background:"images\recipes\picture1.jpg" and the description from var description:"example text bla bla bla". I create a document fragment that i clone and send it to print. Everything prints right, except the PICTURE. I get an X icon instead of the picture. Now I will write all the code I use for this. I have no ideea what is wrong. Everything is right in an example I follow. There it works, mine not.
Ready function add-ons:
document.getElementById("Print").addEventListener("click", PrintButtonHandler, false);
// Register for Print Contract
registerForPrintContract();
All code regarding printing:
function registerForPrintContract() {
var printManager = Windows.Graphics.Printing.PrintManager.getForCurrentView();
printManager.onprinttaskrequested = onPrintTaskRequested;
WinJS.log && WinJS.log("Print Contract registered. Use Print button to print.", "sample", "status");
}
/// <summary>
/// Print event handler for printing via the PrintManager API. The user has to manually invoke
/// the print charm after this function is executed.
/// </summary>
/// <param name="printEvent" type="Windows.Graphics.Printing.PrintTaskRequest">
/// The event containing the print task request object.
/// </param>
function onPrintTaskRequested(printEvent) {
var printTask = printEvent.request.createPrintTask("Print part", function (args) {
var frag = document.createDocumentFragment();
frag.appendChild(document.getElementById("print").cloneNode(true));
args.setSource(MSApp.getHtmlPrintDocumentSource(frag));
// Register the handler for print task completion event
printTask.oncompleted = onPrintTaskCompleted;
});
}
/// <summary>
/// Print Task event handler is invoked when the print job is completed.
/// </summary>
/// <param name="printTaskCompletionEvent" type="Windows.Graphics.Printing.PrintTaskCompleted">
/// The event containing the print task completion object.
/// </param>
function onPrintTaskCompleted(printTaskCompletionEvent) {
// Notify the user about the failure
if (printTaskCompletionEvent.completion === Windows.Graphics.Printing.PrintTaskCompletion.failed) {
WinJS.log && WinJS.log("Failed to print.", "sample", "error");
}
}
function PrintButtonHandler() {
// Optionally, functions to be executed immediately before and after printing can be configured as following:
window.document.body.onbeforeprint = beforePrint;
window.document.body.onafterprint = afterPrint;
// If the print contract is registered, the print experience is invoked.
Windows.Graphics.Printing.PrintManager.showPrintUIAsync();
}
var page = WinJS.UI.Pages.define("/page/split.html", {
ready: function (element, options) {
var dataTransferManager = Windows.ApplicationModel.DataTransfer.DataTransferManager.getForCurrentView();
dataTransferManager.addEventListener("datarequested", dataRequested);
document.getElementById("share").addEventListener("click", showShareUI, false);
},
unload: function () {
var dataTransferManager = Windows.ApplicationModel.DataTransfer.DataTransferManager.getForCurrentView();
dataTransferManager.removeEventListener("datarequested", dataRequested);
}
});
function dataRequested(e) {
var request = e.request;
// Title is required
var dataPackageTitle = document.getElementById("titluReteta").value;
if ((typeof dataPackageTitle === "string") && (dataPackageTitle !== "")) {
var range = document.createRange();
range.selectNode(document.getElementById("print"));
request.data = MSApp.createDataPackage(range);
request.data.properties.title = dataPackageTitle;
// The HTML fragment we are using has an image tag that references a local file accessible only to this application.
// To make sure that target application can render this image, we need to populate a resourceMap as part of the share operation data
// We use the image's relative src property as the key to the resourceMap item we're adding
var path = document.getElementById("print").getAttribute("src");
var imageUri = new Windows.Foundation.Uri(path);
var streamReference = Windows.Storage.Streams.RandomAccessStreamReference.createFromUri(imageUri);
request.data.resourceMap[path] = streamReference;
} else {
request.failWithDisplayText(SdkSample.missingTitleError);
}
}
function showShareUI() {
Windows.ApplicationModel.DataTransfer.DataTransferManager.showShareUI();
}
})();
This the code from the page:
</header>
<img class="article-image" src="#" data-win-bind="src: backgroundImage; alt: title" style="border: 10px double #73513B;" />
<div class="article-content" data-win-bind="innerHTML: content"> </div>
</article>
</div>
And the data-win-bind is the picture that doesnt print.
I added this line <link rel="stylesheet" type="text/css" href="/css/print.css" media="print" /> and print.css contains this:
#rootGrid
{
width: 100%;
height: 100%;
display: block;
}
#inputLabel, #outputLabel, #input, #statusMessage
{
display: none;
}
.article
{
border:none;
}
I really need a fast answer if anyone can solve this. I need this project to be send until Friday. And I am clueless, after lots of example I tried to follow. Thank you very much to the guy that will save me!
LE: I tried also a classic inside the description field. The picture appear in the app, but the same result for printing: a big X icon instead of picture.

Resolved by printing entire document with reformating CSS code for showing just what I want to show. Now it captures all pictures with no problem. No answer got for the initial problem with capturing only the picture.

Related

Javascript function works on html onclick but doesn't work html onload [duplicate]

How do you add an onload event to an element?
Can I use:
<div onload="oQuickReply.swap();" ></div>
for this?
No, you can't. The easiest way to make it work would be to put the function call directly after the element
Example:
...
<div id="somid">Some content</div>
<script type="text/javascript">
oQuickReply.swap('somid');
</script>
...
or - even better - just in front of </body>:
...
<script type="text/javascript">
oQuickReply.swap('somid');
</script>
</body>
...so it doesn't block the following content from loading.
You can trigger some js automatically on an IMG element using onerror, and no src.
<img src onerror='alert()'>
The onload event can only be used on the document(body) itself, frames, images, and scripts. In other words, it can be attached to only body and/or each external resource. The div is not an external resource and it's loaded as part of the body, so the onload event doesn't apply there.
onload event it only supports with few tags like listed below.
<body>, <frame>, <iframe>, <img>, <input type="image">, <link>, <script>, <style>
Here the reference for onload event
Try this! And never use trigger twice on div!
You can define function to call before the div tag.
$(function(){
$('div[onload]').trigger('onload');
});
DEMO: jsfiddle
I just want to add here that if any one want to call a function on load event of div & you don't want to use jQuery(due to conflict as in my case) then simply call a function after all the html code or any other code you have written including the function code and
simply call a function .
/* All Other Code*/
-----
------
/* ----At the end ---- */
<script type="text/javascript">
function_name();
</script>
OR
/* All Other Code*/
-----
------
/* ----At the end ---- */
<script type="text/javascript">
function my_func(){
function definition;
}
my_func();
</script>
I needed to have some initialization code run after a chunk of html (template instance) was inserted, and of course I didn't have access to the code that manipulates the template and modifies the DOM. The same idea holds for any partial modification of the DOM by insertion of an html element, usually a <div>.
Some time ago, I did a hack with the onload event of a nearly invisible <img> contained in a <div>, but discovered that a scoped, empty style will also do:
<div .... >
<style scoped="scoped" onload="dosomethingto(this.parentElement);" > </style>
.....
</div>
Update(Jul 15 2017) -
The <style> onload is not supported in last version of IE. Edge does support it, but some users see this as a different browser and stick with IE. The <img> element seems to work better across all browsers.
<div...>
<img onLoad="dosomthing(this.parentElement);" src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" />
...
</div>
To minimize the visual impact and resource usage of the image, use an inline src that keeps it small and transparent.
One comment I feel I need to make about using a <script>is how much harder it is to determine which <div> the script is near, especially in templating where you can't have an identical id in each instance that the template generates. I thought the answer might be document.currentScript, but this is not universally supported. A <script> element cannot determine its own DOM location reliably; a reference to 'this' points to the main window, and is of no help.
I believe it is necessary to settle for using an <img> element, despite being goofy. This might be a hole in the DOM/javascript framework that could use plugging.
Avoid using any interval-based methods (as they are not performant and accurate) and use MutationObserver targeting a parent div of dynamically loaded div for better efficiency.
Update: Here's a handy function I wrote. Use it like this:
onElementLoaded("div.some_class").then(()=>{}).catch(()=>{});
/**
*
* Wait for an HTML element to be loaded like `div`, `span`, `img`, etc.
* ex: `onElementLoaded("div.some_class").then(()=>{}).catch(()=>{})`
* #param {*} elementToObserve wait for this element to load
* #param {*} parentStaticElement (optional) if parent element is not passed then `document` is used
* #return {*} Promise - return promise when `elementToObserve` is loaded
*/
function onElementLoaded(elementToObserve, parentStaticElement) {
const promise = new Promise((resolve, reject) => {
try {
if (document.querySelector(elementToObserve)) {
console.log(`element already present: ${elementToObserve}`);
resolve(true);
return;
}
const parentElement = parentStaticElement
? document.querySelector(parentStaticElement)
: document;
const observer = new MutationObserver((mutationList, obsrvr) => {
const divToCheck = document.querySelector(elementToObserve);
if (divToCheck) {
console.log(`element loaded: ${elementToObserve}`);
obsrvr.disconnect(); // stop observing
resolve(true);
}
});
// start observing for dynamic div
observer.observe(parentElement, {
childList: true,
subtree: true,
});
} catch (e) {
console.log(e);
reject(Error("some issue... promise rejected"));
}
});
return promise;
}
Implementation details:
HTML:
<div class="parent-static-div">
<div class="dynamic-loaded-div">
this div is loaded after DOM ready event
</div>
</div>
JS:
var observer = new MutationObserver(function (mutationList, obsrvr) {
var div_to_check = document.querySelector(".dynamic-loaded-div"); //get div by class
// var div_to_check = document.getElementById('div-id'); //get div by id
console.log("checking for div...");
if (div_to_check) {
console.log("div is loaded now"); // DO YOUR STUFF!
obsrvr.disconnect(); // stop observing
return;
}
});
var parentElement = document.querySelector("parent-static-div"); // use parent div which is already present in DOM to maximise efficiency
// var parentElement = document // if not sure about parent div then just use whole 'document'
// start observing for dynamic div
observer.observe(parentElement, {
// for properties details: https://developer.mozilla.org/en-US/docs/Web/API/MutationObserverInit
childList: true,
subtree: true,
});
we can use MutationObserver to solve the problem in efficient way adding a sample code below
<!DOCTYPE html>
<html>
<head>
<title></title>
<style>
#second{
position: absolute;
width: 100px;
height: 100px;
background-color: #a1a1a1;
}
</style>
</head>
<body>
<div id="first"></div>
<script>
var callthis = function(element){
element.setAttribute("tabIndex",0);
element.focus();
element.onkeydown = handler;
function handler(){
alert("called")
}
}
var observer = new WebKitMutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
for (var i = 0; i < mutation.addedNodes.length; i++)
if(mutation.addedNodes[i].id === "second"){
callthis(mutation.addedNodes[i]);
}
})
});
observer.observe(document.getElementById("first"), { childList: true });
var ele = document.createElement('div');
ele.id = "second"
document.getElementById("first").appendChild(ele);
</script>
</body>
</html>
In November 2019, I am seeking a way to create a (hypothetical) onparse EventListener for <elements> which don't take onload.
The (hypothetical) onparse EventListener must be able to listen for when an element is parsed.
Third Attempt (and Definitive Solution)
I was pretty happy with the Second Attempt below, but it just struck me that I can make the code shorter and simpler, by creating a tailor-made event:
let parseEvent = new Event('parse');
This is the best solution yet.
The example below:
Creates a tailor-made parse Event
Declares a function (which can be run at window.onload or any time) which:
Finds any elements in the document which include the attribute data-onparse
Attaches the parse EventListener to each of those elements
Dispatches the parse Event to each of those elements to execute the Callback
Working Example:
// Create (homemade) parse event
let parseEvent = new Event('parse');
// Create Initialising Function which can be run at any time
const initialiseParseableElements = () => {
// Get all the elements which need to respond to an onparse event
let elementsWithParseEventListener = document.querySelectorAll('[data-onparse]');
// Attach Event Listeners and Dispatch Events
elementsWithParseEventListener.forEach((elementWithParseEventListener) => {
elementWithParseEventListener.addEventListener('parse', updateParseEventTarget, false);
elementWithParseEventListener.dataset.onparsed = elementWithParseEventListener.dataset.onparse;
elementWithParseEventListener.removeAttribute('data-onparse');
elementWithParseEventListener.dispatchEvent(parseEvent);
});
}
// Callback function for the Parse Event Listener
const updateParseEventTarget = (e) => {
switch (e.target.dataset.onparsed) {
case ('update-1') : e.target.textContent = 'My First Updated Heading'; break;
case ('update-2') : e.target.textContent = 'My Second Updated Heading'; break;
case ('update-3') : e.target.textContent = 'My Third Updated Heading'; break;
case ('run-oQuickReply.swap()') : e.target.innerHTML = 'This <code><div></code> is now loaded and the function <code>oQuickReply.swap()</code> will run...'; break;
}
}
// Run Initialising Function
initialiseParseableElements();
let dynamicHeading = document.createElement('h3');
dynamicHeading.textContent = 'Heading Text';
dynamicHeading.dataset.onparse = 'update-3';
setTimeout(() => {
// Add new element to page after time delay
document.body.appendChild(dynamicHeading);
// Re-run Initialising Function
initialiseParseableElements();
}, 3000);
div {
width: 300px;
height: 40px;
padding: 12px;
border: 1px solid rgb(191, 191, 191);
}
h3 {
position: absolute;
top: 0;
right: 0;
}
<h2 data-onparse="update-1">My Heading</h2>
<h2 data-onparse="update-2">My Heading</h2>
<div data-onparse="run-oQuickReply.swap()">
This div hasn't yet loaded and nothing will happen.
</div>
Second Attempt
The First Attempt below (based on #JohnWilliams' brilliant Empty Image Hack) used a hardcoded <img /> and worked.
I thought it ought to be possible to remove the hardcoded <img /> entirely and only dynamically insert it after detecting, in an element which needed to fire an onparse event, an attribute like:
data-onparse="run-oQuickReply.swap()"
It turns out, this works very well indeed.
The example below:
Finds any elements in the document which include the attribute data-onparse
Dynamically generates an <img src /> and appends it to the document, immediately after each of those elements
Fires the onerror EventListener when the rendering engine parses each <img src />
Executes the Callback and removes that dynamically generated <img src /> from the document
Working Example:
// Get all the elements which need to respond to an onparse event
let elementsWithParseEventListener = document.querySelectorAll('[data-onparse]');
// Dynamically create and position an empty <img> after each of those elements
elementsWithParseEventListener.forEach((elementWithParseEventListener) => {
let emptyImage = document.createElement('img');
emptyImage.src = '';
elementWithParseEventListener.parentNode.insertBefore(emptyImage, elementWithParseEventListener.nextElementSibling);
});
// Get all the empty images
let parseEventTriggers = document.querySelectorAll('img[src=""]');
// Callback function for the EventListener below
const updateParseEventTarget = (e) => {
let parseEventTarget = e.target.previousElementSibling;
switch (parseEventTarget.dataset.onparse) {
case ('update-1') : parseEventTarget.textContent = 'My First Updated Heading'; break;
case ('update-2') : parseEventTarget.textContent = 'My Second Updated Heading'; break;
case ('run-oQuickReply.swap()') : parseEventTarget.innerHTML = 'This <code><div></code> is now loaded and the function <code>oQuickReply.swap()</code> will run...'; break;
}
// Remove empty image
e.target.remove();
}
// Add onerror EventListener to all the empty images
parseEventTriggers.forEach((parseEventTrigger) => {
parseEventTrigger.addEventListener('error', updateParseEventTarget, false);
});
div {
width: 300px;
height: 40px;
padding: 12px;
border: 1px solid rgb(191, 191, 191);
}
<h2 data-onparse="update-1">My Heading</h2>
<h2 data-onparse="update-2">My Heading</h2>
<div data-onparse="run-oQuickReply.swap()">
This div hasn't yet loaded and nothing will happen.
</div>
First Attempt
I can build on #JohnWilliams' <img src> hack (on this page, from 2017) - which is, so far, the best approach I have come across.
The example below:
Fires the onerror EventListener when the rendering engine parses <img src />
Executes the Callback and removes the <img src /> from the document
Working Example:
let myHeadingLoadEventTrigger = document.getElementById('my-heading-load-event-trigger');
const updateHeading = (e) => {
let myHeading = e.target.previousElementSibling;
if (true) { // <= CONDITION HERE
myHeading.textContent = 'My Updated Heading';
}
// Modern alternative to document.body.removeChild(e.target);
e.target.remove();
}
myHeadingLoadEventTrigger.addEventListener('error', updateHeading, false);
<h2>My Heading</h2>
<img id="my-heading-load-event-trigger" src />
use an iframe and hide it iframe works like a body tag
<!DOCTYPE html>
<html>
<body>
<iframe style="display:none" onload="myFunction()" src="http://www.w3schools.com"></iframe>
<p id="demo"></p>
<script>
function myFunction() {
document.getElementById("demo").innerHTML = "Iframe is loaded.";
}
</script>
</body>
</html>
Since the onload event is only supported on a few elements, you have to use an alternate method.
You can use a MutationObserver for this:
const trackElement = element => {
let present = false;
const checkIfPresent = () => {
if (document.body.contains(element)) {
if (!present) {
console.log('in DOM:', element);
}
present = true;
} else if (present) {
present = false;
console.log('Not in DOM');
}
};
const observer = new MutationObserver(checkIfPresent);
observer.observe(document.body, { childList: true });
checkIfPresent();
return observer;
};
const element = document.querySelector('#element');
const add = () => document.body.appendChild(element);
const remove = () => element.remove();
trackElement(element);
<button onclick="add()">Add</button>
<button onclick="remove()">Remove</button>
<div id="element">Element</div>
we can use all these tags with onload
<body>, <frame>, <frameset>, <iframe>, <img>, <input type="image">, <link>, <script> and <style>
eg:
function loadImage() {
alert("Image is loaded");
}
<img src="https://www.w3schools.com/tags/w3html.gif" onload="loadImage()" width="100" height="132">
I really like the YUI3 library for this sort of thing.
<div id="mydiv"> ... </div>
<script>
YUI().use('node-base', function(Y) {
Y.on("available", someFunction, '#mydiv')
})
See: http://developer.yahoo.com/yui/3/event/#onavailable
This is very simple solution and 100% working.
Just load an <img> tag inside the div or at last line of div, if you think you want to execute javascript, after loading all data in div.
As <img> tag supports onload event, so you can easily call javascript here like below:
<div>
<img onLoad="alert('Problem Solved');" src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" />
</div>
This above image will show only a single Dot(.), which you even cant see normally.
Try it.
First to answer your question: No, you can't, not directly like you wanted to do so.
May be a bit late to answer, but this is my solution, without jQuery, pure javascript.
It was originally written to apply a resize function to textareas after DOM is loaded and on keyup.
Same way you could use it to do something with (all) divs or only one, if specified, like so:
document.addEventListener("DOMContentLoaded", function() {
var divs = document.querySelectorAll('div'); // all divs
var mydiv = document.getElementById('myDiv'); // only div#myDiv
divs.forEach( div => {
do_something_with_all_divs(div);
});
do_something_with_mydiv(mydiv);
});
If you really need to do something with a div, loaded after the DOM is loaded, e.g. after an ajax call, you could use a very helpful hack, which is easy to understand an you'll find it ...working-with-elements-before-the-dom-is-ready.... It says "before the DOM is ready" but it works brillant the same way, after an ajax insertion or js-appendChild-whatever of a div. Here's the code, with some tiny changes to my needs.
css
.loaded { // I use only class loaded instead of a nodename
animation-name: nodeReady;
animation-duration: 0.001s;
}
#keyframes nodeReady {
from { clip: rect(1px, auto, auto, auto); }
to { clip: rect(0px, auto, auto, auto); }
}
javascript
document.addEventListener("animationstart", function(event) {
var e = event || window.event;
if (e.animationName == "nodeReady") {
e.target.classList.remove('loaded');
do_something_else();
}
}, false);
I am learning javascript and jquery and was going through all the answer,
i faced same issue when calling javascript function for loading div element.
I tried $('<divid>').ready(function(){alert('test'}) and it worked for me. I want to know is this good way to perform onload call on div element in the way i did using jquery selector.
thanks
As all said, you cannot use onLoad event on a DIV instead but it before body tag.
but in case you have one footer file and include it in many pages. it's better to check first if the div you want is on that page displayed, so the code doesn't executed in the pages that doesn't contain that DIV to make it load faster and save some time for your application.
so you will need to give that DIV an ID and do:
var myElem = document.getElementById('myElementId');
if (myElem !== null){ put your code here}
I had the same question and was trying to get a Div to load a scroll script, using onload or load. The problem I found was that it would always work before the Div could open, not during or after, so it wouldn't really work.
Then I came up with this as a work around.
<body>
<span onmouseover="window.scrollTo(0, document.body.scrollHeight);"
onmouseout="window.scrollTo(0, document.body.scrollHeight);">
<div id="">
</div>
Link to open Div
</span>
</body>
I placed the Div inside a Span and gave the Span two events, a mouseover and a mouseout. Then below that Div, I placed a link to open the Div, and gave that link an event for onclick. All events the exact same, to make the page scroll down to bottom of page. Now when the button to open the Div is clicked, the page will jump down part way, and the Div will open above the button, causing the mouseover and mouseout events to help push the scroll down script. Then any movement of the mouse at that point will push the script one last time.
You could use an interval to check for it until it loads like this:
https://codepen.io/pager/pen/MBgGGM
let checkonloadDoSomething = setInterval(() => {
let onloadDoSomething = document.getElementById("onloadDoSomething");
if (onloadDoSomething) {
onloadDoSomething.innerHTML="Loaded"
clearInterval(checkonloadDoSomething);
} else {`enter code here`
console.log("Waiting for onloadDoSomething to load");
}
}, 100);
When you load some html from server and insert it into DOM tree you can use DOMSubtreeModified however it is deprecated - so you can use MutationObserver or just detect new content inside loadElement function directly so you will don't need to wait for DOM events
var ignoreFirst=0;
var observer = (new MutationObserver((m, ob)=>
{
if(ignoreFirst++>0) {
console.log('Element add on', new Date());
}
}
)).observe(content, {childList: true, subtree:true });
// simulate element loading
var tmp=1;
function loadElement(name) {
setTimeout(()=>{
console.log(`Element ${name} loaded`)
content.innerHTML += `<div>My name is ${name}</div>`;
},1500*tmp++)
};
loadElement('Michael');
loadElement('Madonna');
loadElement('Shakira');
<div id="content"><div>
You can attach an event listener as below. It will trigger whenever the div having selector #my-id loads completely to DOM.
$(document).on('EventName', '#my-id', function() {
// do something
});
Inthis case EventName may be 'load' or 'click'
https://api.jquery.com/on/#on-events-selector-data-handler
Here is a trick that worked for me,
you just need to put your div inside a body element
<body>
<!-- Some code here -->
<body onload="alert('Hello World')">
<div ></div>
</body>
<!-- other lines of code -->
</body>
Use the body.onload event instead, either via attribute (<body onload="myFn()"> ...) or by binding an event in Javascript. This is extremely common with jQuery:
$(document).ready(function() {
doSomething($('#myDiv'));
});
You cannot add event onload on div, but you can add onkeydown and trigger onkeydown event on document load
$(function ()
{
$(".ccsdvCotentPS").trigger("onkeydown");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.2.3/jquery.min.js"></script>
<div onkeydown="setCss( );"> </div>`
Try this.
document.getElementById("div").onload = alert("This is a div.");
<div id="div">Hello World</div>
Try this one too. You need to remove . from oQuickReply.swap() to make the function working.
document.getElementById("div").onload = oQuickReplyswap();
function oQuickReplyswap() {
alert("Hello World");
}
<div id="div"></div>

Reinstatiating javascript for image crop

I'm trying to cobble together a function for a user to select an image for their avatar, preview it on the page using javascript, select the crop using the jquery guillotine, then upload it to the server w/ the coordinates where it can be processed.
So far I can select an image to upload and it will appear in the preview, but guillotine needs the image to be already loaded when it is invoked. Is there a way that I can force guillotine to re-load when I select an image?
This is my code:
<head>
<script src="{% static "assets/js/user_profile.js" %}"></script>
<script type="text/javascript">
function PreviewImage() {
var oFReader = new FileReader();
oFReader.readAsDataURL(document.getElementById("id_avatar").files[0]);
oFReader.onload = function (oFREvent) {
document.getElementById("avatar_preview").src = oFREvent.target.result;
};
};
</script>
</head>
<body>
<input type='file' id='id_avatar' name='avatar' onchange="PreviewImage();" /><br />
<div id="parent" style="width: 300px; height: 300px; overflow: hidden;">
<img id="avatar_preview" src="#" alt="your image" style="width:400px;" />
</div>
</body>
And this is what's in my user_profile.js, which is what I'd like to reinstantiate when I change the avatar input:
jQuery(function() {
var picture = $('#avatar_preview')
var camelize = function() {
var regex = /[\W_]+(.)/g
var replacer = function (match, submatch) { return submatch.toUpperCase() }
return function (str) { return str.replace(regex, replacer) }
}()
var showData = function (data) {
data.scale = parseFloat(data.scale.toFixed(4))
for(var k in data) { $('#'+k).html(data[k]) }
}
picture.on('load', function() {
picture.guillotine({ eventOnChange: 'guillotinechange' })
picture.guillotine('fit')
for (var i=0; i<5; i++) { picture.guillotine('zoomIn') }
// Show controls and data
$('.loading').remove()
$('.notice, #controls, #data').removeClass('hidden')
showData( picture.guillotine('getData') )
// Bind actions
$('#controls a').click(function(e) {
e.preventDefault()
action = camelize(this.id)
picture.guillotine(action)
})
// Update data on change
picture.on('guillotinechange', function(e, data, action) { showData(data) })
})
// Display random picture
picture.attr('src', 'img/unsplash.com_' + Math.ceil(Math.random() * 25) + '.jpg')
})
Is there a way to wrap that into something that can be reloaded without reloading the page and losing the preview?
With a few modifications you can achieve what you want. First off, Guillotine's code demo is much easier to follow than the code from the display demo.
Whenever you set a preview (change the src attribute) the image will be loaded and an onload event will be triggered (eventually). You only care about when new previews finish loading, you don't need to worry about changes on the file input.
So, focus on reloading the plugin each time the image finishes loading, like this. Basically it boils down to:
picture.on('load', function() {
// Reload the plugin (remove existing instance if any and create a new one)
if (picture.guillotine('instance')) picture.guillotine('remove')
picture.guillotine({ eventOnChange: 'guillotinechange' })
// Bind buttons, only once! (to avoid overlaps)
if (! picture.data('bindedBtns')) {
picture.data('bindedBtns', true)
$('#rotate_left').click(function(){ picture.guillotine('rotateLeft') })
$('#rotate_right').click(function(){ picture.guillotine('rotateRight') })
// ...
}
}
You might also find Presto quite useful. It's sole purpose is to display image previews from file inputs. It gracefully falls back looking for the best available way to display the previews.
If you also pair it up with Bifrost the last attempt will be to upload the image asynchronously and get the preview from the server (no need for HTML5, XMLHttpRequest or Flash) so you can be sure you'll get a preview on any browser.
Unfortunately I haven't had the time to complete Presto's readme but the source is very clean and at the top you'll find documentation for it's API and features.
Hope it helps.

wami-recorder - Wami.startRecording is not a function

I am trying to implement Wami-Recorder as described here on stackoverflow with basically the same setup as in the accepted answer ie swfobject.js, recorder.js, and gui.js included in the head tag, the html controls contained in the divs:
<div id="recorder">
<button id="record">Record</button>
<button id="play">Play</button>
</div>
<div id="flash"></div>
and the JavaScript is just sitting at the bottom of the page just before the html end tag:
<script>
Wami.setup({
id: 'flash' // where to put the flash object
});
// initialize some global vars
var recording = '';
var recordingUrl = '';
var playBackUrl = '';
// get button elements
var record = $('#record');
var play = $('#play');
// define functions
function startRecording() {
recording = 'temp.wav';
recordingUrl = 'http://localhost/temp/wami/test/save_file.php?filename=' + recording;
Wami.startRecording(recordingUrl);
// update button attributes
record.html('Stop').unbind().click(function() {
stopRecording();
});
}
function stopRecording() {
Wami.stopRecording();
// get the recording for playback
playBackUrl = 'http://localhost/temp/wami/test/' + recording;
// update button attributes
record.html('Record').unbind().click(function() {
startRecording();
});
}
function startPlaying() {
Wami.startPlaying(playBackUrl);
// update button attributes
play.html('Stop').unbind().click(function() {
stopPlaying();
});
}
function stopPlaying() {
Wami.stopPlaying();
// update button attributes
play.html('Play').unbind().click(function() {
startPlaying();
});
}
// add initial click functions
record.click(function() {
startRecording();
});
play.click(function() {
startPlaying();
});
</script>
</body>
Now, I've never actually seen a working demo of Wami-Recorder, but I'm assuming there should actually be something in the flash container when it loads...? I get no error, and I can right click the area where the flash embed should be and the context menu confirms that there's a flash object loaded, and Firebug shows the DOM has been modified to:
<div id="recorder">
<button id="record">Record</button>
<button id="play">Play</button>
</div>
<div id="flash">
<div id="widb06765e52be" style="position: absolute;">
<object id="wid36dd0ea1ccc" width="214" height="137" type="application/x-shockwave-flash" data="Wami.swf" style="visibility: visible;">
<param name="allowScriptAccess" value="always">
<param name="wmode" value="transparent">
<param name="flashvars" value="visible=false&loadedCallback=Wami._callbacks['wid9ebef515c0b']&console=true">
</object>
</div>
</div>
as well as that the Wami.swf file was fetched via GET with 200 status.
Still, when I click the Record button, I get TypeError: Wami.startRecording is not a function. I'm assuming it's some sort of context issue, in that Wami is not a global for use inside a function for some reason. If so, can anyone explain why? If this is not the case, what have I overlooked?
Edit:
At one point I had tried to implement a more object-oriented way of doing things with:
var Audio = {
setup: function() {
Wami.setup("wami");
}
record: function() {
Audio.status("Recording...");
Wami.startRecording("https://wami-recorder.appspot.com/audio");
}
play: function() {
Wami.startPlaying("https://wami-recorder.appspot.com/audio");
}
stop: function() {
Audio.status("");
Wami.stopRecording();
Wami.stopPlaying();
}
status: function(msg) {
$('#status').html(msg);
}
};
And I would fire the functions from within the document.ready() method depending upon other conditions. The original implementation throws the exact same error, and I stripped it all out to try this more direct approach... to no avail.
You're on the right track! This is a lot of writing, but I hope it helps :-D
On the default implementation using the sample code from the Google repos, you do see the Flash GUI because it's initialized, but in this example, it does not and relies on the HTML buttons. The Flash is still on the page right below the buttons but white one white.
Your error
Using your code and files, the only way I was able to duplicate your error was to access the file via the file system:
file:///c:/xampp/htdocs/wami/index.html
Accessing the same content through a web server:
http://localhost/wami/index.html
works great.
So my assumption is that you don't have a web server to test on and are using the file system instead. I included links to XAMPP and basic setup instructions below, as well as the working code sample.
My setup:
I'm using XAMPP so the browser URL is set to http://localhost/wami/index.html.
You can download XAMPP here.
On Windows, it will install in C:\xampp by default.
Place all your files in C:\xampp\htdocs\wami and you should be all set.
Start APACHE in the XAMPP console
Open a browser and navigate to http://localhost/wami/index.html
I placed all files in that folder (all WAMI files including save_file.php). Once ran, and the first WAV file was created, I elevated the permissions on it for testing (right-click, add FULL CONTROL permission for All Users (I'm on Windows 7).
Full working code sample (same as yours but has the entire code chunk for reference. I removed https:// from the JavaScript call since mixing http and https can cause security popups and broken JavaScript)
I used the PHP file as-is with this code:
<?php
// get the filename
parse_str($_SERVER['QUERY_STRING'], $params);
$file = isset($params['filename']) ? $params['filename'] : 'temp.wav';
// save the recorded audio to that file
$content = file_get_contents('php://input');
$fh = fopen($file, 'w') or die("can't open file");
fwrite($fh, $content);
fclose($fh);
?>
And the HTML file:
<!-- index.html -->
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
<script src="//ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script>
<script src="recorder.js"></script>
</head>
<body>
<div id="recorder">
<button id="record">Record</button>
<button id="play">Play</button>
</div>
<div id="flash"></div>
<script type="text/javascript">
// initialize Wami
Wami.setup({
id: 'flash' // where to put the flash object
});
// initialize some global vars
var recording = '';
var recordingUrl = '';
var playBackUrl = '';
// get button elements
var record = $('#record');
var play = $('#play');
// define functions
function startRecording() {
recording = 'temp.wav';
recordingUrl = 'save_file.php?filename=' + recording;
Wami.startRecording(recordingUrl);
// update button attributes
record.html('Stop').unbind().click(function() {
stopRecording();
});
}
function stopRecording() {
Wami.stopRecording();
// get the recording for playback
playBackUrl = recording;
// update button attributes
record.html('Record').unbind().click(function() {
startRecording();
});
}
function startPlaying() {
Wami.startPlaying(playBackUrl);
// update button attributes
play.html('Stop').unbind().click(function() {
stopPlaying();
});
}
function stopPlaying() {
Wami.stopPlaying();
// update button attributes
play.html('Play').unbind().click(function() {
startPlaying();
});
}
// add initial click functions
record.click(function() {
startRecording();
});
play.click(function() {
startPlaying();
});
</script>
</body>
</html>
The flash object was being embedded in the page, but none of the event listeners were working. I have since switched to jRecorder link, and with a few modifications to the code, have it working with no issues.

Copy and pasted Microsoft example of Javascript to check value in cell, but fails to work

I have been staring at the code below for hours, and I am not sure where to begin on how to fix the problem. In advance, I believe this is more of a javascript problem on my end then a Microsoft Web API problem, since I am literally copying and pasting their code.
I am trying to use Microsoft Excel's Web API to embed an excel sheet on my web page (which works fine) . More specifically, I am trying to have, when highlighted on a cell, it display the value of the selected cell in an alert javascript box.
Here is their working example with code of exactly what I am trying to do http://www.excelmashup.com/APIBrowser#example105
Simply change the tab from "Output" to "HTML" in the bottom right to see the same code as below:
<html>
<head>
<script type="text/javascript" src="http://r.office.microsoft.com/r/rlidExcelWLJS?v=1&kip=1"></script>
<script type="text/javascript">
// run the Excel load handler on page load
if (window.attachEvent) {
window.attachEvent("onload", loadEwaOnPageLoad);
} else {
window.addEventListener("DOMContentLoaded", loadEwaOnPageLoad, false);
}
function loadEwaOnPageLoad() {
var fileToken = "SDBBABB911BCD68292!110/-4923638281765748078/t=0&s=0&v=!ALTlXd5D3qSGJKU";
var props = {
uiOptions: {
showGridlines: false,
selectedCell: "'Sheet1'!C9",
showRowColumnHeaders: false,
showParametersTaskPane: false
},
interactivityOptions: {
allowTypingAndFormulaEntry: false,
allowParameterModification: false,
allowSorting: false,
allowFiltering: false,
allowPivotTableInteractivity: false
}
};
Ewa.EwaControl.loadEwaAsync(fileToken, "myExcelDiv", props, onEwaLoaded);
}
function onEwaLoaded() {
document.getElementById("loadingdiv").style.display = "none";
}
// This sample gets the value in the highlighted cell.
// Try clicking on different cells then running the sample.
function execute()
{
// Get unformatted range values (getValuesAsync(1,...) where 1 = Ewa.ValuesFormat.Formatted)
ewa.getActiveWorkbook().getActiveCell().getValuesAsync(1,getRangeValues,null);
}
function getRangeValues(asyncResult)
{
// Get the value from asyncResult if the asynchronous operation was successful.
if (asyncResult.getCode() == 0)
{
// Get the value in active cell (located at row 0, column 0 of the
// range which consists of a single cell (the "active cell")).
alert("Result: " + asyncResult.getReturnValue()[0][0]);
}
else
{
alert("Operation failed with error message " + asyncResult.getDescription() + ".");
}
}
</script>
</head>
<body>
<input type="button" onclick="execute();">Execute Sample</input> <<<<<Here is the problem
<div id="myExcelDiv" style="width: 402px; height: 346px"></div>
</body>
</html>
When I change the above to onclick="alert('hello')" that works fine, but it does not alert the value of the cell when I use execute(); . Maybe someone could copy and past the code into an .html file and see if it is just a problem on my end and whether the Microsoft code works for them. If it does not work, that would also be useful information.
The key lays on the variable "ewa". Normally when the page loads, inside loadEwaOnPageLoad() there is this line: Ewa.EwaControl.loadEwaAsync(fileToken, "myExcelDiv", props, onEwaLoaded); So we need to grab an Ewa object inside the onEwaLoaded function. I saw it somewhere like this (ewa declared somewhere else):
function onEwaLoaded(asyncResult) {
/*
* Add code here to interact with the embedded Excel web app.
* Find out more at http://msdn.microsoft.com/en-US/library/hh315812.aspx.
*/
if (asyncResult.getSucceeded()) {
// Use the AsyncResult.getEwaControl() method to get a reference to the EwaControl object
ewa = asyncResult.getEwaControl();
//...
After you got the ewa object the rest would be fine. Without it then the variable ewa is indeed not defined.
The Excel Interactive View feature has been disabled. However, I've just fixed some parts of your code to make it work. I've put all details in the comments with asterisks
<html>
<head>
<script type="text/javascript" src="http://r.office.microsoft.com/r/rlidExcelWLJS?v=1&kip=1"></script>
<script type="text/javascript">
var ewa = null;//*******************ADDING THIS IS BETTER**************************
// run the Excel load handler on page load
if (window.attachEvent) {
window.attachEvent("onload", loadEwaOnPageLoad);
} else {
window.addEventListener("DOMContentLoaded", loadEwaOnPageLoad, false);
}
function loadEwaOnPageLoad() {
var fileToken = "SDBBABB911BCD68292!110/-4923638281765748078/t=0&s=0&v=!ALTlXd5D3qSGJKU";
var props = {
uiOptions: {
showGridlines: false,
selectedCell: "'Sheet1'!C9",
showRowColumnHeaders: false,
showParametersTaskPane: false
},
interactivityOptions: {
allowTypingAndFormulaEntry: false,
allowParameterModification: false,
allowSorting: false,
allowFiltering: false,
allowPivotTableInteractivity: false
}
};
Ewa.EwaControl.loadEwaAsync(fileToken, "myExcelDiv", props, onEwaLoaded);
}
function onEwaLoaded(asyncResult) { //*******************PASS asyncResult PARAMETER**************************
//*******************THERE IS NO SUCH THING CALLED "loadingdiv"**************************
//document.getElementById("loadingdiv").style.display = "none";
//*******************ADD THIS IF-ELSE STATMENT**************************
if (asyncResult.getSucceeded()) {
// Use the AsyncResult.getEwaControl() method to get a reference to the EwaControl object
alert("Async operation Succeeded!");
ewa = asyncResult.getEwaControl();
}
else {
alert("Async operation failed!");
}
}
// This sample gets the value in the highlighted cell.
// Try clicking on different cells then running the sample.
function execute() {
// Get unformatted range values (getValuesAsync(1,...) where 1 = Ewa.ValuesFormat.Formatted)
ewa.getActiveWorkbook().getActiveCell().getValuesAsync(1, getRangeValues, null);
}
function getRangeValues(asyncResult) {
// Get the value from asyncResult if the asynchronous operation was successful.
if (asyncResult.getCode() == 0) {
// Get the value in active cell (located at row 0, column 0 of the
// range which consists of a single cell (the "active cell")).
alert("Result: " + asyncResult.getReturnValue()[0][0]);
}
else {
alert("Operation failed with error message " + asyncResult.getDescription() + ".");
}
}
</script>
</head>
<body>
<!-- *******************THE SIMICOLON AFTER execute() IS REMOVED*********************** -->
<input type="button" onclick="execute()" value="Execute Sample"></input>
<!-- *******************STYLE IS IMPROVED*********************** -->
<div id="myExcelDiv" style="width: 100%; height: 1000px"> </div>
</body>
</html>

WinJS.UI.ListView - refreshing items when using template is built using javascript

I've got a ListView that was using HTML-defined templates like this:
<div id="mediumListIconTextTemplate" data-win-control="WinJS.Binding.Template">
<div>
<!-- Displays the "picture" field. -->
<img data-win-bind="alt: title; src: picture" />
<div>
<!-- Displays the "title" field. -->
<h4 data-win-bind="innerText: title"></h4>
<!-- Displays the "text" field. -->
<h6 data-win-bind="innerText: description"></h6>
</div>
</div>
</div>
<div id="basicListView" data-win-control="WinJS.UI.ListView"
data-win-options="{itemDataSource : DataExample.itemList.dataSource, itemTemplate: select('#mediumListIconTextTemplate')}">
</div>
When my list items changed, my item template would be updated to reflect the change. However, out of need, I had to change to using a javaScript function to build my template. I modeled my code after the code found on the sample site:
app.onactivated = function (args) {
if (args.detail.kind === activation.ActivationKind.launch) {
if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
// TODO: This application has been newly launched. Initialize
// your application here.
} else {
// TODO: This application has been reactivated from suspension.
// Restore application state here.
}
args.setPromise(WinJS.UI.processAll().then(function () {
var lView = document.getElementById("templateFunctionListView").winControl;
lView.itemTemplate = itemTemplateFunction;
}));
}
};
function itemTemplateFunction(itemPromise) {
return itemPromise.then(function (item) {
var div = document.createElement("div");
var img = document.createElement("img");
img.src = item.data.picture;
img.alt = item.data.title;
div.appendChild(img);
var childDiv = document.createElement("div");
var title = document.createElement("h4");
title.innerText = item.data.title;
childDiv.appendChild(title);
var desc = document.createElement("h6");
desc.innerText = item.data.text;
childDiv.appendChild(desc);
div.appendChild(childDiv);
return div;
});
};
After changing to the javascript function, my display items never change when my binding data changes.
What do I need to do to make them update?
I think there are two approaches that could work for you.
In my case, when I refresh the data for my app, it's possible that one or more entities may be completely out of date, and there may be new entities to display. So I simply re-set the binding of the ListView, like so:
listView.itemDataSource = Data.items.dataSource;
where Data is the namespace I set up in data.js to contain all my data functions and objects.
When I update the value of the itemDataSource property, the ListView will re-bind to the new data, and display the correct items.
The other thing to look at, if your data is only being updated one property at a time, is using the WinJS.Binding.as function to make the items in the binding list observable, as described here:
http://msdn.microsoft.com/en-us/library/windows/apps/hh781224.aspx#updating_changing_records
If you haven't seen it already, there's some good info on databinding here:
http://msdn.microsoft.com/en-us/library/windows/apps/hh758311.aspx
And I found the following MSDN forum thread that may be helpful:
http://social.msdn.microsoft.com/Forums/en-US/winappswithhtml5/thread/21b9603f-e28d-4c93-b164-a2c91ba5c4ca
Hope the above helps!
For more information on Windows Store app development, register for App Builder.
Instead of rebinding the whole data set you can just rebind the single item. Find the items position in the list and then splice it replacing it with itself.
for (var i = 0; i < list.length; i++){
item = list.getAt(i);
if (item.key == itemToBeReBound.key){
list.splice(i, 1, item);
i = list.length;
}
}

Categories

Resources