我一直在阅读“Google脚本”,这本书经历了Google Apps脚本的多种用途,并引导您构建应用。
我已经浏览了一个关于从模板动态创建表单的部分,我遇到了一个我无法解决的问题。当访问发布的URL时,它返回“遇到的错误:未知的宏showForm”让我感到困惑的是我尝试在mozilla中使用firebug并在脚本编辑器中进行调试,但没有发现错误。任何人都可以帮助指出我应该在哪里寻找或指导帮助排除故障的方向 ?
这是守则。它分成三块。 Code.gs,GS Objecgts.js和Documents API.js
CODE.GS
var templateFolderId = '<<Enter Folder ID>>';
function doGet(e){
var app = UiApp.createApplication().setTitle('Template Creator');
//What this app is about
var grid = app.createGrid(6, 2).setId('grid').setCellPadding(5);
app.add(grid);
grid.setWidget(0,0, app.createLabel("This App will allow you to create a form from"+
" a template in Google Docs."));
//create UI here
// File Chooser
var fileChooser = app.createListBox().setName('fileChooser').setId('fileChooser')
.addChangeHandler(app.createServerChangeHandler('showForm')
.addCallbackElement(grid));
grid.setWidget(2, 0, fileChooser);
//set the file Names in the listBox by calling on the DocsList service
fileChooser.addItem('Choose Template');
var files = DocsList.getFolderById(templateFolderId).getFiles();
for (var i = 0; i < files.length; i++) {
fileChooser.addItem(files[i].getName());
}
// Submit the form button
var button = app.createButton('Submit').setId('button')
.addClickHandler(app.createServerClickHandler('createDoc')
.addCallbackElement(grid))
.setVisible(false);
grid.setWidget(4, 0, button);
/*
* @returns body text from doc
*/
function getTemplateText(fileName){
var files = DocsList.getFolderById(templateFolderId).getFiles();
for (var i = 0; i < files.length; i++) {
if (fileName == files[i].getName()){
var text = DOCS_LIST_API.GdocToFormat(files[i].getId(), 'txt');
return text.getContentText();
}
}
}
// function returns an array of unique form keys
function createKeys(templateFile){
var templateTxt = getTemplateText(templateFile);
var templateVars = templateTxt.match(/\{\%[^\%]+\%\}/g);
var templateKeys = [];
var oneEach = "";
for (var i in templateVars) {
var keyObject = {};
keyObject.text = templateVars[i].replace(/\{\%|\%\}/g, '');
keyObject.id = camelString(templateVars[i]);
if (oneEach.match(keyObject.text) == null){
templateKeys.push(keyObject);
}
oneEach += " " + keyObject.text;
}
return templateKeys;
}
function showForm(e){
var app = UiApp.getActiveApplication();
var flexTable = app.createFlexTable();
var keys = createKeys(e.parameter.fileChooser);
for (var i in keys) {
var text = (keys[i].text);
if(/^instruction/i.test(text)){
flexTable.setWidget(parseInt(i),0,app
.createLabel(text.substring(text.indexOf(':')+1)));
}else{
var questionPanel = app.createHorizontalPanel();
flexTable.setWidget(parseInt(i),0,questionPanel);
questionPanel.add(app.createLabel(text).setWidth('100px'));
questionPanel.add(app.createTextBox().setName(keys[i].id));
}
}
flexTable.setWidget(keys.length+1,0,app.createLabel('________'));
flexTable.setWidget(keys.length+2,0, app.createHorizontalPanel()
.add(app.createLabel('Output file name: ').setWidth('100px'))
.add(app.createTextBox()
.setName('outputFile').setWidth('200px')
.setValue('Copy of '+ e.parameter.fileChooser)));
flexTable.setWidget(keys.length+3,0, app.createHorizontalPanel()
.add(app.createLabel('Google Email: ').setWidth('100px'))
.add(app.createTextBox()
.setName('email').setWidth('200px')));
app.getElementById('button').setVisible(true);
app.getElementById('grid').setWidget(3,0, flexTable);
return app;
}
function createDoc(e){
var app = UiApp.getActiveApplication();
var keys = createKeys(e.parameter.fileChooser);
var files = DocsList.getFolderById(templateFolderId).getFiles();
for (var i in files) {
if (e.parameter.fileChooser == files[i].getName()){
var copyId = files[i].makeCopy(e.parameter.outputFile).getId();
var doc = DocumentApp.openById(copyId)
var copy = doc.getActiveSection();
for (var i in keys) {
var text = keys[i].text;
if(/^instruction/i.test(text)){
if (copy.findText(keys[i].text) != null)
copy.findText(keys[i].text).getElement().removeFromParent();
}else{
copy.replaceText('{%'+keys[i].text+'%}', e.parameter[keys[i].id]);
}
}
doc.saveAndClose();
doc.addEditor(e.parameter.email);
}
}
app.getElementById('grid').setWidget(3,0, app.createAnchor('Open your Document',
doc.getUrl())
.setStyleAttribute('font-size', '18px'));
app.getElementById('button').setVisible(false);
app.getElementById('fileChooser').setItemSelected(0, true);
return app;
}
return app;
}
GS Objects.gs
/*
ObjService
Copyright (c) 2011 James Ferreira
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* ObjService
* @author James Ferriera
* @documentation http://goo.gl/JdEHW
*
* Changes an object like e.parameter into a 2D array useful in
* writting to a spreadsheet with using the .setValues method
*
* @param {Array} headers [header, header, ...]
* @param {Array} objValues [{key:value, ...}, ...]
* @returns {Array} [[value, value, ...], ...]
*/
function objectToArray(headers, objValues){
var values = [];
var headers = camelArray(headers);
for (var j=0; j < objValues.length; j++){
var rowValues = [];
for (var i=0; i < headers.length; i++){
rowValues.push(objValues[j][headers[i]]);
}
values.push(rowValues);
}
return values;
}
/**
* Changes a range array often returned from .getValues() into an
* array of objects with key value pairs.
* The first element in the array is used as the keys (headers)
*
* @param {Array} range [[key, key, ...],[value, value, ...]]
* @returns {Array} [{key:value, ...}, ...]
*/
function rangeToObjects(range){
var headers = range[0];
var values = range;
var rowObjects = [];
for (var i = 1; i < values.length; ++i) {
var row = new Object();
row.rowNum = i;
for (var j in headers){
row[camelString(headers[j])] = values[i][j];
}
rowObjects.push(row);
}
return rowObjects;
}
/**
* Changes a range array into an array of objects with key value pairs
*
* @params {array} headers [key, key, ...]
* @params {array} values [[value, value, ...], ...]
* @returns {array} [{key:value, ...}, ...]
*/
function splitRangesToObjects(headers, values){
var rowObjects = [];
for (var i = 1; i < values.length; ++i) {
var row = new Object();
row.rowNum = i;
for (var j in headers){
row[camelString(headers[j])] = values[i][j];
}
rowObjects.push(row);
}
return rowObjects;
}
/**
* Removes special characters from strings in an array
* Commonly know as a camelCase,
* Examples:
* "First Name" -> "firstName"
* "Market Cap (millions) -> "marketCapMillions
* "1 number at the beginning is ignored" -> "numberAtTheBeginningIsIgnored"
* @params {array} headers [string, string, ...]
* @returns {array} camelCase
*/
function camelArray(headers) {
var keys = [];
for (var i = 0; i < headers.length; ++i) {
var key = camelString(headers[i]);
if (key.length > 0) {
keys.push(key);
}
}
return keys;
}
/**
* Removes special characters from a string
* Commonly know as a camelCase,
* Examples:
* "First Name" -> "firstName"
* "Market Cap (millions) -> "marketCapMillions
* "1 number at the beginning is ignored" -> "numberAtTheBeginningIsIgnored"
* @params {string} header string
* @returns {string} camelCase
*/
function camelString(header) {
var key = "";
var upperCase = false;
for (var i = 0; i < header.length; ++i) {
var letter = header[i];
if (letter == " " && key.length > 0) {
upperCase = true;
continue;
}
if (!isAlnum_(letter)) {
continue;
}
if (key.length == 0 && isDigit_(letter)) {
continue; // first character must be a letter
}
if (upperCase) {
upperCase = false;
key += letter.toUpperCase();
} else {
key += letter.toLowerCase();
}
}
return key;
}
function isCellEmpty_(cellData) {
return typeof(cellData) == "string" && cellData == "";
}
function isAlnum_(char) {
return char >= 'A' && char <= 'Z' ||
char >= 'a' && char <= 'z' ||
isDigit_(char);
}
function isDigit_(char) {
return char >= '0' && char <= '9';
}
文件API.gs
/*
* Private for OAuth
* @ returns OAuth headers
*/
var DOCS_LIST_API = {};
DOCS_LIST_API.googleOAuth = function() {
var oAuthConfig = UrlFetchApp.addOAuthService('google');
oAuthConfig.setRequestTokenUrl("https://www.google.com/accounts/"+
"OAuthGetRequestToken?scope=https://docs.google.com/feeds/");
oAuthConfig.setAuthorizationUrl("https://www.google.com/accounts/OAuthAuthorizeToken");
oAuthConfig.setAccessTokenUrl("https://www.google.com/accounts/OAuthGetAccessToken");
oAuthConfig.setConsumerKey('anonymous');
oAuthConfig.setConsumerSecret('anonymous');
return {oAuthServiceName:'google', oAuthUseToken:"always"};
}
/*
* @ args docID String the id for a Google Document
* @ args format String can be, "txt", "odt", "pdf", "html", "rtf", "doc", "png",
"zip"
* @ returns blob
*
*/
DOCS_LIST_API.GdocToFormat = function(docID, format){
var fetchArgs = DOCS_LIST_API.googleOAuth();
fetchArgs.headers = { "GData-Version": "3.0" };
fetchArgs.method = 'get';
var url = 'https://docs.google.com/feeds/download/documents/export/Export?id='+
docID+'&exportFormat='+format+'&format='+format;
return UrlFetchApp.fetch(url, fetchArgs);
}
// Run it twice
function doOAuth(){
try{
DOCS_LIST_API.GdocToFormat();
}catch(e){
}
}
答案 0 :(得分:0)
似乎code.gs
中存在错误“逻辑”版本应如下所示:(在脚本编辑器中复制和粘贴)
var templateFolderId = '<<Enter Folder ID>>';
function doGet(e){
var app = UiApp.createApplication().setTitle('Template Creator');
//What this app is about
var grid = app.createGrid(6, 2).setId('grid').setCellPadding(5);
app.add(grid);
grid.setWidget(0,0, app.createLabel("This App will allow you to create a form from"+
" a template in Google Docs."));
//create UI here
// File Chooser
var fileChooser = app.createListBox().setName('fileChooser').setId('fileChooser')
.addChangeHandler(app.createServerChangeHandler('showForm')
.addCallbackElement(grid));
grid.setWidget(2, 0, fileChooser);
//set the file Names in the listBox by calling on the DocsList service
fileChooser.addItem('Choose Template');
var files = DocsList.getFolderById(templateFolderId).getFiles();
for (var i = 0; i < files.length; i++) {
fileChooser.addItem(files[i].getName());
}
// Submit the form button
var button = app.createButton('Submit').setId('button')
.addClickHandler(app.createServerClickHandler('createDoc')
.addCallbackElement(grid))
.setVisible(false);
grid.setWidget(4, 0, button);
return app
}
/*
* @returns body text from doc
*/
function getTemplateText(fileName){
var files = DocsList.getFolderById(templateFolderId).getFiles();
for (var i = 0; i < files.length; i++) {
if (fileName == files[i].getName()){
var text = DOCS_LIST_API.GdocToFormat(files[i].getId(), 'txt');
return text.getContentText();
}
}
}
// function returns an array of unique form keys
function createKeys(templateFile){
var templateTxt = getTemplateText(templateFile);
var templateVars = templateTxt.match(/\{\%[^\%]+\%\}/g);
var templateKeys = [];
var oneEach = "";
for (var i in templateVars) {
var keyObject = {};
keyObject.text = templateVars[i].replace(/\{\%|\%\}/g, '');
keyObject.id = camelString(templateVars[i]);
if (oneEach.match(keyObject.text) == null){
templateKeys.push(keyObject);
}
oneEach += " " + keyObject.text;
}
return templateKeys;
}
function showForm(e){
var app = UiApp.getActiveApplication();
var flexTable = app.createFlexTable();
var keys = createKeys(e.parameter.fileChooser);
for (var i in keys) {
var text = (keys[i].text);
if(/^instruction/i.test(text)){
flexTable.setWidget(parseInt(i),0,app
.createLabel(text.substring(text.indexOf(':')+1)));
}else{
var questionPanel = app.createHorizontalPanel();
flexTable.setWidget(parseInt(i),0,questionPanel);
questionPanel.add(app.createLabel(text).setWidth('100px'));
questionPanel.add(app.createTextBox().setName(keys[i].id));
}
}
flexTable.setWidget(keys.length+1,0,app.createLabel('________'));
flexTable.setWidget(keys.length+2,0, app.createHorizontalPanel()
.add(app.createLabel('Output file name: ').setWidth('100px'))
.add(app.createTextBox()
.setName('outputFile').setWidth('200px')
.setValue('Copy of '+ e.parameter.fileChooser)));
flexTable.setWidget(keys.length+3,0, app.createHorizontalPanel()
.add(app.createLabel('Google Email: ').setWidth('100px'))
.add(app.createTextBox()
.setName('email').setWidth('200px')));
app.getElementById('button').setVisible(true);
app.getElementById('grid').setWidget(3,0, flexTable);
return app;
}
function createDoc(e){
var app = UiApp.getActiveApplication();
var keys = createKeys(e.parameter.fileChooser);
var files = DocsList.getFolderById(templateFolderId).getFiles();
for (var i in files) {
if (e.parameter.fileChooser == files[i].getName()){
var copyId = files[i].makeCopy(e.parameter.outputFile).getId();
var doc = DocumentApp.openById(copyId)
var copy = doc.getActiveSection();
for (var i in keys) {
var text = keys[i].text;
if(/^instruction/i.test(text)){
if (copy.findText(keys[i].text) != null)
copy.findText(keys[i].text).getElement().removeFromParent();
}else{
copy.replaceText('{%'+keys[i].text+'%}', e.parameter[keys[i].id]);
}
}
doc.saveAndClose();
doc.addEditor(e.parameter.email);
}
}
app.getElementById('grid').setWidget(3,0, app.createAnchor('Open your Document',
doc.getUrl())
.setStyleAttribute('font-size', '18px'));
app.getElementById('button').setVisible(false);
app.getElementById('fileChooser').setItemSelected(0, true);
return app;
}
编辑:保存后,使用此功能测试: