Blog

dojo.dnd Elemente programmatisch zwischen Containern verschiebenProgrammatically move dojo.dnd items between containers

In order to programmatically move dojo.dnd items (dojo.dnd.Item) between containers (dojo.dnd.Container) you only need to insert existing nodes from the source container into the target container, delete any moved nodes from the source container and finally sync() both containers to update the underlying metadata.

The following code snippet should clarify this principle. It demonstrates that items are only moved from the source container if their value does not match an expected value:

//only moving items if expected value is not met
if (srcContainer.getItem(node.id).data != expectedValue) {                    
  targetContainer.insertNodes(false, [dojo.byId(node.id)]);
  targetContainer.sync();

  srcContainer.delItem(node.id);
  srcContainer.sync(); //sync nodes and metadata
}

Hint: dojo.dnd underlying principle is a separation between data and nodes. So whenever you alter one part of an dndItem (data or node) be sure to synchronize its state by calling sync(). See the official reference guide for more information: dojo.dnd package

body onLoad Event im ZK JavaScript Frameworkbody onLoad Event in ZK JavaScript Framework

Um den body-onLoad Event einer ZK-basierten Anwendung zu realisieren verwendet man einfachsten das eingebaute JQuery, mit der darin enthaltenen load-Funktion:

<script>
  jq(this).load(
    dojo.connect(dojo.byId('someNode'), "onclick", function() {
      dojo.query('#someOtherNode')[0].focus();
      dojo.query('#someOtherNode')[0].select();
    });
</script>

Dieses Beispiel verwendet zusätzlich das Dojo-Toolkit welches folgendermaßen in ZK eingebunden werden kann:

<script src="lib/dojo/dojo.js">
  djConfig={parseOnLoad:true};
</script>

Um zu überprüfen ob alle DOM Elemente auch tatsächlich fertig geladen wurden sollten Elementzugriffe noch mittels der ready-Funktion gekapselt werden:

jq(this).ready(function() {
  dojo.byId('someNode')...
});

Emuliere onClick Event für labels via Client Seite in ZKEmulate onClick event for labels in ZK via the client side

Recently I needed to emulate the built-in functionality of HTML <label> entities to put the focus on its referenced item using the ZK JavaScript framework. Basically, the goal was to define an onClick event for the label that would toggle the checked-status of a checkbox and simultaneously trigger its onCheck event (sending the update request to the server side, thus synchronizing the client with the server side). The checkbox itself controlled the autodrop-status of an auto-completing combobox.

Consequently, once the checkbox is checked the autodrop-functionality of the combobox should be either enabled or disabled. Since the same functionality should be provided by clicking on the label (which failed to register itself with the corresponding checkbox…) an additional onClick event for the label was introduced.

Unfortunately, firing the onCheck event via the label’s onClick event did not automatically fire the corresponding server update message. Therefore some further manual adjustments had to be made. The final result is shown in the following:

<combobox id="autoCompleter" autodrop="true" use="at.kerstner.AutoCompleter"/>
<checkbox id="autoCompleter_checkbox" checked="true" onCheck="autoCompleter.autodrop=self.checked"/>
<label id="autoCompleter_ext" value="Autocomplete?" 
          w:onClick="this.$f('autoCompleter_checkbox').setChecked(!this.$f('autoCompleter_checkbox').isChecked());   
                           this.$f('autoCompleter_checkbox').fire('onCheck', this.$f('autoCompleter_checkbox').isChecked());"/>

The combobox was implemented through the Autocompleter-class, which represents an (simple) extension of ZK’s built-in Combobox widget. By default it is checked and the autodrop-functionality is enabled. The label’s onClick event should emulate the missing functionality to trigger the checkbox’s onCheck event.

In ZK components can be referenced from the client side via the this.$f() function. Thus, the first thing to be when the onClick event is triggered is to update to checked status of the checkbox. Since the onCheck event did not fire automatically the second step was to emulate the onCheck event of the checkbox triggering the update message being sent to the server.

E-Learning Standards – Critical and Practical Perspectives

The following PDF represents my master’s thesis written in the course of my master studies  “Software Development and Business Management” at the Graz University of Technology.

Abstract

Due to rapid technological advances in the past decade, e-learning has experienced substantial growth. Especially bigger, training intensive companies have recognized the potential of reusable electronic learning material.

As a consequence, a lot of effort has been spent on creating e-learning standards, that address every possible learning scenario imaginable. Unfortunately, it is exactly this objective that has caused them to evolve into complex structures, that are very costly to implement. In addition, after years of design, current prominent e-learning standards, such as SCORM, are still in a developmental stage. This reflects the endeavor to merge existing diverse business interests of the companies involved in the standardization process.

Moreover, the majority of current e-learning standards have been designed by technicians rather than educators and, according to critics, lack the pedagogical aspect of learning, being a collection of computer standards, rather than of learning standards per se. The implied conformity of current e-learning standards even created the “EduPunk” movement, which denunciates the constrictive inherent generality of existing electronic learning standard approaches.

This thesis focuses on presenting e-learning in general, together with a selection of current prominent e-learning standards, such as SCORM and QTI, from a critical and practical perspective. Based on this theoretical background, this thesis presents a practical implementation of an e-learning platform called “Wörterwelt”, which has been developed with a focus on common web standards in contrast to strict adherence to existing de facto e-learning standards.

BibTex Citation

@booklet{Kerstner2011,
  author       = {Kerstner, Matthias},
  title        = {E-Learning Standards - Critical and Practical Perspectives},
  year         = {2011},
  month        = apr,
  date         = {4},
  note         = {\url{https://www.kerstner.at/wp-content/uploads/2011/05/E-Learning-Standards-Critical-and-Practical-Perspectives.pdf}}
}

Download:

E-Learning Standards – Critical and Practical Perspectives

Presentation

Access protection using Apache’s .htaccess and PHP

Sometimes it is necessary to limit access to certain files and folders based on your own PHP backend authentication script, i.e. you cannot use Apache’s built-in user authentication, but rather rely on backend authentication provided by your PHP framework.

The following script demonstrates a simple approach to realize access protection using a .htaccess file in combination with a backend PHP authentication script (index.php). The .htaccess file redirects requests to a PHP file called index.php residing in the data directory you want to protect. The index.php file handles the backend authorization process, as well as returns the corresponding file on success and the corresponding HTTP error code on error.

  1. .htaccess
    # restrict access to server files, such as .htaccess
    <Files .ht*>
      order allow,deny
      deny from all
    </Files>
    
    <IfModule mod_rewrite.c>
       RewriteEngine On
       #RewriteBase /
    
       # redirect to /your_data_dir/index.php
       RewriteCond %{REQUEST_URI} !(/your_data_dir/index.php.*)
       RewriteRule ^(.+)$ /your_data_dir/index.php?$1 [QSA,L]
    </IfModule>
    
  2. index.php

    try {

    if (!$DO_SOME_BACKEND_AUTH_CHECKING) {
    header($_SERVER[“SERVER_PROTOCOL”] . ” 403 Forbidden”);
    flush();
    exit;
    }

    $queryString = $_SERVER[‘QUERY_STRING’];

    if ($queryString == ”) {
    throw new Exception(‘No resource specified.’);
    }

    $queryStringParts = explode(“/”, $queryString);
    $saneQueryStringParts = “”; //clean path

    if (count($queryStringParts) < 1) { throw new Exception('No resource specified.'); } foreach ($queryStringParts as $p) { $saneQueryStringParts .= ( $saneQueryStringParts != '' ? '/' : '') . basename($p); } $file = $queryStringParts[count($queryStringParts) - 1]; $filePath = YOUR_DATA_PATH . $saneQueryStringParts; if ($file == '' || $saneQueryStringParts == '' || !file_exists($filePath)) { //send HTTP-404 header($_SERVER["SERVER_PROTOCOL"] . " 404 Not Found"); flush(); exit; } $finfo = finfo_open(FILEINFO_MIME_TYPE); if ($finfo === false) throw new Exception('Failed to determine mime-type.'); $mime = finfo_file($finfo, $filePath); if ($mime === false) throw new Exception('Failed to determine mime-type.'); header('Content-type: ' . $mime); header('Content-Disposition: attachment; filename="' . $file . '"'); readfile($filePath); } catch (Exception $e) { header($_SERVER["SERVER_PROTOCOL"] . " 500 Internal Server Error"); flush(); exit; } [/php]

Using this approach you can refer to your files and folders using their original structures, such as http://your_server/data_dir/images/img_1.png. The .htaccess file will redirect this request to the authentication script index.php residing in /data_dir/index.php using /images/img_1.png as query string. The query string will be converted by basename() for safe use and the resulting file will be returned.

You need PHP’s FileInfo package in order to use index.php, see http://php.net/manual/en/book.fileinfo.php for more information.

Optionally, you could create an alias in .htaccess (or directly in the vhost settings) that redirects requests to resources inside /data/… to a location outside of your DOCUMENT_ROOT, like so:

    Alias /data /your/data/directory
    <Directory "/your/data/directory">
      ...
    </Directory>

Reset Moodle admin account via shell

In order to quickly reset Moodle’s admin password (or any other user account for that matter) you can issue the following command via the shell:

/opt/lampp/bin/mysql -h 127.0.0.1 -u root --password=rootpass --database=moodle -e "update user set password='`/opt/lampp/bin/php -r "echo md5('something_fancy');"`' where username='admin'"

Note that the command above uses a XAMPP setup. You should replace the path to the MySQL/PHP executables accordingly.

Conclusion: Since Moodle’s password system currently only uses plain MD5 to save passwords (without salting it…) it is rather easy to change existing passwords via the shell or any other script.

Update: MoodleDocs provides documentation on how to use the reset_password.php script, see http://docs.moodle.org/en/Administration_via_command_line#Reset_user_password.

dijit.form.Button versteckenHide dijit.form.Button

In order to hide dijit.form.Buttons (and other dijits for that matter) you need to access the dijit’s DOM element and set the CSS styles visibility and display correspondingly, like so:

dojo.style(dijit.byId('yourDijit').domNode, {
  visibility: (hideMe ? 'hidden' : 'visible'),
  display: (hideMe ? 'none' : 'block')
});

Install Apache Tomcat under Ubuntu 10.10

The following steps are required to install Apache Tomcat under Ubuntu 10.10:

  1. install Sun Java JRE/SDK

    For guidelines see for instance http://www.mkyong.com/java/how-to-install-java-jdk-on-ubuntu-linux/.
  2. set PATH, CLASSPATH and JAVA_HOME (Ubuntu should set it automatically when installing Java:
    export PATH=$PATH:/usr/lib/jvm/java-6-sun/bin
    export JAVA_HOME="/usr/lib/jvm/java-6-sun"
    export CLASSPATH="/usr/lib/jvm/java-6-sun"
    

    Hint: In case you want to make this changes permanent and system-wide you could edit /etc/environment accordingly.

  3. download and unpack Apache Tomcat to for instance /opt/tomcat/
  4. start Apache Tomcat using:
    sudo /opt/tomcat/bin/startup.sh
    

    Tomcat should start with the following settings:

    Using CATALINA_BASE:   /opt/tomcat
    Using CATALINA_HOME:   /opt/tomcat
    Using CATALINA_TMPDIR: /opt/tomcat/temp
    Using JRE_HOME:        /usr
    Using CLASSPATH:       /opt/tomcat/bin/bootstrap.jar
    
  5. sometimes it is useful to change CATALINA_HOME to your local (NetBeans, Eclipse, etc.) workspace:
    export CATALINA_HOME="/home/xyz/workspace"
    
  6. activate Tomcat’s manager by creating a manager-user in tomcat-users.xml:
    <?xml version='1.0' encoding='utf-8'?>
    <tomcat-users>
      <role rolename="manager"/>
      <user username="admin" password="secret" roles="admin,manager"/>
    </tomcat-users>
    

Hint: When deploying using for instance NetBeans be sure that the current user has enough rights for the corresponding Tomcat working directory, e.g. /opt/tomcat/work/. This can be achieved with chown or chmod from within the shell.

Apache Wartungsseite mit .htaccess und mod_rewriteApache maintenance page using .htaccess and mod_rewrite

A maintenance page comes in handy to inform users about planned downtime of a web application.

This posts explains how to implement a simple maintenance page using Apache’s .htaccess together with mod_rewrite. This setup has also been tested using vhost settings.

  1. Define your (vhost) settings, to allow .htaccess to override settings used by mod_redirect:

    <VirtualHost *:80>
      ServerName name.localhost
      DocumentRoot "/full/path/to/web"
      <Directory "/full/path/to/web">
        AllowOverride All
        Allow from All
      </Directory>
    </VirtualHost>
    
  2. Define redirect rule in .htaccess:

    <IfModule mod_rewrite.c>
       RewriteEngine On
       #RewriteBase /
       RewriteCond %{DOCUMENT_ROOT}/maintenance -f
       RewriteCond %{REQUEST_FILENAME} !(maintenance.jpg)$
       RewriteRule .* maintenance.php [L]
    </IfModule>
    
  3. Write the maintenance.php file:
    <div style="text-align: center; padding-top: 50px;">
      <h2>Maintenance...</h2>
      <p><img title="maint" border="0" alt="maint" src="maintenance.jpg" /></p>
    </div>
    

In order to enable the maintenance mode simply create a file called maintenance inside your document root. The .htaccess will detect this file when a request is received and will check if either the maintenance image is requested (which will be served as usual) or any other page, which will be redirected to the maintenance page.

Hint: You might want to include an automatic logout section in the maintenance page, so that in case users with active sessions will be logged out gracefully when requesting pages with the maintenance mode enabled, e.g.:

<?php
  session_start();
  $_SESSION = array();

  if(isset($_COOKIE[session_name()])) {
    setcookie(session_name(), '', time() - 42000, '/');
  }

  session_destroy();
?>

Assigning PHP variables in shell

For a project I am currently working on it was necessary to read PHP define()’d-values from a configuration file using a shell script that did some further processing.

In order to be able to read define()’d-values you need to first include() (or better require_once()) the source configuration file(s) and then assign its values to shell variables.

  1. Determine path to PHP:
    PHP_PATH="/opt/lampp/bin/php"
    
  2. Include any required configuration files:
    PHP_REQUIRE="require_once('$(pwd)/../src/config/base.php');"
    
  3. Finally assign PHP variables to shell:
    RELEASE_NUMBER=`$PHP_PATH -r "$PHP_REQUIRE echo RELEASE_VERSION;"`
    

Hint: In case your PHP installation is included in PATH you can simply write PHP_PATH=”php”.

In this example the release version number is read from a base-configuration file, which will be used by the shell script for further processing.

Fritz!Box DHCP Client Id Ubuntu

Today I noticed that when trying to DNS-resolve my Ubuntu laptop from within my home network the Fritz!Box set up failed to do its job. When looking in the Fritz!Box’s configuration menu I found out that it failed to identify Ubuntu devices by name, only by their MAC address (the corresponding name field was empty).

In order to “help” the Fritz!Box to identify Ubuntu devices by name simply enter the “DHCP client ID” in System/Preferences/Network Connections, as shown in the following image.

Ubuntu DHCP client ID

This was tested with FRITZ!Box Fon WLAN 7140 Annex A, Firmware-Version 39.04.41.

Filter dijits using dojo.query

Yesterday I struggled to find a way to filter all dijits in a root container (in my case a simple <div>) to toggle their enabled/disabled state. The approach I was using before looked like this:

dojo.query("input, button, textarea, select", rootContainer).attr("disabled", disable);

This approach used to work fine until I also wanted to include <buttons>. Unfortunately, dojo.query() failed to filter buttons… Every scenario I’ve tried only revealed inputs (except input type=button), textareas, selects, etc.

Anyway, the solution was to filter all DOM-nodes by their “widgetId” attribute and convert to their respective dijits through dijit.byNode, as explained by dante in http://stackoverflow.com/questions/1372013/dojo-disable-all-input-fields-in-div-container.

Thus, the final solution I came up with was to use a wrapper function:

/**
 * Disables all dijits found in rootContainer specified. The params directly
 * refer to dojo.quer().
 * @param String limitations
 * @param String|Object rootContainer
 */
disableDijits : function(limitations, rootContainer) {
  var widgets = dojo.query(limitations, rootContainer).map(dijit.byNode);
  dojo.forEach(widgets, function(w) {
    w.attr('disabled', disable);
  });
}

Dynamic Website Template

A simple template-based script for dynamic websites written in PHP.

Download: N/A

Installation

  1. Unpack the zip file in your webserver directory (eg. /home/you/www/)
  2. Edit config.php to your needs.
  3. Copy all your content files (files you want to be dynamically loaded) into the your PATH_CONTENT directory, which is /home/you/www/content/ by default.
  4. For each content file add an entry in the definitions source from above:
    1. FF: For syntax information please refer to dwt/definitions.php.
    2. DB: please refer to the dwt_initial.sql for structural info.
  5. Call index.php to use your shiny new dynamic website

Configuration

Everything you need (or can) configure can be found in dwt/config.php.

Usage

Have a look at the sample index.php. The most important functions you will need are:

  1. displayContent(): loads page specified by id
  2. displayNavigation(): loads navigation file specified in config.php

e.g. http://www.you.com/index.php?id=12

This request will load the page specified in dwt/definitions.php with ID 12.

Changelog

Yet Another PHP Web Application Framework (YAPWAF)Yet Another PHP Web Application Framework (YAPWAF)

Yet Another PHP Web Application Framework (YAPWAF) ist ein kompaktes und flexibles (MVC) Webanwendungs Framework, das vollständig in PHP verfasst wurde.

Bekannte Frameworks wie etwa das Zend Framework sind häufig speziell für kleinere Webanwendungen wegen des Konfigurationsoverheads zu aufwendig gestaltet und verfehlen daher möglicherweise ihren Zweck. Dank seines schlanken Designs und der einfachen Bedienbarkeit kann YAPWAF hier Abhilfe schaffen.

Der modulare Aufbau ermöglicht eine einfache Konfiguration und Erweiterbarkeit.