url to url redirection using html - javascript

I'm trying to submit a contact form using google-app-script. When I'm submit that, it displays the following page:
https://script.google.com/macros/s/AKfycbx-sxqjOmCD5pGhLzzcI9Tc906bZN5VnNQQCe34/exec
I want this url to to redirect to my another page, how can I achieve that using scripts.
Below is the script. Just for the info, I'm a beginner.
/******************************************************************************
* This tutorial is based on the work of Martin Hawksey twitter.com/mhawksey *
* But has been simplified and cleaned up to make it more beginner friendly *
* All credit still goes to Martin and any issues/complaints/questions to me. *
******************************************************************************/
// if you want to store your email server-side (hidden), uncomment the next line
var TO_ADDRESS = "abc#gmail.com";
// spit out all the keys/values from the form in HTML for email
// uses an array of keys if provided or the object to determine field order
function formatMailBody(obj, order) {
var result = "";
if (!order) {
order = Object.keys(obj);
}
// loop over all keys in the ordered form data
for (var idx in order) {
var key = order[idx];
result += "<h4 style='text-transform: capitalize; margin-bottom: 0'>" + key + "</h4><div>" + sanitizeInput(obj[key]) + "</div>";
// for every key, concatenate an `<h4 />`/`<div />` pairing of the key name and its value,
// and append it to the `result` string created at the start.
}
return result; // once the looping is done, `result` will be one long string to put in the email body
}
// sanitize content from the user - trust no one
// ref: https://developers.google.com/apps-script/reference/html/html-output#appendUntrusted(String)
function sanitizeInput(rawInput) {
var placeholder = HtmlService.createHtmlOutput(" ");
placeholder.appendUntrusted(rawInput);
return placeholder.getContent();
}
function doPost(e) {
try {
Logger.log(e); // the Google Script version of console.log see: Class Logger
record_data(e);
// shorter name for form data
var mailData = e.parameters;
// names and order of form elements (if set)
var orderParameter = e.parameters.formDataNameOrder;
var dataOrder;
if (orderParameter) {
dataOrder = JSON.parse(orderParameter);
}
// determine recepient of the email
// if you have your email uncommented above, it uses that `TO_ADDRESS`
// otherwise, it defaults to the email provided by the form's data attribute
var sendEmailTo = (typeof TO_ADDRESS !== "undefined") ? TO_ADDRESS : mailData.formGoogleSendEmail;
// send email if to address is set
if (sendEmailTo) {
MailApp.sendEmail({
to: String(sendEmailTo),
subject: "About Me: Contact form submitted",
// replyTo: String(mailData.email), // This is optional and reliant on your form actually collecting a field named `email`
htmlBody: formatMailBody(mailData, dataOrder)
});
}
return ContentService // return json success results
.createTextOutput(
JSON.stringify({"result":"success",
"data": JSON.stringify(e.parameters) }))
.setMimeType(ContentService.MimeType.JSON);
} catch(error) { // if error return this
Logger.log(error);
return ContentService
.createTextOutput(JSON.stringify({"result":"error", "error": error}))
.setMimeType(ContentService.MimeType.JSON);
}
}
/**
* record_data inserts the data received from the html form submission
* e is the data received from the POST
*/
function record_data(e) {
var lock = LockService.getDocumentLock();
lock.waitLock(30000); // hold off up to 30 sec to avoid concurrent writing
try {
Logger.log(JSON.stringify(e)); // log the POST data in case we need to debug it
// select the 'responses' sheet by default
var doc = SpreadsheetApp.getActiveSpreadsheet();
var sheetName = e.parameters.formGoogleSheetName || "responses";
var sheet = doc.getSheetByName(sheetName);
var oldHeader = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
var newHeader = oldHeader.slice();
var fieldsFromForm = getDataColumns(e.parameters);
var row = [new Date()]; // first element in the row should always be a timestamp
// loop through the header columns
for (var i = 1; i < oldHeader.length; i++) { // start at 1 to avoid Timestamp column
var field = oldHeader[i];
var output = getFieldFromData(field, e.parameters);
row.push(output);
// mark as stored by removing from form fields
var formIndex = fieldsFromForm.indexOf(field);
if (formIndex > -1) {
fieldsFromForm.splice(formIndex, 1);
}
}
// set any new fields in our form
for (var i = 0; i < fieldsFromForm.length; i++) {
var field = fieldsFromForm[i];
var output = getFieldFromData(field, e.parameters);
row.push(output);
newHeader.push(field);
}
// more efficient to set values as [][] array than individually
var nextRow = sheet.getLastRow() + 1; // get next row
sheet.getRange(nextRow, 1, 1, row.length).setValues([row]);
// update header row with any new data
if (newHeader.length > oldHeader.length) {
sheet.getRange(1, 1, 1, newHeader.length).setValues([newHeader]);
}
}
catch(error) {
Logger.log(error);
}
finally {
lock.releaseLock();
return;
}
}
function getDataColumns(data) {
return Object.keys(data).filter(function(column) {
return !(column === 'formDataNameOrder' || column === 'formGoogleSheetName' || column === 'formGoogleSendEmail' || column === 'honeypot');
});
}
function getFieldFromData(field, data) {
var values = data[field] || '';
var output = values.join ? values.join(', ') : values;
return output;
}

