Get all sub-labels of a Gmail label through a Google Script - google-apps-script

I would like to get all child labels of a given parent label. Is it possible?
In How to check if a Gmail label has a nested sub-label? it is checked whether all labels have a sub-label, and I tried doing something similar for an specific one, but with no results.

The parent-child relation of Gmail labels is based on their names: it you have a label "foo/bar" and there is also a label named "foo", then the former is considered a child of the latter. (I just tested this by manually creating "foo/bar" label and then "foo"; as soon as "foo" appeared, it acquired "bar" as a child.)
So, the following function will return the list of all labels that are children of the given label. (The argument parent here is a label itself, not its name).
function children(parent) {
var name = parent.getName() + '/';
return GmailApp.getUserLabels().filter(function(label) {
return label.getName().slice(0, name.length) == name;
});
}

Related

ngOnChanges only works when it's not the same value

So basically I have a modal component with an input field that tells it which modal should be opened (coz I didn't want to make a component for each modal):
#Input() type!:string
ngOnChanges(changes: SimpleChanges): void {
this.type = changes["type"].currentValue;
this.openModal();
}
that field is binded to one in the app component:
modalType = "auth";
HTML:
<app-modal [type] = modalType></app-modal>
In the beginning it's got the type "auth" (to login or register), but when I click on an icon I want to open a different modal, I do it like so:
<h1 id="options-route"
(click) ="modalType = 'settings'"
>⚙</h1>
but this only works the first time, when modalType already has the value "settings" the event doesn't trigger even though the value has technically changed
I think the problem is that it's the same value because i tried putting a button that does the exact same thing but with the value "auth" again and with that it was clear that the settings button only worked when tha last modal opened was auth and viceversa
any ideas? I want to be able to open the settings modal more than once consecutively possibly keeping onChange because ngDoCheck gets called a whole lot of times and it slows down the app
You need to include the changeDetectorRef, in order to continue in this way.
More about it https://angular.io/api/core/ChangeDetectorRef
Although, a better and a faster alternative is the use of a behavior Subject.
All you have to do is create a service that makes use of a behavior subject to cycle through each and every value exposed and then retrieve that value in as many components as you want. To do that just check for data changes in the ngOnInit of target component.
You may modify this for implementation,
private headerData = new BehaviorSubject(new HeaderData());
headerDataCurrent = this.headerData.asObservable();
changeHeaderData(headerDataNext : HeaderData) {
this.headerData.next(headerDataNext)
console.log("subscription - changeUserData - "+headerDataNext);
}
Explanation:
HeaderData is a class that includes the various values that can be shared with respective data types.
changeHeaderData({obj: value}), is used to update the subject with multiple values.
headerDataCurrent, an observable has to be subscribed to in the target component and data can be retrieved easily.
I mean i'm too l-a-z-y to use your slightly-not-so-much-tbh complicated answers so I just did this:
I added a counter that tops to 9 then gets resetted to 0 and I add it to the value
screwYouOnChangesImTheMasterAndYouShallDoMyBidding = 0;
//gets called onClick
openSettings(){
if(this.screwYouOnChangesImTheMasterAndYouShallDoMyBidding === 9){
this.screwYouOnChangesImTheMasterAndYouShallDoMyBidding = 0;
}
this.screwYouOnChangesImTheMasterAndYouShallDoMyBidding = this.screwYouOnChangesImTheMasterAndYouShallDoMyBidding + 1;
this.modalType = "settings"+this.screwYouOnChangesImTheMasterAndYouShallDoMyBidding;
}
then in the child component I just cut that last character out:
ngOnChanges(changes: SimpleChanges): void {
let change = changes["type"].currentValue as string;
change = change.substring(0, change.length - 1);
this.type = change;
this.openModal();
}
works like a charm 😂

How to remove user Labels from Gmail using GScript

In relation to another question that removes Category Labels, I'd like to use the same code and simply add other user labels to the routines created.
The routines are as follows:
function removeLabelsFromMessages(query, labelsToRemove) {
var foundThreads = Gmail.Users.Threads.list('me', {'q': query}).threads
if (foundThreads) {
foundThreads.forEach(function (thread) {
Gmail.Users.Threads.modify({removeLabelIds: labelsToRemove}, 'me', thread.id);
});
}
}
function ProcessInbox() {
removeLabelsFromMessages(
'label:updates OR label:social OR label:forums OR label:promotions',
['CATEGORY_UPDATES', 'CATEGORY_SOCIAL', 'CATEGORY_FORUMS', 'CATEGORY_PROMOTIONS']
)
<...other_stuff_to_process...>
}
I'm wondering if you can add another user label to the "labelsToRemove" - I've tried simply adding another label to the array, but keep getting an error stating the label cannot be found. I'm' sure it's just a syntax error (I don't code very much), so any suggestions on how to add that?
The code I'm trying to run is:
function CleanReceipts () {
removeLabel (
'label: Receipts',
['CATEGORY_UPDATES', 'CATEGORY_SOCIAL', 'CATEGORY_FORUMS', 'CATEGORY_PROMOTIONS', '#SaneLater']
)
}
where "#SaneLater" is the name of a user label I'd like to remove as well. Thanks in advance.
The reason you are getting the Label not found error is because the threads.modify method is expecting a label id and not a label name.
In order to retrieve the id of this specific label, I suggest you take a look at labels.list and make the request to get the appropriate value:
let labels = Gmail.Users.Labels.list('me');
console.log(labels);
Reference
Gmail API users.threads.modify.

getting a handle on an element in the context of another

