I have a Google Slide where
Slide1 has Layout by name "Layout1"
Slide2 has Layout by name "Layout2"
Slide3 has Layout by name "Layout3"
I want to modify the slide layout of Slide2 from "Layout2" to "Layout1" by specifying the Slidename
Hence my input to function will be SlideIndex AND Layout name
Please note that "Layout1" and "Layout2" and "Layout3" are the names of Layouts they are NOT PREDEFINED LAYOUT NAMES
Sample presentation https://docs.google.com/presentation/d/13D5u4mvYF2sNpCpYtyklqxVmMQ5FPV71UoKsk4Zhf8o/copy here is the sample
function changeSlideLayout() {
var presentation = SlidesApp.getActivePresentation();
var slide = presentation.getSlides()[0];
// Change layout to title slide
slide.setLayout(SlidesApp.Layout.TITLE_SLIDE);
// Change background color to red
slide.setBackgroundColor('#FF0000');
}
After doing some research, it seems that it is not possible to update layouts with the Slides API. You can see here the kind of updates to apply to a presentation.
This is a product limitation for Google Slide API, this request can be promoted for future development through here.
What you can do is insert a new slide and apply a custom layout, here is an example if it helps.
function slideLayout() {
var presentation = SlidesApp.getActivePresentation();
var layouts = presentation.getLayouts();
var layout;
for(var i in layouts)
{
if(layouts[i].getLayoutName() == "2_Blank")
{
layout = layouts[i];
Logger.log(i)
}
}
presentation.appendSlide(layout);
}
Related
I've built an add-on for Google Workspace using the CardService functions. The add-on runs in Gmail and posts a logo at the top. Aesthetically, the logo looks great on desktop. However, on mobile the logo takes up too much room.
Current code is as follows (snippet and with other data removed):
var imageBytes = DriveApp.getFileById(LogoID).getBlob().getBytes();
var encodedImageURL = "data:image/jpeg;base64," + Utilities.base64Encode(imageBytes);
function cardbuild(isHomepage, section) {
// Explicitly set the value of isHomepage as false if null or undefined.
if (!isHomepage) {
isHomepage = false;
}
// Create common elements (Image, Footer)
var image = CardService.newImage()
//.setImageUrl(logourl)
.setImageUrl(encodedImageURL)
.setAltText('Logo');
var footer = CardService.newFixedFooter()
.setPrimaryButton(CardService.newTextButton()
.setText('v. 2.5:2021-05-12')
.setOpenLink(CardService.newOpenLink()
.setUrl(editurl)));
var header = CardService.newCardSection()
.addWidget(image);
var card = CardService.newCardBuilder()
.addSection(header)
.setFixedFooter(footer);
return card.build();
}
Is there a way for me to use the encodedImageURL to set a smaller size of the image? Alternatively, does anyone know of a way to improve resizing when the add-on runs on Gmail for Android?
I want set transparent for specific element, i follow this code:
var instanceTree = this.viewer.model.getInstanceTree();
var fragList = this.viewer.model.getFragmentList();
this.listElement.forEach(element => {
instanceTree.enumNodeFragments(element, (fragId) => {
console.log(element.material)
var material = fragList.getMaterial(fragId)
if (material) {
material.opacity = value;
material.transparent = true;
material.needsUpdate = true;
}
});
});
this.viewer.impl.invalidate(true, true, true);
but it overide for all elements have that material. How can i set for selected element?
Appreciate any comments.
UPDATE 1:
i found go around way is clone main material than register it with different name:
var newMaterial = material.clone();
const materials = this.viewer.impl.matman();
materials.addMaterial('mymaterial',newMaterial,true);
fragList.setMaterial(fragId,newMaterial);
newMaterial.opacity = value;
newMaterial.transparent = true;
newMaterial.needsUpdate = true;
but effect is not what i want, it has different color and when set transparent i can only see a couple object behind it
You can create your own, custom THREE.js material and assign it to the fragment using fragList.setMaterial(fragId, material).
For more information on using custom materials or shaders, see https://forge.autodesk.com/blog/custom-shader-materials-forge-viewer.
EDIT:
Regarding the visual anomalies (for example, when you only see some of the objects behind something semi-transparent), this is a known problem, unfortunately with no clear solution. When the Forge Model Derivative service creates an SVF file to be viewed in Forge Viewer, the individual scene elements are stored in a data structure optimized for fast traversal, depending on whether they are semi-transparent or fully opaque. This data structure is fixed, and so unfortunately, when you take an object that was originally fully opaque, and you make it semi-transparent, it will most likely be rendered in a wrong order...
I'm trying to copy a Header/Footer from the active Doc acting as a template to a newly created Doc. I'm able to get the text easy enough, but I'm not able to get the formatting, fonts or horizontal alignment.
My theory was that I could do something like
newDocHeader.setAttributes(activeDocHeader.getAttributes());
But, I still only see plain text that is left aligned. When inspecting the attributes object on the header i get the following:
({
FONT_SIZE:null,
ITALIC:null,
STRIKETHROUGH:null,
FOREGROUND_COLOR:null,
BOLD:null,
LINK_URL:null,
UNDERLINE:null,
FONT_FAMILY:null,
BACKGROUND_COLOR:null
})
I tried to loop through the Child objects of the Header and perform a similar setAttributes(getAttributes) on each child, but to no avail.
I also thought the copy() function on the Header/Footer object would be promising, but when I tried
newDocFooter = activeDocFooter.copy();
But, this produces a blank footer with no text or formatting.
Is there a good way to copy the formatting, font and horizontal alignment from one Header/Footer to another?
I'm entirely unfamiliar with DocumentApp, but this broadly worked for me:
/**
* Copies headers from one document to another.
* #param {string} source The source document URL.
* #param {string} target The target document URL.
*/
function copyHeader(source, target) {
// Used to map from child types to required "append<X>" method
var functionMap = {
PARAGRAPH: 'appendParagraph',
LIST_ITEM: 'appendListItem',
HORIZONTAL_RULE: 'appendHorizontalRule',
IMAGE: 'appendImage',
TABLE: 'appendTable'
};
var t = DocumentApp.openByUrl(target);
var s = DocumentApp.openByUrl(source);
var sourceHeader = s.getHeader();
var targetHeader = t.getHeader();
// If there is no header in the target doc, add one
if (!targetHeader) {
targetHeader = t.addHeader();
}
targetHeader.clear();
// Docs requires one child element, so one will remain even
// after clearing. Get a reference to it so it can be removed
var targetNumChild = targetHeader.getNumChildren();
if (targetNumChild === 1) {
var placeholderElement = targetHeader.getChild(0);
}
// Copy across each element to the target doc
var c = sourceHeader.getNumChildren();
for (var i = 0; i < c; i++) {
var element = sourceHeader.getChild(i).copy();
var method = functionMap[element.getType()];
targetHeader[method](element);
}
// Remove the saved element if required
if (targetHeader.getNumChildren() > 1 && placeholderElement) {
targetHeader.removeChild(placeholderElement);
}
}
I say broadly only because formatting such as bold, horizontal centering, horizontal rules etc all copied across fine, but bizarrely, lists seem to change from being numbered to being bulleted, so something was lost in translation.
It might need a little tweaking, and surely there is an easier way, but in the absence of anything else, this might be a start.
Source document:
Target document, note that the list type isn't quite right!:
Hope it helps.
I have seen a few examples on Google Groups which demonstrate how to modify the css of the infobox. In this particular example, javascript is used to append a css link to the head of the document:
https://groups.google.com/forum/#!topic/cesium-dev/f0iODd42PeI
var cssLink = frameDocument.createElement("link");
cssLink.href = buildModuleUrl('Path/To/Your/CSS/File.css');
cssLink.rel = "stylesheet";
cssLink.type = "text/css";
viewer.infoBox.frame.contentDocument.head.appendChild(cssLink);
This, however, has not resulted in any changes to the style of my markup.
At best, I have been able to wrap the contents of the infobox by iterating through the entities in the .then function call subsequent to loading a geoJson dataset. When wrapping the contents, I can set style values which are readily apparent in the resulting markup.
var dataSource = Cesium.GeoJsonDataSource.load('../data/mGeoJson.json').then(function(data) {
viewer.dataSources.add(data);
var entities = data.entities.values;
for (var i = 0; i < entities.length; i++)
var entity = entities[i];
if (entity.properties.hasOwnProperty("description")) {
entity.description = '<div style="height: 360px;">' + entity.properties.description
+ '</div>';
}
}
}
This is useful, but does not completely satisfy the requirements of my app.
Could someone provide additional insight into overriding the theme of the infobox, without having to iterate over entities to modify the value of their description properties?
The original solution here wasn't working, because the infoBox is an iframe that has not yet asynchronously loaded when you were trying to modify it.
Instead, you can add an load listener to the iframe, like this:
var viewer = new Cesium.Viewer('cesiumContainer');
var frame = viewer.infoBox.frame;
frame.addEventListener('load', function () {
var cssLink = frame.contentDocument.createElement('link');
cssLink.href = Cesium.buildModuleUrl('Path/To/Your/CSS/File.css');
cssLink.rel = 'stylesheet';
cssLink.type = 'text/css';
frame.contentDocument.head.appendChild(cssLink);
}, false);
This waits for the iframe to become ready to receive the modification, and then applies it.
For what it's worth, I've found success in modifying the theme of the infobox by simply importing my css files in the head of the document. I'm not sure why I wasn't able to modify it directly with stylesheets, as it wasn't previously affecting the infobox's appearance, and this issue was mirrored in the posts that I found in the cesium-dev Google Group. Regardless, it seems to be working just fine now.
Is it possible to change the text of a page of a tabPanel and/or to setVisible() in a UiApp using GAS?
EDIT-1
To clarify my question :
function doGet()
{
var app = UiApp.createApplication();
var tabPanel = app.createTabPanel().setId('AAA');
var horPanel = app.createHorizontalPanel().setId('XXX').setSize(500, 400);
tabPanel.add(horPanel, 'YYY');
app.add(tabPanel);
return app;
}
I want to change change the text 'YYY' into something else at any time after the user sees the panels.
The individual panels are not available as separate objects, you can't change their properties neither hide them individually so I'm afraid what you are trying won't be possible.
The only thing you can do is select one of them, that's about all.
To get the same functionality I use vertical panels and handlers like in this example... it is entirely composed of "normal" panels and I can do what I want with it...
EDIT : handlers to switch panels :
//Panel Handlers
var pHandler1 = app.createClientHandler()
.forEventSource().setStyleAttribute('color','blue')
.forTargets(mainPanel[0]).setVisible(true)
.forTargets(mainPanel[1],mainPanel[2],mainPanel[3]).setVisible(false)
.forTargets(button[1],button[2],button[3]).setStyleAttribute('color','white')
button[0].addClickHandler(pHandler1)
var pHandler2 = app.createClientHandler()
.forEventSource().setStyleAttribute('color','blue')
.forTargets(mainPanel[1]).setVisible(true)
.forTargets(mainPanel[0],mainPanel[2],mainPanel[3]).setVisible(false)
.forTargets(button[0],button[2],button[3]).setStyleAttribute('color','white')
button[1].addClickHandler(pHandler2)
var pHandler3 = app.createClientHandler()
.forEventSource().setStyleAttribute('color','blue')
.forTargets(mainPanel[2]).setVisible(true)
.forTargets(mainPanel[0],mainPanel[1],mainPanel[3]).setVisible(false)
.forTargets(button[0],button[1],button[3]).setStyleAttribute('color','white')
button[2].addClickHandler(pHandler3)
var pHandler4 = app.createClientHandler()
.forEventSource().setStyleAttribute('color','blue')
.forTargets(mainPanel[3]).setVisible(true)
.forTargets(mainPanel[0],mainPanel[1],mainPanel[2]).setVisible(false)
.forTargets(button[0],button[1],button[2]).setStyleAttribute('color','white')
button[3].addClickHandler(pHandler4)
image of another app using this feature :
I accomplished this not by adding strings to the tab, but used a Label instead. I could use the id of the label later to tweak the content.
var horPanel = app.createHorizontalPanel().setId('XXX').setSize(500, 400);
var horLabel = app.createLabel('YYY').setStyleAttributes({fontWeight: 'bold', color: 'red'}).setId('xxxLabel');
tabPanel.add(horPanel, horLabel);
In the call back:
var callBackHorLabel = app.getElementById('xxxLabel');
callBackHorLabel.setText('ZZZ').setStyleAttributes({color: 'inherit'});
There may be better ways to deal with the CSS of created label to make it match the default label, but I was too lazy to research it. Hence, the fontWeight.