Monthly Archiv: January, 2015

New Free Banner Rotation Perl Script: rotate the advertisements on your website automatically

Another free program has been added to the Free Banner Rotation Perl CGI Scripts page. Such scripts allow you to rotate the banners/pictures that are displayed on your website so that different ones are shown each time your page is loaded. Webmasters typically use such scripts to rotate advertisements.

Tutorial: Making a Shoutbox with PHP and jQuery

shoutbox-php-jquery

In this tutorial, we are going to build a shout box with PHP and jQuery, which allows visitors of your website to leave short comments to one another. Shouts will be stored on the server as files, no database like MySQL will be required. We are going to use two PHP libraries to make things easier – Flywheel for storing the shouts as json files and RelativeTime for creating human readable relative time stamps. We will be using Composer to install these libraries.

On the client side, we are using plain jQuery code, and the Emoji One library, which is a free project and library for adding pretty emojis to web apps. Let’s begin!

Running the shoutbox

You can grab the source code from the download button above. It has plenty of comments and is easy to follow. To run it, simply upload it to your web hosting space or add it to the apache htdocs folder if you run something like XAMPP or MAMP. Then, open http://localhost in your browser (or your website, if you uploaded it to your hosting space). Here are a few things to look for:

  • The zip files already contains the dependencies, so you don’t need to install Composer. This makes it easy to get started with the code – simply upload it and use it!
  • Make sure that the data/shouts directory exists and is writable. Otherwise you will see errors in your log file and no shouts will be stored. You might need to chmod it to 777 if you keep seeing errors.

The HTML

Let’s start with index.html. It is a regular HTML5 document, which includes our JavaScript libraries, scripts and stylesheets. Here are the parts relevant to the shoutbox:

index.html

<div class="shoutbox">
    
    <h1>Shout box <img src='./assets/img/refresh.png'/></h1>
    
    <ul class="shoutbox-content"></ul>
    
    <div class="shoutbox-form">
        <h2>Write a message <span>×</span></h2>
        
        <form action="./publish.php" method="post">
            <label for="shoutbox-name">nickname </label> <input type="text" id="shoutbox-name" name="name"/>
            <label class="shoutbox-comment-label" for="shoutbox-comment">message </label> <textarea id="shoutbox-comment" name="comment" maxlength='240'></textarea>
            <input type="submit" value="Shout!"/>
        </form>
    </div>
    
</div>

With JavaScript we will insert the published shouts into the <ul> element. The form is hidden by default, and only revealed when the “Write a message” header is clicked.

Shoutbox with PHP and jQuery

Shoutbox with PHP and jQuery

The JavaScript Code

And here is our script.js, which makes the above HTML work:

assets/js/script.js

