Convert PHP script to JavaScript

  • Add the “base-reality/php-to-javascript”: “>=0.0.3” to your project’s composer.json file:

    “require”:{ “base-reality/php-to-javascript”: “0.1.16” }

    Or the latest tagged version. The dev master should only be used for development, not production.\
  • Include the Composer SPL autoload file in your project: require_once(‘../vendor/autoload.php’);

    Call the converter:
 $phpToJavascript = new PHPToJavascript\PHPToJavascript();
   $phpToJavascript->addFromFile($inputFilename); $jsOutput =
   $phpToJavascript->toJavascript();

$jsOutput will now contain an auto-generated Javascript version of the PHP source file.

Create a custom property editor in Umbraco

Umbraco User’s Guide

This post is helpful in following scenarios –

  • If you are looking to create a custom property editor in Umbraco
  • If you are looking for a way to populate a checkbox list in the content dynamically
  • If you are looking for a way to call an api in umbraco property editor
  • If you are looking for a way to populate a checkbox list with one of the document types dynamically

For this post, we are going to build a custom property editor that will populate the checkbox list with categories (added under home) using an api url.

Let’s say, we have a food website that have different categories like Healthy, Baking, Recipes, Dinner, Summer recipes, etc.
We also have articles related to all these different categories.

Categories under Home –

Content with categories as checkbox list

What is the problem?

Now the problem here is whenever a new category is added, the checkbox list for categories has to be updated manually as we have use the default checkbox list data type.

In order to fix this problem, we will create a custom property editor and use it to create the checkbox list dynamically. So whenever, a new category will be added, the checkbox list for categories will be updated automatically.

What is the solution?

Skills needed to build a Property Editor –

  • Umbraco BackOffice (Using ver 8.0.1 for this post)
  • HTML
  • CSS
  • Javascript (Optional)
  • Angular (Optional)

Files needed for a Property Editor –

  • Manifest
  • HTML file
  • Javascript file
  • CSS (Optional)

First, let’s create a manifest file.

{
  propertyEditors: [
    {
      alias: "CustomCheckBoxList",
      name: "Custom Checkbox list",
      editor: {
        view: "~/App_Plugins/CheckboxListing/checkboxlist.html",
        hideLabel: false,
        valueType: "STRING"
      },
	  prevalues: {
			fields: [				
				{
					label: "Api Url",
					description: "Add the API Url to get the list of items. api/{controller}/{Action}",
					key: "apiUrl",
					view: "textstring"
				}
			]
		}
    }
  ],
  javascript: [
    "~/App_Plugins/CheckboxListing/checkboxlist.controller.js"
  ]
}

Now, let’s add the HTML file

<div ng-controller="CheckboxList.Controller">
   
    <ul class="unstyled">
        <li ng-repeat="category in selectedItems">
            <label class="checkbox">
                <input type="checkbox" name="checkboxlist"
                       value="{{category.key}}"
                       ng-model="category.selected"/>
                {{category.val}}
            </label>
        </li>
    </ul>
</div>

Now, we have to create the Javascript file, which will contain the main logic of this property editor.

angular.module("umbraco")
    .controller("CheckboxList.Controller",
        function($scope, $http, assetsService) {
            var newItems = [];
            $scope.selectedItems = [];
         
            var categories = function() {
                return $http.get($scope.model.config.apiUrl)
                    .then(function(data) {
                        $scope.categories = data;
                        for (var i = 0; i < $scope.categories.data.length; i++) {
                            newItems.push({ id: $scope.categories.data[i].id, value: $scope.categories.data[i].name });
                        }
                        $scope.categories = newItems;
                    });
            }
            categories()
                .then(function() {
                    $scope.$on("formSubmitting",
                        function(ev, args) {
                            if ($scope.model.value === null || $scope.model.value === undefined) {
                                $scope.model.value = [];
                            }
                            var selectedCategories = "";

                            angular.forEach($scope.selectedItems,
                                function(value, key) {                                    
                                    var itemSelected = value.selected;
                                    var item = value.val;

                                    selectedCategories = itemSelected === true
                                        ? selectedCategories + item + ","
                                        : selectedCategories + "";
                                });
                            $scope.model.value = selectedCategories.replace(/(^,)|(,$)/g, "");

                        });


                    function setupViewModel() {
                        if ($scope.model.value === null || $scope.model.value === undefined) {
                            $scope.model.value = [];
                        }

                        for (var i = 0; i < $scope.categories.length; i++) {
                            var isSelected = $scope.model.value.includes($scope.categories[i].value);
                           
                            $scope.selectedItems.push({
                                selected: isSelected,
                                key: $scope.categories[i].id,
                                val: $scope.categories[i].value
                            });
                        }
                    }

                    setupViewModel();

                    $scope.$watch("selectedItems",
                        function(newVal, oldVal) {
                            $scope.model.value = [];

                            for (var x = 0; x < $scope.selectedItems.length; x++) {
                                if ($scope.selectedItems[x].checked) {
                                    $scope.model.value.push($scope.selectedItems[x].key);
                                }
                            }
                        },
                        true);


                    $scope.model.onValueChanged = function(newVal, oldVal) {
                        setupViewModel();
                    };
                });
        });


