How to make images drawn with canvas 2d pixelated

I have a game where im drawing 16×16 images as 256×256 and other high scales. The problem is that they are blurry. I researched how to fix this, but all the articles say that you should make the canvas width 1/4 of the CSS width and set image-rendering to pixelated. This won’t work for me since i will be drawing the images at a variety of scales and the higher scales will still be blurry while the lower scales will be downscaled.

I am not sure how i can do this without just upscaling the actual images, which would increase the game size and potentially make compression artifacts.

If any of you know how to do this, it would really help me.

igGrid with icon in first column generates a check in the rowselector check box

I have the following igGrid defined:

 $('#grdProperties').igGrid({
        dataSource: [],
        width: '100%',
        autofitLastColumn: false,
        fixedHeaders: true,
        renderCheckboxes: true,
        primaryKey: 'property_id',
        autoCommit: true,
        autoGenerateColumns: false,
        autoGenerateLayouts: false,
        features: [
            {
                name: 'Updating',
                editMode: 'none',
                validation: false,
                enableAddRow: false,
                enableDeleteRow: false,
            },
            {
                name: 'Selection', //multipleSelection: true
            },
            {
                name: 'RowSelectors',
                enableCheckBoxes: true,
                enableRowNumbering: false,
                rowSelectorColumnWidth: '15px'
            },
            { name: 'Paging', type: "local", pageSize: 3, pageSizeDropDownLocation: 'inpager' }
        ],
        columns: [
            { headerText: 'View', key: 'view', dataType: 'string', width: '5%', template: '<span style="text-align: center; display: block;" class="binocular-icon" data-bind="click: $parent.OpenPropertyPopUp"><i class="fas fa-binoculars"></i></span>'},
            { headerText: 'property_id', key: 'property_id', dataType: 'number', width: '10%', hidden: true },
            { headerText: 'SBL', key: 'SBL', dataType: 'string', width: '10%' },
            { headerText: 'County', key: 'County', dataType: 'string', width: '10%' },
            { headerText: 'Address', key: 'Address', dataType: 'string', width: '20%' },
            { headerText: 'City', key: 'Locale', dataType: 'string', width: '15%' },
            { headerText: 'State', key: 'State', dataType: 'string', width: '6%' },
            { headerText: 'Zip', key: 'Zip', dataType: 'number', width: '7%' },
            { headerText: 'Owner Name', key: 'OwnerName', dataType: 'string', width: '12%' },
            { headerText: 'Respondent', key: 'Respondent', dataType: 'string', width: '12%' },
            { headerText: 'SD', key: 'SchoolDist', dataType: 'string', width: '5%' },

        ],
    });

I also have this code in the same javascript file:

 vm.OpenPropertyPopUp = function (show) {
        console.log("got here");
        let property_id = 0;

        const selectedRows = vm.eunPropertySelectedRow();
        if (selectedRows.length > 0)
        {
            const firstRow = selectedRows[0]; // Access the first element
            property_id = firstRow.id;
            vm.eunPropertyId(property_id);

            var res = GetPropertyData(property_id, 'front');
            vm.propertyData(ko.mapping.fromJS(res));

            UIkit.modal('#property-modal').toggle();
        } else
        {
            DisplayGeneralMessage("You need to select a property from the grid");
        } 

    }

And I have this in an HTML file:

 <div class="uk-width-1-2">
      <button class="btn" style="float: right; vertical-align: middle; padding-top: 5px; padding-right: 5px" data-bind="click: OpenPropertyPopUp;">View Property</button>
 </div>

When I run my application and I end up clicking on the button, I see in the console “got here” and the model that is defined opens. This is the expected behavior.

I am experiencing a few things:

1 – When I click on the binocular icon, the system places a check mark in the checkbox next to the binocular. Eventually, I want to remove the column that has the checkbox so I have it in there for testing purposes. Why would clicking on the binocular end up placing a check mark in the check box?

2 – When I click on the binocular icon, nothing seems to happen. I do not get any errors in the console and I do not see the text “got here” so I have to assume that the click on the binocular does not end up calling OpenPropertyPopUp.

Any assistance is greatly appreciated.
Thank you.

want to merge two objects and create array of values

I have two objects with same key and value name DateYMD. I want to merge this both object and want to create new object.

Current object data :