$(function(){

    // Storing some elements in variables for a cleaner code base

    var refreshButton = $('h1 img'),
        shoutboxForm = $('.shoutbox-form'),
        form = shoutboxForm.find('form'),
        closeForm = shoutboxForm.find('h2 span'),
        nameElement = form.find('#shoutbox-name'),
        commentElement = form.find('#shoutbox-comment'),
        ul = $('ul.shoutbox-content');

    // Replace :) with emoji icons:
    emojione.ascii = true;

    // Load the comments.
    load();
    
    // On form submit, if everything is filled in, publish the shout to the database
    
    var canPostComment = true;

    form.submit(function(e){
        e.preventDefault();

        if(!canPostComment) return;
        
        var name = nameElement.val().trim();
        var comment = commentElement.val().trim();

        if(name.length && comment.length && comment.length < 240) {
        
            publish(name, comment);

            // Prevent new shouts from being published

            canPostComment = false;

            // Allow a new comment to be posted after 5 seconds

            setTimeout(function(){
                canPostComment = true;
            }, 5000);

        }

    });
    
    // Toggle the visibility of the form.
    
    shoutboxForm.on('click', 'h2', function(e){
        
        if(form.is(':visible')) {
            formClose();
        }
        else {
            formOpen();
        }
        
    });
    
    // Clicking on the REPLY button writes the name of the person you want to reply to into the textbox.
    
    ul.on('click', '.shoutbox-comment-reply', function(e){
        
        var replyName = $(this).data('name');
        
        formOpen();
        commentElement.val('@'+replyName+' ').focus();

    });
    
    // Clicking the refresh button will force the load function
    
    var canReload = true;

    refreshButton.click(function(){

        if(!canReload) return false;
        
        load();
        canReload = false;

        // Allow additional reloads after 2 seconds
        setTimeout(function(){
            canReload = true;
        }, 2000);
    });

    // Automatically refresh the shouts every 20 seconds
    setInterval(load,20000);


    function formOpen(){
        
        if(form.is(':visible')) return;

        form.slideDown();
        closeForm.fadeIn();
    }

    function formClose(){

        if(!form.is(':visible')) return;

        form.slideUp();
        closeForm.fadeOut();
    }

    // Store the shout in the database
    
    function publish(name,comment){
    
        $.post('publish.php', {name: name, comment: comment}, function(){
            nameElement.val("");
            commentElement.val("");
            load();
        });

    }
    
    // Fetch the latest shouts
    
    function load(){
        $.getJSON('./load.php', function(data) {
            appendComments(data);
        });
    }
    
    // Render an array of shouts as HTML
    
    function appendComments(data) {

        ul.empty();

        data.forEach(function(d){
            ul.append('<li>'+
                '<span class="shoutbox-username">' + d.name + '</span>'+
                '<p class="shoutbox-comment">' + emojione.toImage(d.text) + '</p>'+
                '<div class="shoutbox-comment-details"><span class="shoutbox-comment-reply" data-name="' + d.name + '">REPLY</span>'+
                '<span class="shoutbox-comment-ago">' + d.timeAgo + '</span></div>'+
            '</li>');
        });

    }

});

The Emoji One library has version for both JavaScript and PHP. In the appendComments method, we use the emojione.toImage() function to convert all typed-out smileys into emoji. See all functions that are supported, and check out this handy emoji code website. Now that the frontend is ready, let’s move on to the backend.

The PHP Code

We have two files – publish.php and load.php. The first accepts a POST request for storing shouts in the data store, and the second returns the 20 latest shouts. These files are not opened directly by visitors – they only handle AJAX requests.

publish.php

<?php

// Include our composer libraries
require 'vendor/autoload.php';

// Configure the data store

$dir = __DIR__.'/data';

$config = new JamesMossFlywheelConfig($dir, array(
    'formatter' => new JamesMossFlywheelFormatterJSON,
));

$repo = new JamesMossFlywheelRepository('shouts', $config);
    
// Store the posted shout data to the data store

if(isset($_POST["name"]) && isset($_POST["comment"])) {
    
    $name = htmlspecialchars($_POST["name"]);
    $name = str_replace(array("n", "r"), '', $name);

    $comment = htmlspecialchars($_POST["comment"]);
    $comment = str_replace(array("n", "r"), '', $comment);
    
    // Storing a new shout

    $shout = new JamesMossFlywheelDocument(array(
        'text' => $comment,
        'name' => $name,
        'createdAt' => time()
    ));
    
    $repo->store($shout);
    
}

Here we directly use the Flywheel library we mentioned in the beginning. Once it is configured, you can store any type of data, which will be written as a JSON file in the data/shouts folder. Reading these shouts is done in load.php:

load.php

<?php

require 'vendor/autoload.php';

// If you want to delete old comments, make this true. We use it to clean up the demo.
$deleteOldComments = false;

// Setting up the data store

$dir = __DIR__.'/data';

$config = new JamesMossFlywheelConfig($dir, array(
    'formatter' => new JamesMossFlywheelFormatterJSON,
));

$repo = new JamesMossFlywheelRepository('shouts', $config);

// Delete comments which are more than 1 hour old if the variable is set to be true.