That’s it!! You are done with the coding part.

What’s Next?

Just rebuild your project and go to backoffice where you have to create a new data type for the categories.

Go to Settings – Right click on Data Types to create a new data type.
Select datatype that we just created – Custom Checkbox List

Now, you must be thinking that what is Api Url. Ok, so this is the url of the api you will create to get the categories. I am using categories for this post. However, you can use this field to add other api urls as well to populate the checkbox list with anything you want.

Now, we will add the newly created document type to our content page.

And when you load the content again, you will see the categories populated in the checkbox list.

So now, whenever a new category will be added, the checkbox list will be auto-populated with the new one.

Note: It is good to create a datatype like this before you actually create a content as later on if you delete and update a property in your content, you have to update the data associated as well which could be a complex task sometimes.

Countdown timer in Javascript

Below is the code to create a timer till a specific datetime.

For this sample, the deadline is 5/16/2021 11:26:00

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script language="javascript">

     function getTimeRemaining(endtime) {
      var d = new Date();
      var t = endtime.getTime() - d.getTime(); 

      var seconds = Math.floor((t / 1000) % 60);
      var minutes = Math.floor((t / 1000 / 60) % 60);
      var hours = Math.floor((t / (1000 * 60 * 60)) % 24);
      var days = Math.floor(t / (1000 * 60 * 60 * 24));
      return {
        'total': t,
        'days': days,
        'hours': hours,
        'minutes': minutes,
        'seconds': seconds
      };
     }

   function initializeCountdown(id, endtime) {
    var clock = document.getElementById(id); 
    var daysSpan = clock.querySelector('.days');
    var hoursSpan = clock.querySelector('.hours');
    var minutesSpan = clock.querySelector('.minutes');
    var secondsSpan = clock.querySelector('.seconds');

   function updateTimer() {
        var t = getTimeRemaining(endtime);
       
        daysSpan.innerHTML = t.days;
        hoursSpan.innerHTML = ('0' + t.hours).slice(-2);
        minutesSpan.innerHTML = ('0' + t.minutes).slice(-2);
        secondsSpan.innerHTML = ('0' + t.seconds).slice(-2);

        if (t.total <= 0) {
            clearInterval(timeinterval);
        }
     }
     updateTimer();

     var timeinterval = setInterval(updateTimer, 1000);
    }

    window.onload = function () {
     var deadline = new Date("5/16/2021 11:26:00"); // The datetime of the 
     deadline
     initializeCountdown('clockdiv', deadline);
  }
</script>
</head>

<body>
<form id="form1" runat="server">
   
<div id="clockdiv">
  <div style="float:left;">
    <span class="days"></span>
    <div>Days</div>
  </div>
  <div style="float:left;">
    <span class="hours"></span>
    <div>Hours</div>
  </div>
  <div style="float:left;">
    <span class="minutes"></span>
    <div>Minutes</div>
  </div>
  <div style="float:left;">
    <span class="seconds"></span>
    <div>Seconds</div>
  </div>
</div>
</form>
</body>
</html>

Output –

Portable Laptop Stand Desk – Laptop & Tablet – Portable & Foldable

Download S3 files using PowerShell

Use the below script to download the files from any S3 bucket to your local machine

$sourceBucket = '<bucket name from where you want to copy the files from>'
$profile = '<aws profile name>'
$Folder = '<Folder Path on local drive>'

