Is there a way to make the built in HTML 5 spellcheck test fields on page load? I want to add this feature to an existing intranet site so that when the user loads a form the spelling errors are displayed.
It seems that the spelling errors are displayed when the user types an invalid value. I'm trying to show invalid values that were previously saved then served to the page.
Is this possible?
Thanks ST
...
<script>
var e;
function spell()
{
var sp = document.getElementById('sp');
var sel = window.getSelection();
sel.selectAllChildren(sp);
e = sel.getRangeAt(0);
select(sp, e.startOffset);
return true;
}
function select(sp, i)
{
var sel = window.getSelection();
if (i >= e.endOffset) return true;
var r = document.createRange();
r.setStart(sp, i);
r.setEnd(sp, i);
i++;
sel.removeAllRanges();
sel.addRange(r);
setTimeout(function() {select(sp, i)}, 20);
return true;
}
</script>
</head>
<body onload="spell();" >
<div id="sp" spellcheck="true" contenteditable="true">
...
This worked for me with Chrome. It's a bit ugly, you see the cursor moving in the editable div, but it does the job.
Related
I have created a form, used by some users at my school, that uploads a document and creates a new formatted document with all the uploads, which can be images or other docs. At this moment I am having problems with one .docx file that contains some lists, paragraphs and 2 images inside paragraphs. The part of the code I am using is:
...
// Insert Google doc
function insertGdoc(vdoc,IDgdoc,asignat)
{
var Gdoc=DocumentApp.openById(IDgdoc).getBody();
var vdoc_id=vdoc.getId();
var docBody=vdoc.getBody();
docBody.appendPageBreak();
docBody.appendParagraph("Documento de "+asignat).setBold(false);
docBody.appendHorizontalRule();
var insertaBody = DocumentApp.openById(IDgdoc).getActiveSection();
var numElements = insertaBody.getNumChildren();
for( var jj = 0; jj < numElements; ++jj )
{
var element = insertaBody.getChild(jj).copy();
var type = element.getType();
try {
if( type == DocumentApp.ElementType.PARAGRAPH )
{
docBody.appendParagraph(element.asParagraph());
}
else if( type == DocumentApp.ElementType.TABLE )
docBody.appendTable(element);
else if( type == DocumentApp.ElementType.HORIZONTAL_RULE)
docBody.appendHorizontalRule();
else if( type == DocumentApp.ElementType.PAGE_BREAK)
docBody.appendPageBreak();
else if( type == DocumentApp.ElementType.LIST_ITEM )
{
docBody.appendListItem(element);
var glyphType = element.getGlyphType();
element.setGlyphType(glyphType);
}
}
catch (e)
{
Logger.log(e);
}
}
}
// Insert MS Word doc
function insertDoc(vdoc,IDdoc,asignat)
{
var docx = DriveApp.getFileById(IDdoc);
var blob=docx.getBlob();
var newDoc = Drive.newFile();
var file=Drive.Files.insert(newDoc,blob,{convert:true});
insertGdoc(vdoc,file.id,asignat);
}
...
After many attempts, I discovered that the elements that are causing the problems are both pictures. By using the try..catch I can avoid the error by not handling the pictures, but the final document is incomplete. I have also tried to use Utilities.sleep to give the server more time to perform actions and even to close and reopen the document, with no change or worse results.
Another option I discovered here in stackoverflow was to try appending child elements from the paragraph, differentiating if they are pictures, which could copy the first of my pictures (although with size and position changed from the original) but not the second one.
Which is most annoying is that this failure happens if I use the form to do all the process, but if I try the operation manually from the console it works and the whole source document with both pictures is copied to the final doc.
Thank you very much in advance if you can give me any advice.
Rafael
I'm trying to make an app that allows you a text editor. You can type anything in to a text block. You can do two things with said text block:
a) run the text as an html page in a new about:blank tab or
b) save the text as a .html
For some reason, though, when I tried to implement the save ability, neither function would load. If I go into the JS console, it shows me this error upon clicking on the save button:
"Uncaught ReferenceError: saveAsFile is not defined (temp.html,1)"
When I seperated them into two <script> blocks, I could get the save function to work. However, when I did that, the Run in New Tab function no longer worked. It was utterly confusing.
I have used multiple functions before, and I don't know why it's suddenly not working. Can someone help? This is my code:
<script>
function run() {
var codeTab = window.open("" _blank);
var codeRun = document.getElementById("code").value;
codeTab.document.write(codeRun);
}
</script>
<script>
/*i stole-i mean used-this code from someone else*/
function saveAsFile() {
var textToSave = document.getElementById("code").value;
var hiddenElement = document.createElement('a');
hiddenElement.href = 'data:attachment/text,' + encodeURI(textToSave);
hiddenElement.target = '_blank';
hiddenElement.download = 'save.html';
hiddenElement.click();
}
</script>
On line 3, you have window.open("" _blank);. It should be window.open("_blank");.
I also cannot see anywhere saveAs() is being called (or defined). Is it possibly being called in codeRun? See below code which worked for me.
<textarea id="code">
</textarea>
<button onclick="run();">Run</button>
<button onclick="saveAsFile();">Save</button>
<script>
function run() {
var codeTab = window.open("_blank");
var codeRun = document.getElementById("code").value;
codeTab.document.write(codeRun);
}
/*i stole-i mean used-this code from someone else*/
function saveAsFile() {
var textToSave = document.getElementById("code").value;
var hiddenElement = document.createElement('a');
hiddenElement.href = 'data:attachment/text,' + encodeURI(textToSave);
hiddenElement.target = '_blank';
hiddenElement.download = 'save.html';
hiddenElement.click();
}
</script>
Im trying to follow tutorial from this site " Link to Tutorial " to make a idle game.
It shows easy way to make simple local save function, but I can't make it work for some reason. He tells to make a function this and that, but doesn't show how it should look like.
I searched google and saw many different ways, I got some to work but not fully and they weren't simple enough for my lack of knowledge in HTML.
Any help is welcome and appreciated :) thanks in advance.
function save(){
var save = {
cookies: cookies,
cursors: cursors
}
localStorage.setItem("save",JSON.stringify(save));
};
function load(){
var savegame = JSON.parse(localStorage.getItem("save"));
if (typeof savegame.cookies !== "undefined") cookies = savegame.cookies;
};
var cookies = 0;
function cookieClick(number) {
cookies = cookies + number;
document.getElementById("cookies").innerHTML = cookies;
};
var cursors = 0;
function buyCursor() {
var cursorCost = Math.floor(10 * Math.pow(1.1, cursors)); //works out the cost of this cursor
if (cookies >= cursorCost) { //checks that the player can afford the cursor
cursors = cursors + 1; //increases number of cursors
cookies = cookies - cursorCost; //removes the cookies spent
document.getElementById('cursors').innerHTML = cursors; //updates the number of cursors for the user
document.getElementById('cookies').innerHTML = cookies; //updates the number of cookies for the user
};
var nextCost = Math.floor(10 * Math.pow(1.1, cursors)); //works out the cost of the next cursor
document.getElementById('cursorCost').innerHTML = nextCost; //updates the cursor cost for the user
};
function save() {
var save = {
cookies: cookies,
cursors: cursors
}
localStorage.setItem("save", JSON.stringify(save));
};
function load() {
var savegame = JSON.parse(localStorage.getItem("save"));
if (typeof savegame.cookies !== "undefined") cookies = savegame.cookies;
}
window.setInterval(function() {
cookieClick(cursors);
}, 1000);
<html>
<head>
<link rel="stylesheet" type="text/css" href="interface.css" />
</head>
<body>
<button onclick="cookieClick(1)">Click Me!</button>
<br />Cookies: <span id="cookies">0</span>
<br />
<button onclick="buyCursor()">Buy Cursor</button>
<br />Cursors: <span id="cursors">0</span>
<br />Cursor Cost: <span id="cursorCost">10</span>
<script type="text/javascript" src="main.js"></script>
</body>
</html>
Your browser may not support localstorage.
You can check broswer's localstorage support using Modernizr.
Read about it here: http://diveintohtml5.info/detect.html
Also make sure, that you are calling save() method in your code (I don't see it in your code)
I'm teaching a class and for my class I keep all of my student's marks on a google spreadsheet. On my website I would like to present information to students on an individual basis. I've created an app where it presents them with a password text box. They type in their password and then it retrieves information from the spreadsheet that is unique to them and presents it to them in a label. I've been trying to hack this all together, but it's just not working properly and I'm getting an error that I cannot diagnose. If I print out the information using Browser.msgBox() it outputs the info, but otherwise it generates an error. Why is this happening and what is the fix? Here's the code:
var pointsSheet = SpreadsheetApp.openById('1o8_f063j1jYZjFEnI_P7uAztpnEAvQ6mc3Z1_Owa69Y');
//creates and shows an app with a label and password text box
function doGet() {
var app = UiApp.createApplication().setTitle('Incomplete Challenges');
var mygrid = app.createGrid(1, 2);
mygrid.setWidget(0, 0, app.createLabel('Password:'));
mygrid.setWidget(0, 1, app.createPasswordTextBox().setName("text"));
var mybutton = app.createButton('Submit');
var submitHandler = app.createServerClickHandler('getResults');
submitHandler.addCallbackElement(mygrid);
mybutton.addClickHandler(submitHandler);
var mypanel = app.createVerticalPanel();
mypanel.add(mygrid);
mypanel.add(mybutton);
app.add(mypanel);
SpreadsheetApp.getActiveSpreadsheet().show(app);
//return app; //UNCOMMENT WHEN DEPLOYING APP
}
//obtains data based on password entered by user and outputs their info
function getResults(eventInfo) {
var app = UiApp.createApplication().setTitle('Incomplete Challenges');
var password = eventInfo.parameter.text;
var passwordCheckRange = pointsSheet.getRange("B34:C34").getValues();
if (passwordCheckRange == null) {
Browser.msgBox("Error: Range is null");
return app;
}
var name;
for(var i = 0; i < passwordCheckRange.length; i++) {
if(passwordCheckRange[i][1] == password) {
name = passwordCheckRange[i][0];
break;
}
}
var studentRecordRange = pointsSheet.getRange("B3:AY29").getValues();
var headingRange = pointsSheet.getRange("B1:AY2").getValues();
if (studentRecordRange == null) {
Browser.msgBox("Error: Range is null");
return app;
}
var requestedRecord;
for(var i = 0; i < studentRecordRange.length; i++) {
if(studentRecordRange[i][0] == name)
requestedRecord = studentRecordRange[i];
}
var stringRecord = "";
for(var i = headingRange[1].length-1; i >= 7; i--) {
if (requestedRecord[i] == "")
stringRecord += headingRange[1][i] + ": " + headingRange[0][i] + "XP" + "\\n";
}
var mygrid = app.createGrid(2, 1);
mygrid.setWidget(0, 0, app.createLabel('INCOMPLETE CHALLENGES'));
mygrid.setWidget(1, 0, app.createLabel(stringRecord));
var mypanel = app.createVerticalPanel();
mypanel.add(mygrid);
app.add(mypanel);
//Browser.msgBox(stringRecord);
return app;
}
The error that I experience is: Error encountered: An unexpected error occurred.
As you can see it's very helpful.
Line 28 it should be getActiveApplication() and not createApplication().
You cant create an application on another application. :)
Also I think line 63 it should be "<br>"; instead "\n"; along with line 68 it should be createHTML instead of createLabel
I also think that you have apply few styling css so that your app looks good. check on .setStyleAttributes in UiApp.
There are a few errors in this code, the first one -that generates the error you get - is (as mentioned in the other answer) the UiApp.createApplication() in the handler function.
You can't create an UiApp instance in a handler function, you should instead get the active instance and eventually add elements to it (using UiApp.getActiveApplication()).
You can't neither change the title of this instance. Btw, it doesn't make sense since this title will not appear as a "title" when you will be deploying this app as a webapp. It will simply show up at the top of your browser window (as a page title) as your app will occupy the whole screen and not a modal popup anymore. So if you want a title to appear in your Ui, simply add it as an HTML widget where you can choose the font size and weight (and any other CSS styles).
The other error is in the password check, you are using Browser.msgBox("Error: Range is null"); but Browser class won't work in UiApp. You should only use UiApp elements, not spreadSheetApp elements.
And, as a more general comment, I suggest you test your app directly using the .dev url (last saved version) of the app (after saving a beta version and having deployed it) so that you are in the "real" use condition and have a pertinent pov on the result.
Method UiInstance.getElementById(ID) always returns GenericWidget object, even if ID does not exist.
Is there some way how to find out that returned object does not exist in my app, or check whether UI contains object with given ID?
Solution for UI created with GUI builder:
function getSafeElement(app, txtID) {
var elem = app.getElementById(txtID);
var bExists = elem != null && Object.keys(elem).length < 100;
return bExists ? elem : null;
}
It returns null if ID does not exist. I didn't test all widgets for keys length boundary, so be careful and test it with your GUI.
EDIT: This solution works only within doGet() function. It does not work in server handlers, so in this case use it in combination with #corey-g answer.
This will only work in the same execution that you created the widget in, and not in a subsequent event handler where you retrieve the widget, because in that case everything is a GenericWidget whether or not it exists.
You can see for yourself that the solution fails:
function doGet() {
var app = UiApp.createApplication();
app.add(app.createButton().setId("control").addClickHandler(
app.createServerHandler("clicked")));
app.add(app.createLabel(exists(app)));
return app;
}
function clicked() {
var app = UiApp.getActiveApplication();
app.add(app.createLabel(exists(app)));
return app;
}
function exists(app) {
var control = app.getElementById("control");
return control != null && Object.keys(control).length < 100;
}
The app will first print 'true', but on the click handler it will print 'false' for the same widget.
This is by design; a GenericWidget is a "pointer" of sorts to a widget in the browser. We don't keep track of what widgets you have created, to reduce data transfer and latency between the browser and your script (otherwise we'd have to send up a long list of what widgets exist on every event handler). You are supposed to keep track of what you've created and only "ask" for widgets that you already know exist (and that you already know the "real" type of).
If you really want to keep track of what widgets exist, you have two main options. The first is to log entries into ScriptDb as you create widgets, and then look them up afterwards. Something like this:
function doGet() {
var app = UiApp.createApplication();
var db = ScriptDb.getMyDb();
// You'd need to clear out old entries here... ignoring that for now
app.add(app.createButton().setId('foo')
.addClickHandler(app.createServerHandler("clicked")));
db.save({id: 'foo', type: 'button'});
app.add(app.createButton().setId('bar'));
db.save({id: 'bar', type: 'button'});
return app
}
Then in a handler you can look up what's there:
function clicked() {
var db = ScriptDb.getMyDb();
var widgets = db.query({}); // all widgets
var button = db.query({type: 'button'}); // all buttons
var foo = db.query({id: 'foo'}); // widget with id foo
}
Alternatively, you can do this purely in UiApp by making use of tags
function doGet() {
var app = UiApp.createApplication();
var root = app.createFlowPanel(); // need a root panel
// tag just needs to exist; value is irrelevant.
var button1 = app.createButton().setId('button1').setTag("");
var button2 = app.createButton().setId('button2').setTag("");
// Add root as a callback element to any server handler
// that needs to know if widgets exist
button1.addClickHandler(app.createServerHandler("clicked")
.addCallbackElement(root));
root.add(button1).add(button2);
app.add(root);
return app;
}
function clicked(e) {
throw "\n" +
"button1 " + (e.parameter["button1_tag"] === "") + "\n" +
"button2 " + (e.parameter["button2_tag"] === "") + "\n" +
"button3 " + (e.parameter["button3_tag"] === "");
}
This will throw:
button1 true
button2 true
button3 false
because buttons 1 and 2 exist but 3 doesn't. You can get fancier by storing the type in the tag, but this suffices to check for widget existence. It works because all children of the root get added as callback elements, and the tags for all callback elements are sent up with the handler. Note that this is as expensive as it sounds and for an app with a huge amount of widgets could potentially impact performance, although it's probably ok in many cases especially if you only add the root as a callback element to handlers that actually need to verify the existence of arbitrary widgets.
My initial solution is wrong, because it returns false exist controls.
A solution, based on Corey's answer, is to add the setTag("") method and here is ready to use code. It is suitable for event handlers only, because uses tags.
function doGet() {
var app = UiApp.createApplication();
var btn01 = app.createButton("control01").setId("control01").setTag("");
var btn02 = app.createButton("control02").setId("control02").setTag("");
var handler = app.createServerHandler("clicked");
handler.addCallbackElement(btn01);
handler.addCallbackElement(btn02);
btn01.addClickHandler(handler);
btn02.addClickHandler(handler);
app.add(btn01);
app.add(btn02);
return app;
}
function clicked(e) {
var app = UiApp.getActiveApplication();
app.add(app.createLabel("control01 - " + controlExists(e, "control01")));
app.add(app.createLabel("control02 - " + controlExists(e, "control02")));
app.add(app.createLabel("fake - " + controlExists(e, "fake")));
return app;
}
function controlExists(e, controlName) {
return e.parameter[controlName + "_tag"] != null;
}