I tried to see your script, but it return this error: Script function not found: doGet
However, you could try do this...
window.location.href = "YOUR_URL";

Related

Problem with Google Apps Script maximum execution time

I'm new to coding and recently I've created a Google script (based on two other scripts) which does the following:
Searches for a Gmail draft by its subject line
Gets the Gmail draft and uses it as a template to create multiple drafts with unique attachments
Puts a confirmation phrase after drafts are created.
Here is the code:
//Change these to match the column names you are using for email recepient addresses and merge status column//
var RECIPIENT_COL = "Email";
var MERGE_STATUS_COL = "M";
//Creates the menu item "Mail Merge" for user to run scripts on drop-down//
function onOpen(e) {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Mail Merge')
.addItem('📌 Create Drafts', 'createDrafts').addToUi();
}
function createDrafts() {
// search for the draft Gmail message to merge with by its subject line
var subjectLine = Browser.inputBox("Select draft " + "to merge with:", "Paste the subject line:", Browser.Buttons.OK_CANCEL);
if (subjectLine === "cancel" || subjectLine == ""){
// if no subject line finish up
return;
}
// get the draft Gmail message to use as a template
var emailTemplate = getGmailTemplateFromDrafts_(subjectLine);
emailTemplate.subject = subjectLine;
// get the data from the active sheet
var sheet = SpreadsheetApp.getActiveSheet();
var dataRange = sheet.getDataRange();
// fetch values for each row in the Range.
var data = dataRange.getValues();
// assuming row 1 contains our column headings
var header = data.shift();
// get the index of column named 'M' (Assume header names are unique)
var draftCreatedColIdx = header.indexOf(MERGE_STATUS_COL);
var object = data.map(function(row) {
// create a new object for next row using the header as a key
var nextRowObject = header.reduce(function(accumulator, currentValue, currentIndex) {
accumulator[currentValue] = row[currentIndex];
return accumulator;
}, {}) // Use {} here rather than initialAccumulatorValue
return nextRowObject;
});
// loop through all the rows of data
object.forEach(function(row, rowIdx){
// only create drafts if mail merge status cell is blank
if (row[MERGE_STATUS_COL] === ''){
var msgObj = fillInTemplateFromObject_(emailTemplate, row);
var attachment_id = "File Name";
// split the values taken from cell into array
var pdfName = row[attachment_id].split(', ');
// initialize files as empty array
var files = [];
// run through cell values and perform search
for(var j in pdfName){
// perform the search,results is a FileIterator
var results = DriveApp.getFilesByName(pdfName[j]);
// interate through files found and add to attachment results
while(results.hasNext()) {
// add files to array
files.push(results.next());
}
}
// #see https://developers.google.com/apps-script/reference/gmail/gmail-app#sendemailrecipient-subject-body-options
GmailApp.createDraft(row[RECIPIENT_COL], msgObj.subject, msgObj.text, {htmlBody: msgObj.html, attachments: files});
// create a confirmation phrase in the first column
sheet.getRange("A" + (rowIdx + 2)).setValue("DRAFT");
}
});
}
/**
* Get a Gmail draft message by matching the subject line.
* #param {string} subject_line to search for draft message
* #return {object} containing the plain and html message body
*/
function getGmailTemplateFromDrafts_(subject_line) {
try {
// get drafts
var drafts = GmailApp.getDrafts();
// filter the drafts that match subject line
var draft = drafts.filter(subjectFilter_(subject_line))[0];
// get the message object
var msg = draft.getMessage();
return {text: msg.getPlainBody(), html:msg.getBody()};
} catch(e) {
throw new Error("Oops - can't find Gmail draft");
}
}
/**
* Filter draft objects with the matching subject linemessage by matching the subject line.
* #param {string} subject_line to search for draft message
* #return {object} GmailDraft object
*/
function subjectFilter_(subject_line){
return function(element) {
if (element.getMessage().getSubject() === subject_line) {
return element;
}
}
}
/**
* Fill HTML string with data object.
* #param {string} template string containing {{}} markers which are replaced with data
* #param {object} data object used to replace {{}} markers
* #return {object} message replaced with data
* H/T https://developers.google.com/apps-script/articles/mail_merge
*/
function fillInTemplateFromObject_(template, data) {
// convert object to string for simple find and replace
template = JSON.stringify(template);
// Search for all the variables to be replaced, for instance {{Column name}}
var templateVars = template.match(/{{([^}]+)}}/g);
// Replace variables from the template with the actual values from the data object.
// If no value is available, replace with the empty string.
for (var i = 0; i < templateVars.length; ++i) {
// strip out {{ }}
var variableData = data[templateVars[i].substring(2, templateVars[i].length - 2)];
template = template.replace(templateVars[i], variableData || "");
}
// convert back to object
return JSON.parse(template);
}
The script works as expected but when I'm trying to process too many rows with too many attachments it exceeds a 6-minute Google Script maximum execution time.
While trying to solve this problem I found a simple script that uses a continuationToken and by doing so never exceeds the limit. My goal is to try to use the same principle in my own script and to process rows by tens. Unfortunatelly, I haven't had any luck so far and need some help. Here's the code of the script that I found:
Code.gs
function onOpen() {
SpreadsheetApp.getUi().createMenu("List Drive files").addItem('Start', 'start').addToUi();
}
function start() {
var ui = HtmlService.createHtmlOutputFromFile('ui');
return SpreadsheetApp.getUi().showSidebar(ui);
}
function getDriveFiles(continuationToken) {
if(continuationToken) {
var files = DriveApp.continueFileIterator(continuationToken);
}
else {
var files = DriveApp.getFiles();
}
var i = 0;
while (files.hasNext() && i < 10) {
var file = files.next();
SpreadsheetApp.getActiveSheet().appendRow([file.getName(), file.getUrl()]);
i++;
if(i == 10) {
return files.getContinuationToken();
}
}
}
ui.html
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons.css">
<div style="text-align:center; margin-top:10px">
<div>Files processed:</div>
<div id="nbOfFilesProcessed">0</div>
<br>
<button id="startButton" class="blue" onclick="start()">Start</button>
<div class="secondary">Close the sidebar to stop the script.</div>
</div>
<script>
function start() {
document.getElementById("startButton").disabled = true;
google.script.run.withSuccessHandler(onSuccess).getDriveFiles();
}
function onSuccess(continuationToken){
// If server function returned a continuationToken it means the task is not complete
// so ask the server to process a new batch.
if(continuationToken) {
var nbOfFilesProcessedEl = document.getElementById("nbOfFilesProcessed");
nbOfFilesProcessedEl.innerHTML = parseInt(nbOfFilesProcessedEl.innerHTML) + 10;
google.script.run.withSuccessHandler(onSuccess).getDriveFiles(continuationToken);
}
}
</script>
From what I see in the code you posted you will have to edit your createDrafts function in this way:
Edit how the function is triggered: you will have to use an HTML ui element to run javascript inside it.
Edit the while loop so that it has a return statement when you hit the limit of your batch.
Create a Javascript function in the HTML ui element that handles the success of the createDrafts function and recursively calls it in case that the continuationToken is returned.
Snippets
UI Component
You can keep your custom menu and on click add this HTML to a UI dialog.
- code.gs -
//Creates the menu item "Mail Merge" for user to run scripts on drop-down//
function onOpen(e) {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Mail Merge')
.addItem('📌 Create Drafts', 'openDialog').addToUi();
}
function openDialog() {
// Display a modal dialog box with custom HtmlService content.
var htmlOutput = HtmlService
.createHtmlOutputFromFile('Dialog')
.setWidth(250)
.setHeight(300);
SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'Create Drafts');
}
- Dialog.html -
<!-- The UI will be very similar to the one you found, I will keep only the strictly necessary statements for this example -->
<div>
<button id="startButton" onclick="startBatch()">Start</button>
</div>
<script>
function startBatch() {
google.script.run.withSuccessHandler(onSuccess).createDrafts();
}
function onSuccess(continuationToken){
// If server function returned a continuationToken it means the task is not complete
// so ask the server to process a new batch.
if(continuationToken) {
google.script.run.withSuccessHandler(onSuccess).createDrafts(continuationToken);
}
}
</script>
Apps Script Component
function createDrafts(continuationToken) {
var batchLimit = 10;
// ...
// run through cell values and perform search
for(var j in pdfName){
// perform the search,results is a FileIterator
if (continuationToken) {
var results = DriveApp.continueFileIterator(continuationToken);
} else {
var results = DriveApp.getFilesByName(pdfName[j]);
}
// interate through files found and add to attachment results
let i = 0;
while(results.hasNext() && i<batchLimit) {
// add files to array
files.push(results.next());
i++;
if (i === batchLimit) {
return results.getContinuationToken();
}
}
}
Final considerations
As an improvement to your batch operation, I would save all the user inputs so that you will be able to continue the script without prompting for it again. You can either pass these values to the return function on a javascript object or save them in the cache with the CacheService utility.
Moreover, try to find the correct trade off between execution time and batch limit: A small batch limit will never hit the time limit but will consume your quota very fast.
References:
Client Side API
Cache Service
Apps Script UI

How to auto populate HTML fields by from Spreadsheet Data using Apps Script?

I want to populate my form fields using Spreadsheet data using Phone number. If the user entered their phone number, fields will be auto populated (Name, email, etc)
Now, its only populating the Full Name.
My Code.GS:
function autoComplete(info){
var opensheet = "https://docs.google.com/spreadsheets/d/xxxxxxxxx/edit#gid=0";
var sso = SpreadsheetApp.openByUrl(opensheet);
var wst = sso.getSheetByName("Invoices");
var data = wst.getRange(2, 1, wst.getLastRow()-1, 5).getValues();
var phoneSearch = data.map(function(r){ return r[0]; });
var newsletter = data.map(function(r){ return r[1]; });
var fullname = data.map(function(r){ return r[2]; });
var email = data.map(function(r){ return r[4]; });
var position = phoneSearch.indexOf(info);
if(position > -1){
return fullname[position];
} else {
return '';
}
}
My Javascript:
function getDetails(){
var info = document.getElementById("phone_number").value;
if(info.length === 14) {
google.script.run.withSuccessHandler(updateInfo).autoComplete(info)
}
}
function updateInfo(fullname){
document.getElementById("full_name").value = fullname;
M.updateTextFields();
}
I want to autocomplete the fields based on spreadsheet data. If user enters the phone number, the fields must be auto-filled up.
See screenshot: https://ibb.co/wJjz205
you might extend your script to return additional values in the object, like:
...
if(position > -1){
return {
'fullname': fullname[position],
'email': email[position]
// add other fields if necessary
}
} else {
return '';
}
...
and then access the vaules as the properties of returned object:
function updateInfo(response){
document.getElementById("full_name").value =response['fullname'];
document.getElementById("email").value =response['email'];
M.updateTextFields();
}

Google apps script sheet, check index of a cell?

I'm trying to send a multi-step web form to a Google sheet, using Google apps script and Ajax.
And because it's a public form and in multi-steps, I want to save the second ajax request to the same row as the first ajax request. And to avoid duplicated submissions, I save a unique id in the first time and check against it in the next submissions.
Assuming this is the sheet structure:
Timestamp step1-col step2-col uniqueId
---------------------------------------------------------------------
1547266627717 step1-data step2-data 1234
My code in GAS as follows:
var uniqueIdColIndex = 4, step2ColIndex = 3;
function doGet(e) {
return handleResponse(e);
}
function handleResponse(e) {
var lock = LockService.getPublicLock();
lock.waitLock(30000);
try {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
var nextRow = sheet.getLastRow() + 1;
var row = [];
//make a search for the uniqueId;
var uniqueIdColValues = sheet.getRange(2, uniqueIdColIndex, sheet.getLastRow()).getValues()[0];
var uniqueIdRowIndex = uniqueIdColValues.indexOf(e.parameters.uniqueId);
//if the uniqueId were saved before:
if (uniqueIdRowIndex > -1) { //<--- this always fail! why?
//make another search for the step2-value;
var step2Data = sheet.getRange(uniqueIdColIndex + 1, step2ColIndex).getValues()[0];
//if the step2-data wasn't saved before, save it;
if (!step2Data) {
sheet.getRange(uniqueIdColIndex + 1, step2ColIndex).setValues([e.parameters.step2data]);
// return a json success results
return ContentService
.createTextOutput(JSON.stringify({"result": "success", "row": nextRow}))
.setMimeType(ContentService.MimeType.JSON);
}
//else: continue writing the form to the sheet;
} else {
//loop through the header columns
for (var i = 0; i < headers.length; i++) {
if (headers[i] === "Timestamp") { //save a 'Timestamp'
row.push(new Date().getTime());
} else { //else use the header names to get data
if (!e.parameters[headers[i]]) {
row.push('');
} else {
row.push(e.parameters[headers[i]]);
}
}
}
//save the data for the first step;
sheet.getRange(nextRow, 1, 1, row.length).setValues([row]);
//return a json success
return ContentService
.createTextOutput(JSON.stringify({"result": "success", "row": nextRow}))
.setMimeType(ContentService.MimeType.JSON);
}
} catch (e) {
// if error return this
return ContentService
.createTextOutput(JSON.stringify({"result": "error", "error": e}))
.setMimeType(ContentService.MimeType.JSON);
} finally { //release lock
lock.releaseLock();
}
}
The problem is:
I always end up getting duplicated submissions in 2 rows like so:
Timestamp step1-col step2-col uniqueId
---------------------------------------------------------------------
1547266627717 step1-data 1234
1547266647568 step2-data 1234
Which happens because my uniqueId check always fails, I guess.
What am I doing wrong?
And how can I merge both steps/ajax requests to the same row?

Refreshing a webpage is actually redirecting to bing

I have a script, in which I am adding custom URL to the browser back button
for this I used this particular script
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script type="text/javascript" src="js/jquery.cookie.js"></script>
<script type="text/javascript" src="js/native.history.js"></script>
<script type="text/javascript" src="js/go.new.js"></script>
<script>
$(window).load(function()
{
setTimeout(backtrap, 100);
if (!($.cookie("clkd"))){
$.cookie("clkd", 1, { expires : 14 , path: '/'});
}
setInterval(toggle_image, 1000);
});
window.onpageshow = function (e) {
if (e.persisted) {
location.reload();
}
};
window.onpopstate = function(event) {
if (document.location.toString().indexOf("redir=1")>0){
window.location.href = "<?=$$last_offer?>";
//window.location.href = "<?=$szLinkURL?>";
}
};
function toggle_image()
{
var height = $('#banner-img').height();
$('#banner-img').toggle();
$('#loader-img').toggle();
$('#loader-img').css({'height':height+'px'});
}
function show_star(rate,id)
{
$('#al-stars-'+id).html('<span class="stars" id="stars-'+id+'">'+parseFloat(rate)+'</span>');
$('#stars-'+id).stars();
}
$.fn.stars = function()
{
return $(this).each(function() {
$(this).html($('<span />').width(Math.max(0, (Math.min(5, parseFloat($(this).html())))) * 16));
});
}
</script>
Now the script seems to work fine, but I face a new proble, that is:
when I am clicking the refresh button on the browser, the page is rediecting to bing.com
but I dont know why this is happening...
in case if needed here's the script in the go.new.js
/**
* go.js
*
* Functions for go.php and the backtrap
*/
// --------------------------------------------------------------------------------------------------------------------
// Code for parsing query string gratefully lifted from http://unixpapa.com/js/querystring.html, with an
// addition for modifying/generating new query strings.
// Query String Parser
//
// qs= new QueryString()
// qs= new QueryString(string)
//
// Create a query string object based on the given query string. If
// no string is given, we use the one from the current page by default.
//
// qs.value(key)
//
// Return a value for the named key. If the key was not defined,
// it will return undefined. If the key was multiply defined it will
// return the last value set. If it was defined without a value, it
// will return an empty string.
//
// qs.values(key)
//
// Return an array of values for the named key. If the key was not
// defined, an empty array will be returned. If the key was multiply
// defined, the values will be given in the order they appeared on
// in the query string.
//
// qs.keys()
//
// Return an array of unique keys in the query string. The order will
// not necessarily be the same as in the original query, and repeated
// keys will only be listed once.
//
// QueryString.decode(string)
//
// This static method is an error tolerant version of the builtin
// function decodeURIComponent(), modified to also change pluses into
// spaces, so that it is suitable for query string decoding. You
// shouldn't usually need to call this yourself as the value(),
// values(), and keys() methods already decode everything they return.
//
// Note: W3C recommends that ; be accepted as an alternative to & for
// separating query string fields. To support that, simply insert a semicolon
// immediately after each ampersand in the regular expression in the first
// function below.
function QueryString(qs)
{
this.dict= {};
// If no query string was passed in use the one from the current page
if (!qs) qs= location.search;
// Delete leading question mark, if there is one
if (qs.charAt(0) == '?') qs= qs.substring(1);
// Parse it
var re= /([^=&]+)(=([^&]*))?/g;
while (match= re.exec(qs))
{
var key= decodeURIComponent(match[1].replace(/\+/g,' '));
var value= match[3] ? QueryString.decode(match[3]) : '';
if (this.dict[key])
this.dict[key].push(value);
else
this.dict[key]= [value];
}
}
QueryString.decode= function(s)
{
s= s.replace(/\+/g,' ');
s= s.replace(/%([EF][0-9A-F])%([89AB][0-9A-F])%([89AB][0-9A-F])/g,
function(code,hex1,hex2,hex3)
{
var n1= parseInt(hex1,16)-0xE0;
var n2= parseInt(hex2,16)-0x80;
if (n1 == 0 && n2 < 32) return code;
var n3= parseInt(hex3,16)-0x80;
var n= (n1<<12) + (n2<<6) + n3;
if (n > 0xFFFF) return code;
return String.fromCharCode(n);
});
s= s.replace(/%([CD][0-9A-F])%([89AB][0-9A-F])/g,
function(code,hex1,hex2)
{
var n1= parseInt(hex1,16)-0xC0;
if (n1 < 2) return code;
var n2= parseInt(hex2,16)-0x80;
return String.fromCharCode((n1<<6)+n2);
});
s= s.replace(/%([0-7][0-9A-F])/g,
function(code,hex)
{
return String.fromCharCode(parseInt(hex,16));
});
return s;
};
QueryString.prototype.value= function (key)
{
var a= this.dict[key];
return a ? a[a.length-1] : undefined;
};
QueryString.prototype.values= function (key)
{
var a= this.dict[key];
return a ? a : [];
};
QueryString.prototype.keys= function ()
{
var a= [];
for (var key in this.dict)
a.push(key);
return a;
};
QueryString.prototype.set = function(key, value)
{
this.dict[key] = [value];
};
QueryString.prototype.add = function(key, value)
{
if (typeof this.dict[key] == 'undefined') {
this.dict[key] = [value];
} else {
this.dict[key].push(value);
}
};
QueryString.prototype.toString = function()
{
var pieces = [];
for (var key in this.dict) {
for (var idx in this.dict[key]) {
pieces.push( encodeURIComponent(key) + '=' + encodeURIComponent(this.dict[key][idx]));
}
}
return pieces.join('&');
};
// --------------------------------------------------------------------------------------------------------------------
// Load ourselves into the user's history, with an altered query string. The 'bt' var tells us what step of the
// back trap we were LAST on. After that, we redirect ourselves to the next URL.
function backtrap() {
var qs = new QueryString();
qs.set('redir', 1);
var own_url = window.location.href;
var qs_at = own_url.indexOf('?');
var doped_url;
if (qs_at == -1) {
doped_url = own_url + '?' + qs.toString();
} else {
doped_url = own_url.substring(0, qs_at) + '?' + qs.toString();
}
History.pushState({}, '', doped_url);
History.pushState({} ,'', own_url);
alert(doped_url);
alert(own_url);
}
for better understanding
check this link and detect
http://gomotrak.com/main/click.php?c=2173&key=jm64njqpq608t19bgqi3fwfq&c2=AA09_00000&c3=[zone]
[NOTE]
The backbutton is working fine, there is no issue with the back-button...
Problem is, when i am clicking on the refresh button of the browser in the address bar, its reloading the bing page.
Also $$last_offer is absolutely fine cause its working this way
if(stripos($ua,'android') !== false)
{
$agent = 'a';
setlocale(LC_ALL, 'pt_BR.UTF-8');
$last_CSVfp = fopen("offer_android.csv", "r");
$last_offer_data = array();
if($last_CSVfp !== FALSE)
{
while(! feof($last_CSVfp))
{
$last_offer_data[] = fgetcsv($last_CSVfp,"",",");
}
}
fclose($last_CSVfp);
$last_arr_size = count($last_offer_data);
$last_offer = "offer".intval(intval($last_arr_size)+1);
}
so $last_offer becomes "offer3" for example
and $$last_offer becomes "$offer3" its like alias of a phpvariabledenoted by anotherphp variable`

Excel Type Filter popup for Jqgrid

I need to have a filter ( like in Excel spread Sheet) to embedded to the 'jquery' dialog popup. in this case i need to show all the unique values in the column and check box just before that value to select to the user. when user pressed filter button i need to filter only the values that user requested through the check boxes.
Can any one please let me any approach that i must follow.
Thanks in advance for your help and valuable time.
I was able to develop basic grid with excel kind of filter feature. any one who will come across this type of requirement can use this answer as a foundation.
I use this answer from 'Oleg' to embed the filter popup screen to the basic 'jqgrid'.
in the jqgrid page declare this array with the attributes (columns) that needs to display the filter screen popup.
var applyFilterColumnNames = ['Id','Type','custId','UserId'];
and the column model should be as follows -
colModel :[
{name:'Id', index:'Id',hidden: true,sortable: true},
{name:'custId', index:'custId', width:140,align:"left",sortable: true,search : false},
{name:'Type', index:'Type', width:120,align:"left",sortable: true,search : false},
{name:'UserId', index:'UserId', width:150,align:"left",sortable: true,search : false},
],
used that reference answer to embed the filter button function.
gr.closest("div.ui-jqgrid-view").find("div.ui-jqgrid-hdiv table.ui-jqgrid-htable tr.ui-jqgrid-labels > th.ui-th-column > div.ui-jqgrid-sortable")
.each(function () {
var idPrefix = "jqgh_" + gr[0].id + "_";
var idIndex = (this.id).substr(idPrefix.length,this.id.length) ;
if(includeInArray(applyFilterColumnNames,idIndex)){
jq('<button id=btn_'+idIndex+'>').css({float: "right", height: "17px"}).appendTo(this).button({
icons: {
primary: "ui-icon-gear"
},
text: false
}).click(function (e) {
var idPrefix = "jqgh_" + gr[0].id + "_";
// thId will be like "jqgh_list_name"
var thId = jq(e.target).closest('div.ui-jqgrid-sortable')[0].id ;
if (thId.substr(0, idPrefix.length) === idPrefix) {
var colName = thId.substr(idPrefix.length);
//alert('Clicked the button in the column "' + colName + '"');
constructFilter(colName);
return false;
}
});
//}
}
});
Below is the script i used to filter the jqgrid according to the filters
//Variables that use in filtering operation
var originalData = null;
var filteredData;
var selectedFilters = new Object();
var chkBoxElement;
var firstSortColumn;
function constructFilter(columnName){
// for the first initiation of the filter populate current grid data to an array
if(originalData == null || originalData == 'null'){
try{
// this array will hold the initail data set of the grid
originalData = gr.jqGrid('getGridParam','data');
// set the first sorting grid column
firstSortColumn = columnName;
// check if column is associated with a formatter. if so format the originalData values accordingly.
formatGridData(columnName);
}catch(e){}
}
var colData = new Array();
var filterDataSet;
// if current column is equal to initial sorted column set all posible values to the check boxes in the
// filter screen to select. ( since this is the master sorting column and other columns will filter according to that)
if(columnName == firstSortColumn){
filterDataSet = originalData;
}else{
// set current grid data set to show as checkboxes in the filter page
filterDataSet = gr.jqGrid('getCol',columnName,false);
}
for(key in filterDataSet){
// check box element object that will hold the checkbox label and its state ( true / false)
chkBoxElement = new Object();
chkBoxElement.id = getValueFromArray(filterDataSet[key],columnName);
if(typeof(chkBoxElement.id)== 'undefined'){
break;
}
// if this id is saved in previous filtering event checked option will set to true.
if(typeof(selectedFilters[columnName]) != 'undefined'){
if (includeInArray(selectedFilters[columnName],chkBoxElement.id)){
chkBoxElement.selected = true;
}else{
chkBoxElement.selected = false;
}
}
colData.push(chkBoxElement);
}
// removing duplicates
var uniqueValues = removeDuplicates(colData);
// sort the array without duplicate with the custom comparator
uniqueValues.sort(sortComparator);
// open the filter screen. return type will captured in the 'seletedElements' variable as pipe separated string
seletedElements = window.showModalDialog(filterUrl,uniqueValues,"dialogWidth:400px;dialogHeight:250px;center:yes;resizable:no;status:no;help:no;");
if(seletedElements != null && seletedElements != 'null'){
// get selected values to the array
selectedFilters[columnName] = seletedElements.split("|");
}else{
//user just close the popup (using close button) will return without doing anything
return;
}
if(columnName == firstSortColumn){
// refine filter with the non filtered data set
refillGrid(seletedElements,columnName,originalData);
}else{
// send current data set to refine
var currentDataSet = gr.jqGrid('getGridParam','data');
refillGrid(seletedElements,columnName,currentDataSet);
}
}
function formatGridData(columnName){
var isFormatter = gr.jqGrid("getColProp",columnName);
if(typeof isFormatter.formatter !== 'undefined') {
if(jq.isFunction( isFormatter.formatter ) ) {
for(key in originalData){
var plainValue = originalData[key][columnName];
var formattedVal = isFormatter.formatter.call(null,plainValue,null,null,null);
originalData[key][columnName] = formattedVal;
}
}
}
}
function resetFilters(){
for(key in applyFilterColumnNames){
jq("#btn_"+applyFilterColumnNames[key]).button("option", {
//icons: { primary: this.checked ? 'ui-icon-check' : 'ui-icon-closethick' }
icons: { primary: 'ui-icon-gear'}
});
}
gr.jqGrid("setCaption",gridCaption);
refreshGrid(originalData);
originalData = null;
firstSortColumn = null;
selectedFilters = new Object();
}
function refillGrid(seletedElements,columnName,filterDataSet){
var filteredData= new Array();
var elementsArray;
try{
elementsArray = seletedElements.split("|");
}catch(e){
// this exception happens when user simply open the filter screen
// do nothing and close it.
trace('Error in filter splitting -'+e);
return;
}
// When user de-select all check boxes from the popup screen
if(elementsArray == ""){
refreshGrid(originalData);
return;
}
// refine the grid data according to the filters
var mydata = filterDataSet;
for(i=0;i<elementsArray.length;i++){
var filterElement = elementsArray[i];
for(j = 0;j<mydata.length;j++){
if(filterElement==getValueFromArray(mydata[j],columnName)){
filteredData.push(mydata[j]);
}
}
}
// change the button icon to indicate that the column is filtered
changeButtonIcon(columnName);
// update the column header to indicate sort by column
changeGridCaption(columnName);
// fill the grid according to the passed array
refreshGrid(filteredData);
}
function changeGridCaption(columnName){
// get columns name array
var columnNames = gr.jqGrid('getGridParam','colNames');
// get column model array
var colModel = gr.jqGrid('getGridParam','colModel');
var colModelIndex=null;
if (firstSortColumn == columnName){
for(key in colModel){
try{
if (colModel[key].name == firstSortColumn){
colModelIndex = key;
break;
}
}catch(e){}
}
if(colModelIndex != null){
var columnName = columnNames[colModelIndex];
gr.jqGrid("setCaption",gridCaption + " - Filtered based on : "+columnName);
}
}
}
function changeButtonIcon(columnName){
//change the button Icon
jq("#btn_"+columnName).button("option", {
//icons: { primary: this.checked ? 'ui-icon-check' : 'ui-icon-closethick' }
icons: { primary: 'ui-icon-link'}
});
}
function getValueFromArray(obj,columnName){
if(obj !=null && typeof(obj)!='undefined'){
// if obj param is string just return it
if(typeof obj =='string'){
return obj;
}else{
return obj[columnName];
}
}
}
function sortComparator(a,b){
try{
var aId = a.id.toLowerCase();
var bId = b.id.toLowerCase();
if (aId < bId) {return 1}
if (aId > bId) {return -1}
}catch(e){
return 0;
}
}
function includeInArray(arr,obj) {
//alert(arr);
return (arr.indexOf(obj) != -1);
}
function refreshGrid(results) {
gr.jqGrid('clearGridData')
.jqGrid('setGridParam', { data: results })
.trigger('reloadGrid');
}
function removeDuplicates(valueArray){
var arr = {};
for ( i=0; i < valueArray.length; i++ ){
if(valueArray[i].id != null){
arr[valueArray[i].id] = valueArray[i];
}
}
valueArray = new Array();
for ( key in arr ){
valueArray.push(arr[key]);
}
return valueArray;
}
If something wrong here please let me know.this solution is working fine. but i really appreciate the comments in therms of performance and code best practices.

Categories

Resources