$items = Get-S3Object -BucketName $sourceBucket -ProfileName $profile -Region 'us-east-1'
Write-Host "$($items.Length) objects to copy"
$index = 1
$items | % {
    Write-Host "$index/$($items.Length): $($_.Key)"
    $fileName = $Folder + ".\$($_.Key.Replace('/','\'))"
    Write-Host "$fileName"
    Read-S3Object -BucketName $sourceBucket -Key $_.Key -File $fileName -ProfileName $profile -Region 'us-east-1' > $null
    $index += 1
}

Find some interesting books on Amazon here –

Amazon S3 Programming Guide: Beginner’s guide book on how to get started with Amazon Simple Storage Service

Amazon S3 For Dummies

Amazon S3 How To Videos

Amazon S3 Hosting For Beginners


Disclosure: We use affiliate links to monetize our content.  We may receive a commission on products or services that you purchase through clicking on links within this blog.

Building APIs with API Gateway

Serverless development allows the developer to focus more on the application code and logic and not worry about the infrastructure details.

Scaling which is handled by AWS also becomes simpler as the developer only has to invoke the APIs in response to events. There are no more idle servers sitting and waiting for the events to trigger as AWS manages the availability of servers as and when required.

The key benefits of serverless development is –

  • No infrastructure management
  • No idle servers
  • High availability
  • Flexible scaling.

There are a number of managed services provided by AWS that act as the building blocks for your application. Some of them are AWS Lambda that provide you with compute services, S3 for storage services, Amazon Aurora for the relations database needs or Dynamo DB for NoSQL databases.

All the interaction with these managed services provided by AWS involve invoking an API and getting the response back which mainly consist of the business logic you need got your application.

The service which we are going to discuss further is API Gateway which is designed to help you develop and operate the APIs.

 

API Gateway

API Gateway is one of the managed services provided by AWS to create, publish, monitor and secure REST and WebSocket APIs. The REST APIs created using API Gateway are HTTP-based and stick to the REST protocol which allows for stateless client-server communication.

You can implement the standard HTTP methods like GET, PUT, POST, DELETE, and PATCH.

You can simply access the API Gateway from the AWS Management Console and if you are using one of the available programming languages in AWS SDKs, then SDK could be used to access the API Gateway. It can also be accessed using the AWS Command Line Interface as well.

 

How API Gateway works

api gateway architecture In the above diagram, on the left we have all users, web and mobile applications, IoT devices and all the private applications that are on VPC or on-premises. All these connect to the API Gateway using the HTTP-based request

API Gateway receives the request and determine what to do with that request. API Gateway adds a CloudWatch monitoring where you can easily monitor the API calls. It also determines if the response from the application is cached in the memory (API Gateway Cache).

API Gateway then invoke a number of backend managed services like AWS Lambda, EC2 endpoints, etc.

 

Choosing the right API endpoint (Host name of the API)

The selection of the right API endpoint depends on where the majority of your application traffic originates. There are basically 3 types of API endpoints –

  • Edge optimized – It is helpful to reduce client latency as the API requests are routed to the nearest CloudFront Point of Presence (POP).
  • Regional – It is helpful to reduce latency when the calls are triggered from the same region as the API
  • Private – It is helpful when you want to only expose the APIs inside your VPC.

Edge Optimized

edge optimized API Gateway deploy a CloudFront distribution which is managed by API Gateway. The nearest CloudFront receives the request from the customer and route it to API Gateway endpoint in the AWS region. This is how the customer latency is reduced.

 

Regional

 

 

This is completely different than Edge Optimized end point that we just discussed above. In this there is no CloudFront distribution deployed by AWS. The customer request directly goes to the API Gateway that are in a specific AWS region. This endpoint provides lot of flexibility as you can customize different scenarios like load balancers, etc.

You can decide how the request from the customer is routed towards the endpoint. You can also add firewalls, caching and SSL certificates as well with this style.

 

Private

 

 

This endpoint is only exposed from within the VPC. It means that all the API requests originates from within your own VPC and they are not exposed publicly.

This type of API endpoint is used for secure work environments like financial institutions, etc.

 

It is very important to select the right API endpoint from the above 3 types. You can easily choose the type of endpoint you want to use from the dropdown while creating the API. If your requirements change later on, you can simply come back and change the API and you are not locked down to only one type of endpoint.