[{
          "Id": "1",
          "date": "2024-12-05T00:00:00",
          "DateYMD": 20241205,
          "bookTimeFrom": "2024-12-05T08:00:00",
          "bookTimeTo": "2024-12-05T13:00:00"
        },
        {
          "Id": "2",
          "date": "2024-12-05T00:00:00",
          "DateYMD": 20241205,
          "bookTimeFrom": "2024-12-05T14:00:00",
          "bookTimeTo": "2024-12-05T18:00:00"
        }]

I am trying to achieve this using object.assign method but not working as expected.

Desired output :

{
         "date": "2024-12-05T00:00:00",
         "DateYMD": 20241205,
         "Id": ["1","2"],
         "bookTimeFrom": ["2024-12-05T08:00:00", "2024-12-05T14:00:00"],
         "bookTimeTo": ["2024-12-05T13:00:00", "2024-12-05T18:00:00"]
     };

Can anyone tell me why using IntersectionObserver for revealing things on my page is interrupting smooth scrolling

I’m facing an issue with smooth scrolling on my website. When I implement an IntersectionObserver for revealing things as they come into view, the scrolling becomes jittery, almost as if the page is stuck, and then you got to givie it another try to actually continue scrolling. The issue seems to happen unless I scroll all the way down to the footer first. After that, the scrolling seems to work fine. How can I fix this and make scrolling smooth at all times?

Also, it even happens when the document opens. when you visit my site, again you got to give it a little push to actually see the rest of the site.

    document.addEventListener("DOMContentLoaded", function () {
        const reveals = document.querySelectorAll(".reveal");

        const observer = new IntersectionObserver(
            (entries, observer) => {
                entries.forEach((entry) => {
                    if (entry.isIntersecting) {
                        entry.target.classList.add("reveal-visible"); // Added class when in view
                        observer.unobserve(entry.target);
                    }
                });
            },
            {threshold: 0.2}
        );

        reveals.forEach((reveal) => {
            observer.observe(reveal);
        });
    });

Find Javascript Errors [closed]

I was charged with resolving the issues with these javascript codes. I am just a starter and therefore, I will need all the help I can get.

I keep getting these error messages:

  1. formatTime.js

My Code:

// formats the current date/time so that it reads as hh:mm:ss PM/AM
function formatTime(time) {
  hour = time.getHours();
  if (hour>12) {
    hour = hour-12;
    meridies = "PM";
  } else {
    meridies = "AM";
  }
  minute = time.getMinutes();
  if (minute<10) {
    minute = "0"+minute;
  }
  second = time.getSeconds();
  if (second<10) {
    second = "0"+second;
  }
  return hour+":"+minute+":"+second+" "+meridies;
}

Errors:

'hour' is not defined.
'meridies' is not defined.
'minute' is not defined.
'second' is not defined.
  1. times.js

My Code:

/* global formatTime: true */
/* Please do not remove the comment above. */

// timer to calculate the starting and stopping clicks
$(document).ready(function() {
  $("#start").on('click',function() {
    $("#start").addClass("hidden");
    $("#stop").removeClass("hidden");
    $("#time_ended").addClass("hidden");
    $("#time_started").removeClass("hidden");
    start_time = new Date;
    formatted_time = formatTime(start_time);
  });

  $("#stop").on('click',function() {
    $("#stop").addClass("hidden");
    $("#reset").removeClass("hidden");
    $("#time_started").addClass("hidden");
    $("#time_ended").removeClass("hidden");
    end_time = new Date;
    formatted_end_time = formatTime(end_time);
    $("body").append("<p class='results'>You started at "+formatted_time+".</p>");
    $("body").append("<p class='results'>You finished at "+formatted_end_time+".</p>");
    time_change = end_time-start_time;
    $("body").append("<p class='results'>You counted "+(time_change/1000).tofixed(2)+" seconds.</p>");
    $("body").append("<p class='results'>You are off by "+(time_change/1000-45).tofixed(2)+" seconds.</p>");
  });
});

Errors:

Missing '()' invoking a constructor.
'start_time' is not defined.
'formatted_time' is not defined.
'end_time' is not defined.
'formatted_end_time' is not defined.
'time_change' is not defined.

I tried various javascript validators, used the Firefox Developer tools but no solution.

app script code running slowly google slides

I am making a game in google slides and the code takes around a minute to run and that is too long for the game im making. the script is meant to get data from a spreadsheet then get images and insert them into a slide. (the getting images and inserting them into the slide part is the one that is slowing down the script)

