How to get the first revision without having a delete button? - javascript

<div class="right modal-footer">
<a class="modal-action waves-effect btn-flat left" ng-switch-when="true" ng-click="delete()">Delete</a>
<a class="modal-action waves-effect btn-flat" ng-click="close()">Cancel</a>
<a class="modal-action waves-effect btn-flat" ng-click="save()">Save</a>
</div>
</div>
The first revision or revision A should not have a delete button. Every other revision needs to have one, so that's revision B, C, etc. Does anyone have any ideas on how i can do this?
The above part is the footer for the summary revision dialog. It includes the action buttons of save, cancel, and delete. Delete button is the main focus here.
The below part is the JavaScript controller code that tells what the button to do. When the revision is opened it will display the original revisions details along with which revision this is. the close function is simple, just simply closing the dialog without saving the entered and changed information. The save function is also pretty simple, saves the entered data and will show the changes when the save button is clicked on. The Delete function will delete the current revision and move back the the revision before it, so for example, deleting revision C will display revision B. But what I am trying to do is hide the delete button on Revision A(the first revision) so it will not delete the initial revision and keep the delete button display for any other revision.
Thank you developers for your help.
angular.module('Comet').controller('RevisionEditController', function ($scope, $rootScope, $objectExtensions, $odataModel, $validation, $toast, ProposalsService, ErrorsService) {
const DIALOG_SEL = '#revisionEditDialog';
$scope.originalRevision = null;
$scope.revision = null;
/**
* Opens the dialog.
* #param {number} proposal - The proposal that the revision is for.
* #param {object} [revision] - The existing revision to edit. Null when creating a new revision.
*/
$scope.open = function (proposal, revision) {
$scope.originalRevision = new $odataModel.ProposalDetail(revision);
$scope.revision = new $odataModel.ProposalDetail(revision);
$scope.revision.rev = revision ? revision.rev : getNextRevision(proposal.proposalDetails);
$scope.revision.proposal = {
id: proposal.id
};
$(DIALOG_SEL).modal('open');
};
/**
* Closes the dialog.
*/
$scope.close = function () {
$(DIALOG_SEL).modal('close');
};
/**
* Saves the revision.
*/
$scope.save = function () {
if ($validation.validate($scope.revisionEditForm)) {
$rootScope.dataReady = false;
if ($scope.revision.id) {
ProposalsService.editProposalDetail($scope.revision.proposal.id, $scope.revision.id, $scope.originalRevision, $scope.revision)
.then(onSaveSuccess, onSaveFailure);
} else {
ProposalsService.addProposalDetail($scope.revision.proposal.id, $scope.revision)
.then(onSaveSuccess, onSaveFailure);
}
}
};
/**
* Deletes the revision.
*/
$scope.delete = function () {
ProposalsService.deleteProposalDetail($scope.revision.proposal.id, $scope.revision.id)
.then(onDeleteSuccess, onDeleteFailure);
};
/**
* Calls the revision updated callback and closes the dialog.
* #param {object} updatedRevision - The updated revision.
*/
function onSaveSuccess(updatedRevision) {
$scope.$ctrl.onRevisionUpdated({ revision: updatedRevision });
$scope.close();
$rootScope.dataReady = true;
}
/**
* Displays an error message and logs the exception.
* #param {object} ex - The exception to log.
*/
function onSaveFailure(ex) {
$toast.error('There was an error saving the revision. Please try again.');
ErrorsService.log(ex);
$rootScope.dataReady = true;
}
/**
* Calls the revision deleted callback and closes the dialog.
* #param {number} id - The ID of the revision that was deleted.
*/
function onDeleteSuccess(id) {
$scope.$ctrl.onRevisionDeleted({ id: id });
$scope.close();
$rootScope.dataReady = true;
}
/**
* Displays an error message and logs the exception.
* #param {object} ex - The exception to log.
*/
function onDeleteFailure(ex) {
$toast.error('There was an error deleting the revision. Please try again.');
ErrorsService.log(ex);
$rootScope.dataReady = true;
}
/**
* Gets the next revision number.
* #param {object[]} revisions - The previous revisions.
* #returns {string} The next revision number.
*/
function getNextRevision(revisions) {
var nextRevision = '';
var latestRevision = revisions
.sort(function (a, b) {
var order = 0;
if (a.id > b.id)
order = -1;
else if (a.id < b.id)
order = 1;
return order;
})[0];
if (latestRevision) {
nextRevision = latestRevision.rev ? '' : 'A';
var increment = true;
for (var idx = latestRevision.rev.length - 1; idx >= 0 && increment; idx--) {
var currLetter = latestRevision.rev[idx].charCodeAt(0);
if (currLetter == 90) {
nextRevision = nextRevision + 'A';
} else {
increment = false;
nextRevision = String.fromCharCode(currLetter + 1) + nextRevision;
}
}
if (nextRevision.length < latestRevision.rev.length) {
nextRevision = latestRevision.substring(0, nextRevision.length - 1) + nextRevision;
}
}
return nextRevision;
}

I assume that there is a loop where you iterate the revisions, use the loop's index to check with ngIf if the button should be shown.

Related

How to autofill Google form with random answears using JS

I want to randomly fill a 100 google forms using JS. Is any way to do it?
There is example google form.
I couldn't find anything on stackoverflow or web, only python or java solutions. But I want to do it in javascript if it is possible of course.
Here is a dirty script, which could be a starting point. It only works with the specific form you provided as an example. It uses document.querySelector to target the form elements.
As soon as you'll open the form, it will fill it, submit it, go back to it, submit it, over and over.
To use it:
Install the TamperMonkey extension in Google Chrome
Click on the icon that appeared in your browser, select "Dashboard"
Create a new script, and replace all the content with the code below
Ctrl + S to save
Open the form in a tab and watch it do the work
Code:
// ==UserScript==
// #name GoogleForm Spammer
// #namespace http://tampermonkey.net/
// #version 0.1
// #description Spam a Google Form
// #author You
// #match https://docs.google.com/forms/*
// #grant unsafeWindow
// ==/UserScript==
(function() {
window.addEventListener('load', function() {
if (window.location.pathname.indexOf('/forms/d') === 0) { // If we're on the form page
submitRandomForm();
} else if (window.location.pathname.indexOf('/forms/u') === 0) { // If we're on the "submitted" page
goBackToForm();
}
function submitRandomForm() {
// Size
var radios = document.querySelectorAll(".appsMaterialWizToggleRadiogroupRadioButtonContainer"),
radioIndex = Math.floor(Math.random() * radios.length);
radios[radioIndex].click();
// Print
var checkboxes = document.querySelectorAll(".appsMaterialWizTogglePapercheckboxCheckbox"),
checkboxIndex = Math.floor(Math.random() * checkboxes.length);
checkboxes[checkboxIndex].click();
// Age (between 16 and 45)
var age = Math.floor(Math.random() * 30) + 16;
document.querySelector(".quantumWizTextinputPaperinputInput").value = age;
// Submit
document.querySelector(".freebirdFormviewerViewCenteredContent .appsMaterialWizButtonPaperbuttonLabel").click();
}
function goBackToForm() {
window.location.href = 'https://docs.google.com/forms/d/e/1FAIpQLSd7GueJGytOiQpkhQzo_dCU0oWwbk3L1htKblBO1m14VHSpHw/viewform';
}
});
})();
And here is a little cleaner way. You declare the form URL at the top, the form fields, and for some of them, a function which will return a random value according to your needs.
To try this one out, save that script, and try accessing this form:
// ==UserScript==
// #name GoogleForm Spammer
// #namespace http://tampermonkey.net/
// #version 0.1
// #description Spam a Google Form
// #author You
// #match https://docs.google.com/forms/*
// #grant none
// ==/UserScript==
var formUrl = 'https://docs.google.com/forms/d/e/1FAIpQLSdQ9iT7isDU8IIbyg-wowB-9HGzyq-xu2NyzsOeG0j8fhytmA/viewform';
var formSchema = [
{type: 'radio'}, // A
{type: 'radio'}, // B
{type: 'checkbox'}, // C
{type: 'checkbox'}, // D
{type: 'short_text', func: generateAnswerE }, // E
{type: 'paragraph', func: generateParagraph }, // F
];
function generateAnswerE() {
// Let's say we want a random number
return Math.floor(Math.random() * 30) + 16;
}
function generateParagraph() {
// Just for the example
return "Hello world";
}
(function() {
window.addEventListener('load', function() {
if (window.location.pathname.indexOf('/forms/d') === 0) { // If we're on the form page
submitRandomForm();
} else if (window.location.pathname.indexOf('/forms/u') === 0) { // If we're on the "submitted" page
window.location.href = formUrl;
}
function submitRandomForm() {
var formItems = document.querySelectorAll('.freebirdFormviewerViewItemsItemItem');
for (var i = 0; i < formSchema.length; i++) {
var field = formSchema[i],
item = formItems[i];
switch(field.type) {
case 'radio':
var radios = item.querySelectorAll(".appsMaterialWizToggleRadiogroupRadioButtonContainer"),
radioIndex = Math.floor(Math.random() * radios.length);
radios[radioIndex].click();
break;
case 'checkbox':
var checkboxes = item.querySelectorAll(".appsMaterialWizTogglePapercheckboxCheckbox"),
checkboxIndex = Math.floor(Math.random() * checkboxes.length);
checkboxes[checkboxIndex].click();
break;
case 'short_text':
item.querySelector(".quantumWizTextinputPaperinputInput").value = field.func();
break;
case 'paragraph':
item.querySelector(".quantumWizTextinputPapertextareaInput").value = field.func();
break;
}
}
// Submit
document.querySelector(".freebirdFormviewerViewCenteredContent .appsMaterialWizButtonPaperbuttonLabel").click();
}
});
})();

How to call a function on change of window.checkoutConfig data so to refresh the content of checkout page Magento 2

In my checkout page when promo code is applied, I am updating a text using some calculation in knockoutjs
So, I am using window.checkoutConfig data in my js for some calculation.
the function works well when called from HTML, but it doesn't run on itself when window.checkoutConfig data is changed, I need to reload the page to see my changes.
And this is what knockoutjs is for, Automatic UI Refresh.
Magento_Checkout/web/template/summary/item/details.html
<span class="tag-text">
<!-- ko if: getFinalSale($parent)-->
<u class="product-tag underline-bold-text checkout-final-sale" data-bind="text: getFinalSale($parent)"></u>
<!-- /ko -->
</span>
I have written above code in details.html
and my js is
Magento_Checkout/web/js/view/summary/item/details.js
knockout js
define([
'uiComponent',
'ko',
'Magento_Checkout/js/model/totals'
], function (Component, ko, totals) {
'use strict';
var finalSaleData = window.checkoutConfig.items;
return Component.extend({
defaults: {
template: 'Magento_Checkout/summary/item/details'
},
quoteItemData: quoteItemData,
finalSaleData: finalSaleData,
/**
* #param {Object} quoteItem
* #return {String}
*/
getItems: function(item_id) {
var itemElement = null;
_.each(this.finalSaleData, function(element, index) {
if (element.item_id == item_id) {
itemElement = element;
}
});
return itemElement;
},
getFinalSale: function (quoteItem) {
var item = this.getItems(quoteItem.item_id);
var tagText = '';
if((((item.price*item.qty) - item.discount_amount)/(item.base_old_price*item.qty))< 0.5){
var tagText = 'Final Sale';
}else{
if(item.base_old_price && item.price){
// && item.price < item.price && item.base_old_price / item.price <= 0.5){
if(((item.base_old_price - item.price)/item.base_old_price)>0.5){
var tagText = 'Final Sale';
}
}
}
return tagText;
},
});
});
I am using var finalSaleData = window.checkoutConfig.items in my function getFinalSale.
How to make getFinalSale function run every time when window.checkoutConfig.items data is changed without refreshing the page.
The problem is, this runs only when the page reloads.
How to make getFinalSale function run every time the user applies promo code without refreshing the page so that my HTML gets updated too.
Basically Final Sale text needs to be shown on the basis of that logic in js code in getFinalSale function.
How to achieve that.

Insert inline image to automatic email response via google forms

I am trying to insert a company logo into an automatic email that is sent out to customers who fill in a form via our website (which is linked to google forms). I am using the script to generate the automatic email and I can't seem to find out how to insert an inline image. I'm currently linking to an online image we have and it doesn't work well because the aspect ratio seems to vary depending on which device you are using.
Could someone please amend my code below so that it works with an inline image. Many thanks.
/**
* #OnlyCurrentDoc Limits the script to only accessing the current form.
*/
var DIALOG_TITLE = 'Example Dialog';
var SIDEBAR_TITLE = 'Example Sidebar';
/**
* Adds a custom menu with items to show the sidebar and dialog.
*
* #param {Object} e The event parameter for a simple onOpen trigger.
*/
function onOpen(e) {
FormApp.getUi()
.createAddonMenu()
.addItem('Show sidebar', 'showSidebar')
.addItem('Show dialog', 'showDialog')
.addToUi();
}
/**
* Runs when the add-on is installed; calls onOpen() to ensure menu creation and
* any other initializion work is done immediately.
*
* #param {Object} e The event parameter for a simple onInstall trigger.
*/
function onInstall(e) {
onOpen(e);
}
/**
* Opens a sidebar. The sidebar structure is described in the Sidebar.html
* project file.
*/
function showSidebar() {
var ui = HtmlService.createTemplateFromFile('Sidebar')
.evaluate()
.setTitle(SIDEBAR_TITLE);
FormApp.getUi().showSidebar(ui);
}
/**
* Opens a dialog. The dialog structure is described in the Dialog.html
* project file.
*/
function showDialog() {
var ui = HtmlService.createTemplateFromFile('Dialog')
.evaluate()
.setWidth(350)
.setHeight(170);
FormApp.getUi().showModalDialog(ui, DIALOG_TITLE);
}
/**
* Appends a new form item to the current form.
*
* #param {Object} itemData a collection of String data used to
* determine the exact form item created.
*/
function addFormItem(itemData) {
// Use data collected from sidebar to manipulate the form.
var form = FormApp.getActiveForm();
switch (itemData.type) {
case 'Date':
form.addDateItem().setTitle(itemData.name);
break;
case 'Scale':
form.addScaleItem().setTitle(itemData.name);
break;
case 'Text':
form.addTextItem().setTitle(itemData.name);
break;
}
}
/**
* Queries the form DocumentProperties to determine whether the formResponse
* trigger is enabled or not.
*
* #return {Boolean} True if the form submit trigger is enabled; false
* otherwise.
*/
function getTriggerState() {
// Retrieve and return the information requested by the dialog.
var properties = PropertiesService.getDocumentProperties();
return properties.getProperty('triggerId') != null;
}
/**
* Turns the form submit trigger on or off based on the given argument.
*
* #param {Boolean} enableTrigger whether to turn on the form submit
* trigger or not
*/
function adjustFormSubmitTrigger(enableTrigger) {
// Use data collected from dialog to manipulate form.
// Determine existing state of trigger on the server.
var form = FormApp.getActiveForm();
var properties = PropertiesService.getDocumentProperties();
var triggerId = properties.getProperty('triggerId');
if (!enableTrigger && triggerId != null) {
// Delete the existing trigger.
var triggers = ScriptApp.getUserTriggers(form);
for (var i = 0; i < triggers.length; i++) {
if (triggers[i].getUniqueId() == triggerId) {
ScriptApp.deleteTrigger(triggers[i]);
break;
}
}
properties.deleteProperty('triggerId');
} else if (enableTrigger && triggerId == null) {
// Create a new trigger.
var trigger = ScriptApp.newTrigger('respondToFormSubmit')
.forForm(form)
.onFormSubmit()
.create();
properties.setProperty('triggerId', trigger.getUniqueId());
}
}
/**
* Responds to form submit events if a form summit trigger is enabled.
* Collects some form information and sends it as an email to the form creator.
*
* #param {Object} e The event parameter created by a form
* submission; see
* https://developers.google.com/apps-script/understanding_events
*/
function respondToFormSubmit(e) {
if (MailApp.getRemainingDailyQuota() > 0) {
var form = FormApp.getActiveForm();
var message = 'There have been ' + form.getResponses().length +
' response(s) so far. Latest Response:\n';
var itemResponses = e.response.getItemResponses();
for (var i = 0; i < itemResponses.length; i++) {
var itemTitle = itemResponses[i].getItem().getTitle();
var itemResponse = JSON.stringify(itemResponses[i].getResponse());
message += itemTitle + ': ' + itemResponse + '\n';
}
MailApp.sendEmail(
Session.getEffectiveUser().getEmail(),
'Form response received for form ' + form.getTitle(),
message,
{name: 'Forms Add-on Template'});
}
}
/* Send Confirmation Email with Google Forms */
function Initialize() {
var triggers = ScriptApp.getProjectTriggers();
for (var i in triggers) {
ScriptApp.deleteTrigger(triggers[i]);
}
ScriptApp.newTrigger("SendConfirmationMail")
.forSpreadsheet(SpreadsheetApp.getActiveSpreadsheet())
.onFormSubmit()
.create();
}
function SendConfirmationMail(e) {
try {
var ss, bcc, sendername, subject, columns, submitter;
var message, value, textbody, sender, aliases;
// Log the aliases for this Gmail account and send an email as the first one.
var aliases = GmailApp.getAliases();
// This is your email address and you will be in the CC
bcc = aliases[0];
// This will show up as the sender's name
sendername = "The Flatser Team";
// This is the submitter's name
submitter = e.namedValues["Full Name"].toString();
// This is the submitter's email address
sender = e.namedValues["Email Address"].toString();
// Optional but change the following variable
// to have a custom subject for Google Docs emails
subject = "Please select a call time";
// This is the body of the auto-reply
message = "Dear "+ submitter + ", <br/><br/>Thank you for completing our form. Please fill in your availability for a telephone or skype call using the link below.<br/><br/>https://calendly.com/bcwolf/flatser-skype-call/06-23-2015<br/><br/><br/>Kind regards,<br/><br/>--<br/><br/><b>The Flatser Team</b><br/><a href='www.flatser.com'>www.flatser.com</a><br/><br/><img width='10%' height='10%' src='http://flatser.com/img/logo1.png'/>";
ss = SpreadsheetApp.getActiveSheet();
columns = ss.getRange(1, 1, 1, ss.getLastColumn()).getValues()[0];
textbody = message.replace("<br>", "\n");
GmailApp.sendEmail(sender, subject, textbody,
{bcc: bcc, name: sendername, htmlBody: message, from: aliases[0] });
} catch (e) {
Logger.log(e.toString());
}
}
You can set different widths according to different devices in your email using media queries.
In your case, i would prepend the <style> in your message variable for function SendConfirmationMail and add class to img tag inside the message variable which will then look as follows:
BODY OF MESSAGE ( assuming you need 100px width logo on mobile and 200px width on bigger screens. Also note do not set the height as it will ruin the aspect ratio if you calculate it incorrectly)
// This is the body of the auto-reply
// This is what i would add
message = "<style> #media (max-width:499px) { .logo__flaster { width: 100px; } #media (min-width:500px) { .logo__flaster { width: 200px; } </style>"
// This is same, i have only removed width from img and added class logo__flaster which i used in the style above.
message += "Dear "+ submitter + ", <br/><br/>Thank you for completing our form. Please fill in your availability for a telephone or skype call using the link below.<br/><br/>https://calendly.com/bcwolf/flatser-skype-call/06-23-2015<br/><br/><br/>Kind regards,<br/><br/>--<br/><br/><b>The Flatser Team</b><br/><a href='www.flatser.com'>www.flatser.com</a><br/><br/><img class='logo__flaster' src='http://flatser.com/img/logo1.png'/>";
Please read Media Queries in HTML Email article for more information, Also see more media queries templates if you want to customise more to a specific screen.

How to poll a Google Doc from an add-on

A documented restriction with document and sheet add-ons is that Apps Script cannot tell what a user does outside of the add-on. This tantalizing tip is given:
It is possible to poll for changes in a file's contents from a
sidebar's client-side code, although you'll always have a slight
delay. That technique can also alert your script to changes in the
user's selected cells (in Sheets) and cursor or selection (in Docs).
Sadly, this isn't shown in any of the demo code. How can I do it?
The polling is done from the html code in your add-on's User Interface, calling across to server-side Apps Script functions using google.script.run.
Using jQuery simplifies this, and we can even start with the answers from jQuery, simple polling example.
function doPoll(){
$.post('ajax/test.html', function(data) {
alert(data); // process results here
setTimeout(doPoll,5000);
});
}
The basic idea can work for Google Apps Script, if we replace the ajax calls with the GAS equivalents.
Here's the skeleton of the poll function that you would use in your html file:
/**
* On document load, assign click handlers to button(s), add
* elements that should start hidden (avoids "flashing"), and
* start polling for document updates.
*/
$(function() {
// assign click handler(s)
// Add elements that should start hidden
// Start polling for updates
poll();
});
/**
* Poll a server-side function 'serverFunction' at the given interval
* and update DOM elements with results.
*
* #param {Number} interval (optional) Time in ms between polls.
* Default is 2s (2000ms)
*/
function poll(interval){
interval = interval || 2000;
setTimeout(function(){
google.script.run
.withSuccessHandler(
function(results) {
$('#some-element').updateWith(results);
//Setup the next poll recursively
poll(interval);
})
.withFailureHandler(
function(msg, element) {
showError(msg, $('#button-bar'));
element.disabled = false;
})
.serverFunction();
}, interval);
};
Add-on Example, Document Poller
This is a demonstration of the jQuery polling technique calling server-side Google Apps Script functions to detect user behavior in a Google Document. It does nothing useful, but it showcases a few things that would typically require knowledge of the user's activity and state of the document, for instance context-sensitve control over a button.
The same principle could apply to a spreadsheet, or a stand-alone GAS Web Application.
Like the UI App example in this question, this technique could be used to get around execution time limits, for operations with a User Interface at least.
The code builds upon the example add-on from Google's 5-minute quickstart. Follow the instructions from that guide, using the code below instead of that in the quickstart.
Code.gs
/**
* Creates a menu entry in the Google Docs UI when the document is opened.
*
* #param {object} e The event parameter for a simple onOpen trigger. To
* determine which authorization mode (ScriptApp.AuthMode) the trigger is
* running in, inspect e.authMode.
*/
function onOpen(e) {
DocumentApp.getUi().createAddonMenu()
.addItem('Start', 'showSidebar')
.addToUi();
}
/**
* Runs when the add-on is installed.
*
* #param {object} e The event parameter for a simple onInstall trigger. To
* determine which authorization mode (ScriptApp.AuthMode) the trigger is
* running in, inspect e.authMode. (In practice, onInstall triggers always
* run in AuthMode.FULL, but onOpen triggers may be AuthMode.LIMITED or
* AuthMode.NONE.)
*/
function onInstall(e) {
onOpen(e);
}
/**
* Opens a sidebar in the document containing the add-on's user interface.
*/
function showSidebar() {
var ui = HtmlService.createHtmlOutputFromFile('Sidebar')
.setTitle('Document Poller');
DocumentApp.getUi().showSidebar(ui);
}
/**
* Check if there is a current text selection.
*
* #return {boolean} 'true' if any document text is selected
*/
function checkSelection() {
return {isSelection : !!(DocumentApp.getActiveDocument().getSelection()),
cursorWord : getCursorWord()};
}
/**
* Gets the text the user has selected. If there is no selection,
* this function displays an error message.
*
* #return {Array.<string>} The selected text.
*/
function getSelectedText() {
var selection = DocumentApp.getActiveDocument().getSelection();
if (selection) {
var text = [];
var elements = selection.getSelectedElements();
for (var i = 0; i < elements.length; i++) {
if (elements[i].isPartial()) {
var element = elements[i].getElement().asText();
var startIndex = elements[i].getStartOffset();
var endIndex = elements[i].getEndOffsetInclusive();
text.push(element.getText().substring(startIndex, endIndex + 1));
} else {
var element = elements[i].getElement();
// Only translate elements that can be edited as text; skip images and
// other non-text elements.
if (element.editAsText) {
var elementText = element.asText().getText();
// This check is necessary to exclude images, which return a blank
// text element.
if (elementText != '') {
text.push(elementText);
}
}
}
}
if (text.length == 0) {
throw 'Please select some text.';
}
return text;
} else {
throw 'Please select some text.';
}
}
/**
* Returns the word at the current cursor location in the document.
*
* #return {string} The word at cursor location.
*/
function getCursorWord() {
var cursor = DocumentApp.getActiveDocument().getCursor();
var word = "<selection>";
if (cursor) {
var offset = cursor.getSurroundingTextOffset();
var text = cursor.getSurroundingText().getText();
word = getWordAt(text,offset);
if (word == "") word = "<whitespace>";
}
return word;
}
/**
* Returns the word at the index 'pos' in 'str'.
* From https://stackoverflow.com/questions/5173316/finding-the-word-at-a-position-in-javascript/5174867#5174867
*/
function getWordAt(str, pos) {
// Perform type conversions.
str = String(str);
pos = Number(pos) >>> 0;
// Search for the word's beginning and end.
var left = str.slice(0, pos + 1).search(/\S+$/),
right = str.slice(pos).search(/\s/);
// The last word in the string is a special case.
if (right < 0) {
return str.slice(left);
}
// Return the word, using the located bounds to extract it from the string.
return str.slice(left, right + pos);
}
Sidebar.html
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons.css">
<!-- The CSS package above applies Google styling to buttons and other elements. -->
<div class="sidebar branding-below">
<form>
<div class="block" id="button-bar">
<button class="blue" id="get-selection" disabled="disable">Get selection</button>
</div>
</form>
</div>
<div class="sidebar bottom">
<img alt="Add-on logo" class="logo" height="27"
id="logo"
src="https://www.gravatar.com/avatar/adad1d8ad010a76a83574b1fff4caa46?s=128&d=identicon&r=PG">
<span class="gray branding-text">by Mogsdad, D.Bingham</span>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js">
</script>
<script>
/**
* On document load, assign click handlers to button(s), add
* elements that should start hidden (avoids "flashing"), and
* start polling for document selections.
*/
$(function() {
// assign click handler(s)
$('#get-selection').click(getSelection);
// Add elements that should start hidden
var newdiv1 = $( "<div class='block' id='cursor-word'/>" ).hide(),
newdiv2 = $( "<div class='block' id='selected-text'/>" ).hide();
$('#button-bar').after( newdiv1, newdiv2 );
$('#cursor-word').html('<H2>Word at cursor:</H2><p id="cursor-word-content"></p>');
$('#selected-text').html('<H2>Selected text:</H2><p id="selected-text-content"></p>');
// Start polling for updates
poll();
});
/**
* Poll the server-side 'checkSelection' function at the given
* interval for document selection, and enable or disable the
* '#get-selection' button.
*
* #param {Number} interval (optional) Time in ms between polls.
* Default is 2s (2000ms)
*/
function poll(interval){
interval = interval || 2000;
setTimeout(function(){
google.script.run
.withSuccessHandler(
function(cursor) {
if (cursor.isSelection) {
// Text has been selected: enable button, hide cursor word.
$('#get-selection').attr('disabled', false);
$('#cursor-word').hide();
// $('#selected-text').show(); // Not so fast - wait until button is clicked.
}
else {
$('#get-selection').attr('disabled', true);
$('#cursor-word').show();
$('#selected-text').hide();
}
$('#cursor-word-content').text(cursor.cursorWord);
//Setup the next poll recursively
poll(interval);
})
.withFailureHandler(
function(msg, element) {
showError(msg, $('#button-bar'));
element.disabled = false;
})
.checkSelection();
}, interval);
};
/**
* Runs a server-side function to retrieve the currently
* selected text.
*/
function getSelection() {
this.disabled = true;
$('#error').remove();
google.script.run
.withSuccessHandler(
function(selectedText, element) {
// Show selected text
$('#selected-text-content').text(selectedText);
$('#selected-text').show();
element.disabled = false;
})
.withFailureHandler(
function(msg, element) {
showError(msg, $('#button-bar'));
element.disabled = false;
})
.withUserObject(this)
.getSelectedText();
}
/**
* Inserts a div that contains an error message after a given element.
*
* #param msg The error message to display.
* #param element The element after which to display the error.
*/
function showError(msg, element) {
var div = $('<div id="error" class="error">' + msg + '</div>');
$(element).after(div);
}
</script>
Polling Interval
The setTimeout() function accepts a time interval expressed in milliseconds, but I found through experimentation that a two-second response was the best that could be expected. Therefore, the skeleton poll() has a 2000ms interval as its default. If your situation can tolerate a longer delay between poll cycles, then provide a larger value with the onLoad call to poll(), e.g. poll(10000) for a 10-second poll cycle.
Sheets
For a sheet example see How do I make a Sidebar display values from cells?

adding 'Next' 'Random' 'previous' buttons to this random image script

I have a random image script, which displays random images on each page load. I want to add Next, Previous and Random buttons to this script, but don't know how to implement them.
Here's the Script
<script type="text/javascript">
var Statements = new Array(
'<img src="http://4.bp.blogspot.com/_UdzqQpb36Jo/R9kVS0h1BFI/AAAAAAAAD_o/SRGugAQSF0A/s1600/timming_pictures_37.jpg" height="650" width="625">',
'<img src="http://4.bp.blogspot.com/_UdzqQpb36Jo/SCxOksTrn4I/AAAAAAAAFDg/q3RilNGj9kc/s1600/loving_husbands_03.jpg" height="650" width="625">',
'<img src="http://3.bp.blogspot.com/_lCRnsgTQgRo/Se2KNaw6bpI/AAAAAAAAA5c/yV2PCN0Pmyo/s1600/pic22806.jpg" height="650" width="625">',
'<img src="http://1.bp.blogspot.com/_lCRnsgTQgRo/Se2J4mZjNEI/AAAAAAAAA4s/Q6Z8IlWLS-A/s1600/pic14006.jpg" height="650" width="625">'
);
function GetStatement(outputtype)
{
if(++Number > Statements.length - 1) Number = 0;
if (outputtype==0)
document.write(Statements[Number])
else if (document.getElementById)
document.getElementById("ponder").innerHTML=Statements[Number];
}
function GetRandomNumber(lbound, ubound)
{
return (Math.floor(Math.random() * (ubound - lbound)) + lbound);
}
var Number = GetRandomNumber(0, Statements.length - 1);
</script>
<script type="text/javascript">
GetStatement(0)
</script>
PS. I am using this script in blogger blog as blogpost.
Based on the request from first my answer, here the code:
HTML code:
<body onload="showPicNo(a)">
<div id="picture"><img name="picturegallery"></div>
<div id="navigation">
Backward |
Forward |
Share site
</div>
<body>
And the modifed Javascript code:
/*
The array 'pics' contains all adresses of picture you want to show. Scrope: global
*/
var pics=new Array (
"https://www.gravatar.com/avatar/9be5d328127c377109b295b5941733fb?s=32&d=identicon&r=PG",
"https://www.gravatar.com/avatar/1e81ddcda5d50a39c2beeaba3797702a?s=32&d=identicon&r=PG&f=1",
"https://www.gravatar.com/avatar/f47359966d28f2e603b6f759855970db?s=32&d=identicon&r=PG&f=1",
"https://www.gravatar.com/avatar/7d1a2026b0dca412b04ec548397b37f6?s=32&d=identicon&r=PG"
);
/*
The variable to used as the minimum number of elements and container for the current picture.
Because we work with an array, the index from first array element is zero.
Scope: global
*/
var a = 0;
/*
The variabe that used as the maximum number of showed pictures.
Here: The number of elements from array 'pics'. Scrope: global
*/
var b = pics.length;
/*
The current url that contains the adressbar from browser. Scope: global
*/
var currentUrl = document.URL;
/*
---------------------------------------------------------------------------------
Initial quicktest, if the parameter 'picnoprogram' does exits.
The parameter 'picnoprogram' is used parallel as an indicator and
as persistance layer.
Scope: global
*/
var existsPicParameter = currentUrl.match(/picnoparam\S*/i);
/*
Some helper variables. Scope: global
*/
var tmpPicParameter, tmpPicParameterOld;
/*
First requirement: If the page was loaded at the first time, it shall be show a
random picture from all available pictures.
The value of variable 'existsPicParamete' will be Null, if the parameter does not
exists in the adress bar; else a list of elements will be stored in there.
*/
if (existsPicParameter != null)
{
/*
So the page wasn't been loaded at first time.
We need the index from the last showed picture.
*/
tmpPicParameter = existsPicParameter[0].match(/picnoparam=\d+/i);
if (tmpPicParameter != null)
{
/*
Extracting the index from string
*/
a = parseInt(tmpPicParameter[0].match(/\d+/i));
tmpPicParameterOld = tmpPicParameter[0];
}
} else {
/*
So the page was loaded at the first time.
Generate a random number, within the declared range.
*/
a = Math.floor(Math.random() * (b - a)) + a;
}
/*
End of the initial quicktest
---------------------------------------------------------------------------------
*/
/*
The javascript function for forward scrolling.
It needs an explicit call.
*/
function fw()
{
if (a == (b - 1))
{
/*
The index of last array element is the array length minus 1.
Then reset the counter variable.
*/
a = 0;
} else {
a++;
}
navigate(a);
}
/*
The javascript function for backward scrolling.
It needs an explicit call.
*/
function bw()
{
if (a == 0)
{
a = b - 1;
} else {
a--
}
navigate(a);
}
/*
The javascript function that modified the page url
*/
function navigate(a)
{
if (existsPicParameter == null)
{
if (currentUrl.indexOf("?") == -1)
{
currentUrl += "?";
} else {
/*
In case there were already one or more url parameters,
the seporerator for another one is '&'
*/
currentUrl += "&";
}
/*
Extend the current url with parameter 'picnoprogram'.
*/
currentUrl += "picnoparam="+a;
} else {
/*
Update the current parameter value in the adressbar with the new one,
by replacing.
Only if the parameter 'picnoprogram' had been alerady exist
*/
tmpPicParameter[0] = tmpPicParameter[0].replace(/\d+/i,a);
currentUrl = currentUrl.replace(tmpPicParameterOld,tmpPicParameter[0]);
}
/* "Reload the site" */
window.location.replace(currentUrl);
}
/*
The javascript function for assigning the stored url to the HTML element 'img'.
It needs an explicit call.
*/
function showPicNo(picNumber)
{
window.document.images["picturegallery"].src=pics[picNumber];
}
/*
The javascript function that uses the share service from facebook.
See: http://stackoverflow.com/questions/13223951/facebook-share-button-how-to-implement .
It needs an explicit call.
*/
function shareButton()
{
/*
This ist the main part of the solution
*/
var facebooksUrlForSharingSites = 'https://www.facebook.com/sharer/sharer.php?u='
facebooksUrlForSharingSites += document.URL;
/*
An example way how to transfer the sharing data
*/
window.open(facebooksUrlForSharingSites,450,420);
}
Hopefully it meets your requirement.
I don't know your surrounding HTML code. In my eyes you should throw away your code.
Here a simple image gallery that should meet your requirements:
HTML code:
<html>
<head>
<meta http-equiv="expires" content="0">
</head>
<body onload="randomStartPic()">
<div id="picture"><img name="picturegallery"></div>
<div id="navigation">
Backward | Forward
</div>
<body>
</html>
And the Javascript code:
var pics=new Array ("http://4.bp.blogspot.com/_UdzqQpb36Jo/R9kVS0h1BFI/AAAAAAAAD_o/SRGugAQSF0A/s1600/timming_pictures_37.jpg", ...)
var a=0, b = pics.length;
function fw()
{
if (a == (b - 1))
{
a = 0;
} else {
a++;
}
showPicNo(a);
}
function bw()
{
if (a == 0)
{
a = b - 1;
} else {
a--;
}
showPicNo(a);
}
function randomStartPic()
{
a = Math.floor(Math.random() * (b - a)) + a;
showPicNo(a);
}
function showPicNo(picNumber)
{
window.document.images["picturegallery"].src=pics[picNumber];
}
At my local computer it did work perfectly...

Categories