I have a typical page containing sections of label/field pairs but with the same label name in different sections. The sections have are named so I can identify them using the name. The HTML is structured so that the section name is a sibling of another element containing the label/fields
<div class="section">Business Address<\div>
<div>
<div class="field">
<div class="label">Country<\div>
<input type="text">
....
If I could identify the label element using a selector only I can do something like: -
const siblingHandle = page.evaluateHandle(() => {
const sectionLabelHandle = Array.from(document.querySelectorAll('.blah')).find(el=>el.textContent.includes('section label name'))
return sectionLabelHandle.nextElementSibling
})
const label = await siblingHandle.$('label selector')
But what I need is a handle on the label element so that I can get its sibling field so I can type a value in it.
I can't use siblingHandle.$eval() as it doesn't return a handle.
I've also considered using page.waitForFunction, passing in the handle so that can be used instead of 'document'
const labelHandle = page.waitForFunction(
handle => Array.from(handle.querySelectorAll('sel')).find(el=>el.textContent.includes('text'),
{},
siblingHandle
)
but I get a cycling JSON error if I do that.
So, a couple of questions,
1) Is there any way to get siblings in Puppeteer without having to use nextElementSibling in an evaluate function?
2) How can I search for an element containing specified text, but in the context of a parent handle rather than document?
Xpath selectors as opposed to CSS selectors can answer both of your questions.
Search for an element via specified text:
const xpathWithText = '//div[text()="Country"]';
Using it to get the next sibling:
const xPathTextToSibling = '//div[text()="Country"]/following-sibling::input';
In practice:
const myInput = await page.waitForXPath(xPathTextToSibling);
await myInput.type('Text to type');
You should not need to search for an element with specific text in the context of a parent handle because the second selector I used above will give you a handle of the element you want to type in directly.

how to dynamically place components in form using angular

I have to create a 2 column form where left and right side will have different sections/groups of elements. these sections are created as directives, now i have to place these directives in the form based on the column and postion values that I recieve from the json.
{ group:"Group 1",column:1,position:2} then group1 directive should be placed on left side and in the second row of the left column. kindly suggest how to stitch these directives based on the position received
You can arrange your directives on the DOM as you want.
If you don't want to change elements on your DOM, You can create a directive with "C" or "A" as the required attribute (which means you can add it to any html element). Then, all you have to do is change the classes/ attribute on each position to get the desired result.
.directive('InputA', function () {
return {
restrict: 'C',
template... });
.directive('InputB', function () {
return {
restrict: 'C',
template... });
Then, your section can be like this:
<div col-m-6><div class="InputA"/><div class="InputB"/><div class="InputC"/></div>
than if you want to change the order all you have to do is change the classes to :
<div col-m-6><div class="InputC"/><div class="InputA"/><div class="InputB"/></div>
see http://jsfiddle.net/zmvr4tee/ - although i wouldn't recommend using jquery for the manipulation, i would create a parent directive that handles it but you get the idea.
Update:
added a function that recieveing a JSON, ordering it and place it according to column/position attributes.
function build(){
//you can play with column and position attributes to get different order
//recieving the JSON
var inputs = angular.fromJson('[{ "label": "firstThird","column":1,"position":3},{ "label": "secondSecond","column":2,"position":2},{ "label": "firstSecond","column":1,"position":2},{ "label": "secondThird","column":2,"position":3},{ "label": "firstFirst","column":1,"position":1},{ "label": "secondFirst","column":2,"position":1}]' );
//sorting the input to match the right postition of each directive
inputs.sort(function(a, b){
return (a.column*2+a.position)-(b.column*2+b.position);
});
//positioning the directives according to their column and postiion attributes
for(var i=0;i<3;i++)
{
$("#leftSection").children(':nth-child('+(i+1)+')').addClass(inputs[i].label);
}
for(var i=0;i<3;i++)
{
$("#rightSection").children(':nth-child('+(i+1)+')').addClass(inputs[i+3].label);
}
//compileing the form with angular to get the results
angular.element($("#myForm")).injector().invoke(function($compile) {
var scope = angular.element($("#myForm")).scope();
$compile($("#myForm"))(scope);
});
}
see update Fiddle here:Updated Fiddle

mootools 1.11 div contains checked checkbox

how can mootools 1.11 determine if a div contains any checked check boxes?
tried all kinds of variations using $ $$ $E $ES getElements and css selectors, its just not returning true if this div contains no tick boxes
var ticked = $(sId).getElements('[checked=checked]');
if($chk(ticked)){alert('yo');}else{unticked = true;}
"checked" is a dynamically assigned DOM property (which is a boolean), and accessing the attribute only returns the value that was there when the page loaded (or the value you placed when using setAttribute).
Also, as MooTools 1.11 does not have complex selectors (attributes can not be filtered directly within $$) and the filterByAttribute function only accepts direct string comparison, this is your only (and best!) option:
$(sId).getElements('input').filter(function(input) {
return /radio|checkbox/.test(input.getAttribute('type')) && input.checked;
})
note: I added radio just for completeness, the filter loop would have to be run anyways to verify the checked status.
If you want to simplify the process and be able to reuse the code (the MooTools way), you can also mix-in the checked filter into Elements like this:
Element.extend({
getCheckedInputs: function() {
return this.getElements('input').filter(function(input) {
return /radio|checkbox/.test(input.getAttribute('type')) && input.checked;
});
}
});
and then your selection call is reduced to:
$(sID).getCheckedInputs();
From The Documentation:
$(sId).getElements("input:checked");
for 1.1
console.log( $('id').getProperty('checked') );