if($deleteOldComments) {
    
    $oldShouts = $repo->query()
                ->where('createdAt', '<', strtotime('-1 hour'))
                ->execute();

    foreach($oldShouts as $old) {
        $repo->delete($old->id);
    }
    
}

// Send the 20 latest shouts as json

$shouts = $repo->query()
        ->orderBy('createdAt ASC')
        ->limit(20,0)
        ->execute();

$results = array();

$config = array(
    'language' => 'RelativeTimeLanguagesEnglish',
    'separator' => ', ',
    'suffix' => true,
    'truncate' => 1,
);

$relativeTime = new RelativeTimeRelativeTime($config);
        
foreach($shouts as $shout) {
    $shout->timeAgo = $relativeTime->timeAgo($shout->createdAt);
    $results[] = $shout;
}

header('Content-type: application/json');
echo json_encode($results);

We’ve included code which deletes shouts older than an hour. We use this feature to keep the demo clean. You can enable it if you wish. After selecting the shouts, we are also calculating the human-readable relative time stamp with the RelativeTime library.

With this our shoutbox is ready! You can embed it in your website, customize it and change the code any way you please. We hope you like it!

Creating Your First Desktop App With HTML, JS and Node-WebKit

first-nodewebkit-app

These days you can do pretty much anything with JavaScript and HTML. Thanks to Node-WebKit, we can even create desktop applications that feel native, and have full access to every part of the operating system. In this short tutorial, we will show you how to create a simple desktop application using Node-WebKit, which combines jQuery and a few Node.js modules.

Node-WebKit is a combination of Node.js and an embedded WebKit browser. The JavaScript code that you write is executed in a special environment and has access to both standard browser APIs and Node.js. Sounds interesting? Keep reading!

Update (15th Jan 2015) – Just after a week of publishing this tutorial, node-webkit was renamed to NW.js. For now, this tutorial is perfectly compatible with it. In the future we might update it if there are any changes.

Installing Node-WebKit

For developing applications, you will need to download the node-webkit executable, and call it from your terminal when you want to run your code. (Later you can package everything in a single program so your users can only click an icon to start it).

Head over to the project page and download the executable that is built for your operating system. Extract the archive somewhere on your computer. To start it, you need to do this in your terminal:

# If you are on linux/osx

/path/to/node-webkit/nw /your/project/folder

# If you are on windows

C:pathtonode-webkitnw.exe C:yourprojectfolder

# (the paths are only for illustrative purposes, any folder will do)

This will open a new node-webkit window and print a bunch of debug messages in your terminal.

You can optionally add the extracted node-webkit folder to your PATH, so that it is available as the nw command from your terminal.

Your First Application

There is a Download button near the top of this article. Click it and get a zip with a sample app that we prepared for you. It fetches the most recent articles on Tutorialzine from our RSS feed and turns them into a cool looking 3D carousel using jQuery Flipster.

Directory Structure

Directory Structure

Once you extract it, you will see the files above. From here this looks like a standard static website. However, it won’t work if you simply double click index.html – it requires Node.js modules, which is invalid in a web browser. To run it, CD into this folder, and try running the app with this command:

/path/to/node-webkit/nw .

This will show our glorious desktop app.

Our node-webkit app

Our node-webkit app

How it was made

It all starts with the package.json file, which node-webkit looks up when starting. It describes what node-webkit should load and various parameters of the window.

package.json

{
  "name": "nw-app",
  "version": "1.0.0",
  "description": "",
  "main": "index.html",
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1"
  },
  "author": "",
  "window": {
    "toolbar": false,
    "width": 800,
    "height": 500
  },
  "license": "ISC",
  "dependencies": {
    "pretty-bytes": "^1.0.2"
  }
}

The window property in this file tells node-webkit to open a new window 800 by 500px and hide the toolbar. The file pointed to by the main property will be loaded. In our case this is index.html:

index.html

<!DOCTYPE html>
<html>
<head>

	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">

	<title>Tutorialzine Node-Webkit Experiment</title>

	<link rel="stylesheet" href="./css/jquery.flipster.min.css">
	<link rel="stylesheet" href="./css/styles.css">