function myFunction() {
  var textboxvalue
  var stop = 0
  var mapspreadsheet = SpreadsheetApp.openById('1VMox84RztQX_A1FDLPAdqVsop_pTdxMtASiempOvfIw')//map sheet
  var Local = SlidesApp.getActivePresentation();
  var LocalFile = DriveApp.getFileById(Local.getId());
  var name = LocalFile.getOwner().getName();
  var pfp = LocalFile.getOwner().getPhotoUrl();
  var Gameserver = SpreadsheetApp.openById("1OV9pHfPgYwNGSagejbVyb2u0pCzdn7uY6at_cgXzWdc");//server sheet
  var PlayerData = SpreadsheetApp.openById("1nLVvr8crxDwZA3ly_iEqctTzEW8xpkcqw6EQ6Yr9OV0");//data sheet
  var Clients = Gameserver.setCurrentCell(Gameserver.getRange('A2')).getValue();//get number of created clients
  var cellthingy =  Clients + 1
  var PlayerDataFinder = PlayerData.createTextFinder(name).findNext();//get PlayerData cell if there is one
  var PlayerRow = PlayerData.setCurrentCell(PlayerDataFinder).getRow()
  var positionX = PlayerData.setCurrentCell(PlayerData.getRange('C'+ PlayerRow)).getValue()//get X and Y coordinates
  var positionY = PlayerData.setCurrentCell(PlayerData.getRange('D'+ PlayerRow)).getValue()
  Local.addEditor("[email protected]")//give me access to the slide
  console.log("Clients: "+Clients);//print number of created clients
  console.log("Name: " + name)//player name
  console.log(pfp)//player pfp
  //TODO - Add check to make sure I am not updating the servers
  if (Gameserver.setCurrentCell(Gameserver.getRange('A3')).getValue() != 1){
  const slide = SlidesApp.getActivePresentation().getSlides()[0];//get only slide in presentation
       slide.getShapes().forEach(shape => {//this is here to find the textbox and takethe text from it
      if (shape.getShapeType() == SlidesApp.ShapeType.TEXT_BOX) {
      textboxvalue = shape.getText().asString().trim().toLocaleLowerCase();
      shape.remove();
        if (textboxvalue.length == 0){
          console.log(textboxvalue.length)
      console.log("no new inputs")
      stop = "1"
        }}
             });
  slide.insertShape(SlidesApp.ShapeType.TEXT_BOX, 540, 70, 170, 300);
            var images = slide.getImages().toString()
                  slide.getImages().forEach(image => {//this is here to find the textbox and take the text from it
      image.remove();
        });
            slide.insertImage(pfp, 248.5, 165, 45, 45)
            console.log(images)
               try{
             if(1!=stop){//if no new inputs don't run the script
  console.log('loading data')
  var PlayerDataFinder = PlayerData.createTextFinder(name).findNext();//get PlayerData cell if there is one
  var PlayerRow = PlayerData.setCurrentCell(PlayerDataFinder).getRow()
  var positionX = PlayerData.setCurrentCell(PlayerData.getRange('C'+ PlayerRow)).getValue()//get X and Y coordinates
  var positionY = PlayerData.setCurrentCell(PlayerData.getRange('D'+ PlayerRow)).getValue()
  var oldpositionX = positionX
  var oldpositionY = positionY
  console.log(textboxvalue)
  console.log(positionX.toString() + "," + positionY.toString())
  console.log('got data!');
if(textboxvalue == "up"){//giant if statement thingy to check what is typed in the box
  console.log("moving player up!")
PlayerData.setCurrentCell(PlayerData.getRange('D'+ PlayerRow)).setValue(positionY + 1)
GetMap(positionX,positionY+1)
}else{if(textboxvalue == "down"){
console.log("moving player down!")
PlayerData.setCurrentCell(PlayerData.getRange('D'+ PlayerRow)).setValue(positionY - 1)
GetMap(positionX,positionY-1)
}else{if(textboxvalue == "left"){
  console.log("moving player left!")
PlayerData.setCurrentCell(PlayerData.getRange('C'+ PlayerRow)).setValue(positionX - 1)
GetMap(positionX-1,positionY)
}else{if(textboxvalue == "right"){
  console.log("moving player right!")
PlayerData.setCurrentCell(PlayerData.getRange('C'+ PlayerRow)).setValue(positionX + 1)
GetMap(positionX+1,positionY)
}else{if(textboxvalue == "block up"){

}else{if(textboxvalue == "attack up"){

}else{if(textboxvalue == "block down"){

}else{if(textboxvalue == "attack down"){

}else{if(textboxvalue == "block left"){

}else{if(textboxvalue == "attack left"){

}else{if(textboxvalue == "block right"){

}else{if(textboxvalue == "attack right"){
}}}}}}}}}}}}
positionX = PlayerData.setCurrentCell(PlayerData.getRange('C'+ PlayerRow)).getValue()//get new X value
positionY = PlayerData.setCurrentCell(PlayerData.getRange('D'+ PlayerRow)).getValue()//get new Y value
var positioncombined = positionX.toString() + "," + positionY.toString()//combine them
console.log(positioncombined)
positionX = PlayerData.setCurrentCell(PlayerData.getRange('C'+ PlayerRow)).getValue()+1//get new X value
positionY = PlayerData.setCurrentCell(PlayerData.getRange('D'+ PlayerRow)).getValue()//get new Y value
var positioncombined = positionX.toString() + "," + positionY.toString()//combine them
try{
var positioncellfinder = mapspreadsheet.setActiveSheet(mapspreadsheet.getSheetByName('coordinates')).createTextFinder(positioncombined).findNext().getA1Notation();//find position cell
console.log(positioncellfinder)
}catch(error){
  console.log(error)
  console.log('Can't get position cell!, undoing movement')
  PlayerData.getRange('C'+PlayerRow).setValue(oldpositionX);
  PlayerData.getRange('D'+PlayerRow).setValue(oldpositionY);
}
        }else{
          GetMap(positionX,positionY);
        }
  }catch(error){//check if threre is no playerdata
  console.log(error);
  if (error == "{ [Exception: Invalid argument: cell] name: 'Exception' }"){
    console.log(error);
    console.log('No data found! creating data');
    PlayerData.getRange("A" + cellthingy).setValue(name);
    PlayerData.getRange("B" + cellthingy).setValue(pfp);
    PlayerData.getRange('C'+ cellthingy).setValue("0");//set X to 0
    PlayerData.getRange('D'+ cellthingy).setValue("0");//set Y to 0
    Gameserver.setCurrentCell(Gameserver.getRange('A2')).setValue(Clients + 1)
    console.log('Done');
  }
  }
  }
  }
function Getcellimage(X,Y) {
  try{
var mapspreadsheet = SpreadsheetApp.openById('1VMox84RztQX_A1FDLPAdqVsop_pTdxMtASiempOvfIw')//map 
console.log("textfinder start")
var positioncellfinder = mapspreadsheet.setActiveSheet(mapspreadsheet.getSheetByName('coordinates')).createTextFinder(X.toString() + 
 "," +  Y.toString()).findNext().getA1Notation();//find image cell
 console.log("textfinder end")
var imgthingy = mapspreadsheet.setActiveSheet(mapspreadsheet.getSheetByName('IMG')).setCurrentCell(mapspreadsheet.getRange(positioncellfinder)).getValue()//get img
console.log(imgthingy)
return(imgthingy)
}catch(error){
  console.log(imgthingy + "cellimageerror:" + error)
  return("https://drive.google.com/file/d/1R9qlYwqWSlWhrDLVTJLaJQKet3Smt9R8/view?usp=sharing")
}
}
function GetMap(PLAYERX,PLAYERY){
Getandinsertimage(PLAYERX,PLAYERY,1,0)
Getandinsertimage(PLAYERX,PLAYERY,-1,0)
Getandinsertimage(PLAYERX,PLAYERY,0,1)
Getandinsertimage(PLAYERX,PLAYERY,0,-1)
Getandinsertimage(PLAYERX,PLAYERY,1,1)
Getandinsertimage(PLAYERX,PLAYERY,1,-1)
Getandinsertimage(PLAYERX,PLAYERY,-1,1)
Getandinsertimage(PLAYERX,PLAYERY,-1,-1)
Getandinsertimage(PLAYERX,PLAYERY,-1,2)
Getandinsertimage(PLAYERX,PLAYERY,0,2)
Getandinsertimage(PLAYERX,PLAYERY,1,2)
Getandinsertimage(PLAYERX,PLAYERY,-1,-2)
Getandinsertimage(PLAYERX,PLAYERY,0,-2)
Getandinsertimage(PLAYERX,PLAYERY,-2,2)
Getandinsertimage(PLAYERX,PLAYERY,-2,0)
Getandinsertimage(PLAYERX,PLAYERY,-2,-1)
Getandinsertimage(PLAYERX,PLAYERY,-2,-2)
Getandinsertimage(PLAYERX,PLAYERY,1,-2)
Getandinsertimage(PLAYERX,PLAYERY,2,1)
Getandinsertimage(PLAYERX,PLAYERY,2,2)
Getandinsertimage(PLAYERX,PLAYERY,2,0)
Getandinsertimage(PLAYERX,PLAYERY,2,-1)
Getandinsertimage(PLAYERX,PLAYERY,2,-2)
Getandinsertimage(PLAYERX,PLAYERY,-2,1)
}
function GetIdFromUrl(url) { 
  console.log(url)
  return url.match(/[-w]{25,}/); }
function Getandinsertimage(PLAYERX,PLAYERY,X,Y) {
const slide = SlidesApp.getActivePresentation().getSlides()[0];//get only slide in presentation
var bread = DriveApp.getFileById(GetIdFromUrl(Getcellimage(PLAYERX+X,PLAYERY+Y)))
slide.insertImage(bread, 248.5+45*X, 165-45*Y, 45, 45)
}

The email signature block is not loading with my Add-In

I’m working on developing my first Add-In for Outlook 365/Windows 10. In theory, it’s quite simple—it’s a drop-down menu with two options. Each option opens a new email and loads a different template, depending on the selection.

So far, the menu is functioning smoothly. Selecting option A displays the corresponding template, and the same goes for option B.

However, I’m facing a problem: I can’t get the user’s signature to load automatically as expected, even though the signature is properly configured and set as the default for new emails.

Attached you will find my manifest.xml and commands.ts

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<OfficeApp xmlns="http://schemas.microsoft.com/office/appforoffice/1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bt="http://schemas.microsoft.com/office/officeappbasictypes/1.0" xmlns:mailappor="http://schemas.microsoft.com/office/mailappversionoverrides/1.0" xsi:type="MailApp">
<Id>2eb95a7a-bc4a-4f53-bc6f-ba64b72d8663</Id>
<Version>1.0.0.0</Version>
<ProviderName>Contoso</ProviderName>
<DefaultLocale>en-US</DefaultLocale>
<DisplayName DefaultValue="NewClientMatter"/>
<Description DefaultValue="A template to get started."/>
<IconUrl DefaultValue="https://localhost:3000/assets/icon-64.png"/>
<HighResolutionIconUrl DefaultValue="https://localhost:3000/assets/icon-128.png"/>
<SupportUrl DefaultValue="https://www.contoso.com/help"/>
<AppDomains>
<AppDomain>https://www.contoso.com</AppDomain>
</AppDomains>
<Hosts>
<Host Name="Mailbox"/>
</Hosts>
<Requirements>
<Sets>
<Set Name="Mailbox" MinVersion="1.5"/>
</Sets>
</Requirements>
<FormSettings>
<Form xsi:type="ItemRead">
<DesktopSettings>
<SourceLocation DefaultValue="https://localhost:3000/taskpane.html"/>
<RequestedHeight>250</RequestedHeight>
</DesktopSettings>
</Form>
</FormSettings>
<Permissions>ReadWriteItem</Permissions>
<Rule xsi:type="RuleCollection" Mode="Or">
<Rule xsi:type="ItemIs" ItemType="Message" FormType="Read"/>
<Rule xsi:type="ItemIs" ItemType="Message" FormType="Edit"/>
</Rule>
<DisableEntityHighlighting>false</DisableEntityHighlighting>
<VersionOverrides xmlns="http://schemas.microsoft.com/office/mailappversionoverrides" xsi:type="VersionOverridesV1_0">
<Requirements>
<bt:Sets DefaultMinVersion="1.5">
<bt:Set Name="Mailbox"/>
</bt:Sets>
</Requirements>
<Hosts>
<Host xsi:type="MailHost">
<DesktopFormFactor>
<FunctionFile resid="Commands.Url"/>
<ExtensionPoint xsi:type="MessageReadCommandSurface">
<OfficeTab id="TabDefault">
<Group id="msgReadGroup">
<Label resid="GroupLabel"/>
<Control xsi:type="Menu" id="DropdownMenu">
<Label resid="DropdownMenu.Label"/>
<Supertip>
<Title resid="DropdownMenu.Label"/>
<Description resid="DropdownMenu.Tooltip"/>
</Supertip>
<Icon>
<bt:Image size="16" resid="MenuIcon.16x16"/>
<bt:Image size="32" resid="MenuIcon.32x32"/>
<bt:Image size="80" resid="MenuIcon.80x80"/>
</Icon>
<Items>
<Item id="InternalAction">
<Label resid="InternalAction.Label"/>
<Supertip>
<Title resid="InternalAction.Label"/>
<Description resid="InternalAction.Tooltip"/>
</Supertip>
<Icon>
<bt:Image size="16" resid="InternalIcon.16x16"/>
<bt:Image size="32" resid="InternalIcon.32x32"/>
<bt:Image size="80" resid="InternalIcon.80x80"/>
</Icon>
<Action xsi:type="ExecuteFunction">
<FunctionName>handleInternalAction</FunctionName>
</Action>
</Item>
<Item id="ExternalAction">
<Label resid="ExternalAction.Label"/>
<Supertip>
<Title resid="ExternalAction.Label"/>
<Description resid="ExternalAction.Tooltip"/>
</Supertip>
<Icon>
<bt:Image size="16" resid="ExternalIcon.16x16"/>
<bt:Image size="32" resid="ExternalIcon.32x32"/>
<bt:Image size="80" resid="ExternalIcon.80x80"/>
</Icon>
<Action xsi:type="ExecuteFunction">
<FunctionName>handleExternalAction</FunctionName>
</Action>
</Item>
</Items>
</Control>
</Group>
</OfficeTab>
</ExtensionPoint>
</DesktopFormFactor>
</Host>
</Hosts>
<Resources>
<bt:Images>
<bt:Image id="MenuIcon.16x16" DefaultValue="https://localhost:3000/assets/menu-icon-16.png"/>
<bt:Image id="MenuIcon.32x32" DefaultValue="https://localhost:3000/assets/menu-icon-32.png"/>
<bt:Image id="MenuIcon.80x80" DefaultValue="https://localhost:3000/assets/menu-icon-80.png"/>
<bt:Image id="InternalIcon.16x16" DefaultValue="https://localhost:3000/assets/int-16.png"/>
<bt:Image id="InternalIcon.32x32" DefaultValue="https://localhost:3000/assets/int-32.png"/>
<bt:Image id="InternalIcon.80x80" DefaultValue="https://localhost:3000/assets/int-80.png"/>
<bt:Image id="ExternalIcon.16x16" DefaultValue="https://localhost:3000/assets/ext-16.png"/>
<bt:Image id="ExternalIcon.32x32" DefaultValue="https://localhost:3000/assets/ext-32.png"/>
<bt:Image id="ExternalIcon.80x80" DefaultValue="https://localhost:3000/assets/ext-80.png"/>
</bt:Images>
<bt:Urls>
<bt:Url id="Commands.Url" DefaultValue="https://localhost:3000/commands.html"/>
<bt:Url id="Taskpane.Url" DefaultValue="https://localhost:3000/taskpane.html"/>
<bt:Url id="CommandsJs.Url" DefaultValue="https://localhost:3000/commands/commands.js"/>
</bt:Urls>
<bt:ShortStrings>
<bt:String id="GroupLabel" DefaultValue="New Client/Matter"/>
<bt:String id="DropdownMenu.Label" DefaultValue="Choose Action"/>
<bt:String id="InternalAction.Label" DefaultValue="Internal"/>
<bt:String id="ExternalAction.Label" DefaultValue="External"/>
</bt:ShortStrings>
<bt:LongStrings>
<bt:String id="DropdownMenu.Tooltip" DefaultValue="Select an action to perform."/>
<bt:String id="InternalAction.Tooltip" DefaultValue="Opens an internal email template."/>
<bt:String id="ExternalAction.Tooltip" DefaultValue="Opens an external email template."/>
</bt:LongStrings>
</Resources>
</VersionOverrides>
</OfficeApp>

commands.ts

/* global Office */
Office.onReady(function (info) {
if (info.host === Office.HostType.Outlook) {
Office.actions.associate("handleInternalAction", handleInternalAction);
Office.actions.associate("handleExternalAction", handleExternalAction);
}
});
/**
* Handles the "Internal" action.
* @param event The Office Add-in event.
*/
function handleInternalAction(event: Office.AddinCommands.Event): void {
openEmailTemplate("internal", event);
}
/**
* Handles the "External" action.
* @param event The Office Add-in event.
*/
function handleExternalAction(event: Office.AddinCommands.Event): void {
openEmailTemplate("external", event);
}
/**
* Opens an email template with the user's signature.
* @param templateType The type of template ("internal" or "external").
* @param event The Office Add-in event.
*/
function openEmailTemplate(templateType: string, event: Office.AddinCommands.Event): void {
let templateBody: string;
let subject: string;
if (templateType === "internal") {
templateBody = "This is the internal email template.";
subject = "Internal Email Subject"; // Modifica el asunto si es necesario
} else {
templateBody = `
This is the external email template.<br/><br/>`;
subject = "External Client/Matter"; // Asunto para correos externos
}
Office.context.mailbox.displayNewMessageForm({
subject,
htmlBody: templateBody,
});
setTimeout(() => {
Office.context.mailbox.item.body.getAsync(Office.CoercionType.Html, (result) => {
if (result.status === Office.AsyncResultStatus.Succeeded) {
const userSignature = result.value || "";
if (userSignature) {
const combinedBody = templateBody + "<br/><br/>" + userSignature;
Office.context.mailbox.item.body.setAsync(
combinedBody,
{
coercionType: Office.CoercionType.Html,
},
(setResult) => {
if (setResult.status === Office.AsyncResultStatus.Succeeded) {
} else {
console.error("Failed to set email body:", setResult.error);
}

event.completed();
}
);
} else {
console.warn("User's signature not available.");
event.completed();
}
} else {
console.error("Failed to get user's signature:", result.error);
event.completed();
}
});
}, 2000); 
event.completed();
} ```

Thank you so much for your support!

How to ensure a timer and question flow work seamlessly in a JavaScript quiz app?

In my JavaScript quiz app, I have a 180-second countdown timer and need to ensure users can’t move to the next question without selecting an answer. How can I synchronize the timer with the quiz flow and manage user interactions effectively?

I implemented a countdown timer that starts at 180 seconds for the entire quiz and a nextQuestion() function to navigate through questions. I also added a check to ensure users select an answer before proceeding.

I expected the timer to run independently while allowing the quiz to only proceed when an answer is selected, but I ran into issues where the timer either stops prematurely or doesn’t align with the quiz flow.

is there a way to update docs from a query without having to loop through the results?

I’m trying to update a field in all the docs returned by a query. The code below works but I was wondering if there’s a way to accomplish this without having to loop the result of the query and running updateDoc on every item.

    const query_ref = query(
        collection(db, "somecollection"),
        where("something_id", "==", this.something_id)
    );
    const snapshot = await getDocs(query_ref);
    for (const doc of snapshot.docs) {
        const ref = doc(db, "somecollection", doc.id);
        await updateDoc(ref, {field: value});
    }

Needs Javascript Help To Block Spam For Mailing List

We need to block spam from being added to the mail listing.

We need the below Javascript code to be modified to block certain characters. Right now, we only have code for those fields if they are left blank.

There are certain characters such as .space, .ru, .pl, etc. we do not want to accept in the email field anymore. There should be a message that says this is an invalid email address.
For the Knowledge field, we want a code to prevent certain characters such as a foreign language (ex: Купить КОКАИН в Киеве? САЙТ – KOKS.TOP Купить) and html from being added such as https://, url, and any html code. There should be an error message saying we cannot accept urls, etc.

I need to add a line of code for txtaKnowledge to prohibit urls and strange characters.

  <SCRIPT LANGUAGE=JAVASCRIPT>
function InputIsValid() 
 {  
     

        //Check for missing Knowledege
    if (document.frmMailingList.txtaKnowledge.value == "")
    {
        alert("Please include how you heard about us!");
        document.frmMailingList.txtaKnowledge.focus();
        return false;
    }   
    


    //If it made it here, everything looks ok
    return true;
}

     
 
 
// -->
</SCRIPT>

event.originalEvent.propertyName not working in any none Chromium browsers

jQuery

$('body > header').on('webkitTransitionEnd oTransitionEnd msTransitionEnd transitionend', function(event) { 
                    
    if (event.target && event.originalEvent.propertyName === 'height') {
        console.log('height changed');
    }

});

The CSS is transitioning from height: auto to height: 100% and vise-versa.

This works as expected in Chromium browsers but not in any other browser. In Firefox for example, when I console.log(event.originalEvent.propertyName) before the if parameter I get other property names but never height.

How do I get event.originalEvent.propertyName to return height as Chromium browsers do?

This returns undefined on all browsers:

$('body > header').on('webkitTransitionEnd oTransitionEnd msTransitionEnd transitionend', function(event) { 
    var evt = event.originalEvent || event;
    if (evt.propertyName === 'height') {
         console.log('height changed');
    }
});

Expo app throws “Network request failed” when installed through APK

I’m working on a personal app to control things on my home through a server running on Flask. I’ve already made the app, and it works on Expo loaded to my phone through the QR, it send the requests to my server, and everything works correctly, but after I built the APK through expo eas, when I install on my phone, it doesn’t work anymore, it throws “Network request failed”, and nothing else to guide me into what is the problem. My guess was that Android was probably blocking HTTP requests, since due to this being a server mounted on an RPi for my home, I don’t really need to bother into dealing with certificates, so after researching a while, I came with this app.json(Removed private parts), but is still not working.

{
  "expo": {
    "name": "",
    "slug": "",
    "version": "1.0.0",
    "orientation": "portrait",
    "icon": "./assets/icon.png",
    "userInterfaceStyle": "light",
    "newArchEnabled": true,
    "splash": {
      "image": "./assets/splash-icon.png",
      "resizeMode": "contain",
      "backgroundColor": "#000000"
    },
    "ios": {
      "supportsTablet": true
    },
    "android": {
      "adaptiveIcon": {
        "foregroundImage": "./assets/icon.png",
        "backgroundColor": "#000000"
      },
      "usesCleartextTraffic": true,
      "package": "",
      "permissions": ["INTERNET"]
    },
    "web": {
      "favicon": "./assets/favicon.png"
    },
    "extra": {
      "eas": {
        "projectId": ""
      }
    }
  }
}

I’ve tested my app through HTTP request shortcuts app, so I know it should be possible to reach my server through an actual Android app, and since the app works on the Expo testing then I’m guessing that I’m not using the fetch library wrong(I didn’t install any custom library, just the basic fetch from React). What am I missing to make this work? I’ve tried to do it like it says in this question, but after installing that library, it messed up my whole project, causing me not to be able to load the application for testing through QR, and only be able to build it and install it, which anyway didn’t work, still threw the error. Outside this app.json, I haven’t modified any other file, just the defaults Expo files, and my app, and in case is necessary, this is how I handle the request:

const togglePlay = async () => {
    try {
      const response = await fetch(`${apiUrl}toggle`);
      const json = await response.json();

      handleToast(json);
      if (json.status) {
        setIsAnimating((prev) => json.state);
      }
    } catch (error) {
      Toast.show({
        type: 'error',
        text1: 'Error',
        text2: error.message,
      });
      handleError(error);
    }
  };

Auto-include webpack vendors bundles

I’m using webpack’s CodeSplittingPlugin which produces vendors bundles, is there a way to prevent the need to manually add and update vendor bundles script tags in HTML? Something like a bundle that has a static name and that I can add to all of my HTML documents which will auto load the vendor bundle for scripts that require it?

I don’t want to use the HTMLWebpackPlugin because I’m using Razor views and not plain HTML.

Why does this Node.js script produce different output each time?

This script is from a Nodejs introducing book. This part is about the event loop of Javascript.

const sleep_st = (t) => new Promise((r) => setTimeout(r, t));
const sleep_im = () => new Promise((r) => setImmediate(r));

(async () => {
    setImmediate(() => console.log(1));
    console.log(2);
    await sleep_st(0);
    setImmediate(() => console.log(3));
    console.log(4);
})();

The two possible outputs are “2 4 1 3” and “2 1 4 3”.

I expect the outputs are always consistent.

How to access the last value in an async generator after a for await…of?

When using for await...of to iterate over an async generator, the final value (return value) seems to be consumed and inaccessible afterward. Here’s a minimal example:

async function* exampleGenerator() {
  yield 1;
  yield 2;
  return 3; // Final value
}

async function main() {
  const generator = exampleGenerator();

  for await (const value of generator) {
    console.log(value); // Logs 1, 2
  }

  const final = await generator.next();
  console.log(final.value); // undefined, expected 3
}

main();

How can I access the final value (3) after using for await...of? Is there a way to retrieve it without losing the simplicity of for await...of?