</head>
<body>

	<div class="flipster">
		<ul>
			<!-- Tutorialzine's latest articles will show here -->
		</ul>
	</div>

	<p class="stats"></p>

	<script src="./js/jquery.min.js"></script>
	<script src="./js/jquery.flipster.min.js"></script>
	<script src="./js/script.js"></script>
</body>
</html>

And finally, here is our JavaScript file. This is where it gets interesting!

js/script.js

// Mixing jQuery and Node.js code in the same file? Yes please!

$(function(){


	// Display some statistic about this computer, using node's os module.

	var os = require('os');
	var prettyBytes = require('pretty-bytes');

	$('.stats').append('Number of cpu cores: <span>' + os.cpus().length + '</span>');
	$('.stats').append('Free memory: <span>' + prettyBytes(os.freemem())+ '</span>');

	// Node webkit's native UI library. We will need it for later
	var gui = require('nw.gui');


	// Fetch the recent posts on Tutorialzine

	var ul = $('.flipster ul');

	// The same-origin security policy doesn't apply to node-webkit, so we can
	// send ajax request to other sites. Let's fetch Tutorialzine's rss feed:

	$.get('http://feeds.feedburner.com/Tutorialzine', function(response){

		var rss = $(response);

		// Find all articles in the RSS feed:

		rss.find('item').each(function(){
			var item = $(this);
			
			var content = item.find('encoded').html().split('</a></div>')[0]+'</a></div>';
			var urlRegex = /(http|ftp|https)://[w-_]+(.[w-_]+)+([w-.,@?^=%&amp;:/~+#]*[w-@?^=%&amp;/~+#])?/g;

			// Fetch the first image of the article
			var imageSource = content.match(urlRegex)[1];


			// Create a li item for every article, and append it to the unordered list

			var li = $('<li><img /><a target="_blank"></a></li>');

			li.find('a')
				.attr('href', item.find('link').text())
				.text(item.find("title").text());

			li.find('img').attr('src', imageSource);

			li.appendTo(ul);

		});

		// Initialize the flipster plugin

		$('.flipster').flipster({
			style: 'carousel'
		});

		// When an article is clicked, open the page in the system default browser.
		// Otherwise it would open it in the node-webkit window which is not what we want.

		$('.flipster').on('click', 'a', function (e) {

			e.preventDefault();
			
			// Open URL with default browser.
			gui.Shell.openExternal(e.target.href);

		});

	});

});

Notice that we are accessing Tutorialzine’s RSS feed directly with jQuery, even though it is on a different domain. This is not possible in a browser, but Node-WebKit removes this limitation to make development of desktop applications easier.

Here are the node modules we’ve used:

  • Shell – A node webkit module that provides a collection of APIs that do desktop related jobs.
  • OS – The built-in Node.js OS module, which has a method that returns the amount of free system memory in bytes.
  • Pretty Bytes – Convert bytes to a human readable string: 1337 → 1.34 kB.

Our project also includes jQuery and the jQuery-flipster plugin, and that’s pretty much it!

Packaging and Distribution

You most certainly don’t want your users to go through the same steps in order to run you application. You wan’t to package it in a standalone program, and open it by simply double clicking it.

Packaging node-webkit apps for multiple operating systems takes a lot of work to do manually. But there are libraries that do this for you. We tried this npm module – https://github.com/mllrsohn/node-webkit-builder, and it worked pretty well.

The only disadvantage is that the executable files have a large size (they can easily hit 40-50mb) , because they pack a stripped down webkit browser and node.js together with your code and assets. This makes it rather impractical for small desktop apps (such as ours), but for larger apps it is worth a look.

Conclusion

Node-webkit is a powerful tool that opens a lot of doors to web developers. With it, you can easily create companion apps for your web services and build desktop clients which have full access to the users’s computer.

You can read more about node-webkit on their wiki.

Powered by Gewgley