Showing posts with label JQuery. Show all posts
Showing posts with label JQuery. Show all posts

Sunday, July 21, 2013

TYPO3 ExtBase backend module with progressbar using AJAX


Assume you have created a TYPO3 ExtBase Extension and must enable the user to import data (e.g. CSV file) to the tables of your TYPO3 ExtBase extension. With ExtBase, you can easily create a TYPO3 backend module so the user can upload the CSV file and start the data import.

Now assume the user uploads a very big set of data (several 100 MBs) to be imported and starts the data import process. Well, the user will see the hourglass a long, long time and if the user is impacient, he will surely assume that something went wrong and will click somewhere else in the TYPO3 backend and within that cancel the data import.

So would'nt it be nice if you could show the user a progressbar or an updating informal text, that the import is still running?

When you look at the concepts of some extensions with backend modules in TER, you will often see, that PHP methods like flush() or ob_flush() is used to update data in a backend module for long taking processes.

With ExtBase you can't use flush(), since the output for the backend module is rendered with fluid and the output will first display, when the action that displays the content has finished.

In this article I will show how to use AJAX in a TYPO3 ExtBase backend module to show an updating JQuery UI progressbar.



Please note, that the example code located on Github has been created with TYPO3 6.1 and uses namespaces, so it only runs with TYPO3 > 6.x. But - the shown technique can also be adapted to TYPO3 4.5.

First of all, I've created a TYPO3 extension with the extension builder. The extension has a backend module called "mod1". This module uses the controller "Example" and the action "index".

/**
 * Registers a Backend Module
 */
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerModule(
 'derhansen.' . $_EXTKEY,
 'web', // Make module a submodule of 'web'
 'mod1', // Submodule key
 '', // Position
 array(
  'Example' => 'index',
  
 ),
 array(
  'access' => 'user,group',
  'icon'   => 'EXT:' . $_EXTKEY . '/ext_icon.gif',
  'labels' => 'LLL:EXT:' . $_EXTKEY . '/Resources/Private/Language/locallang_mod1.xlf',
 )
);

The extension builder automatically creates Typoscript files with constants and setup settings for the backend module templates. Those settings look like:


templateRootPath = EXT:extbase_bemodule_ajax/Resources/Private/Backend/Templates/

As you may notice, the templates, layouts and partials are located in a subfolder named "Backend". Using this, you always need to include the extension's Typoscript in your sites Typoscript template. If you remove the folder "Backend" and just place your templates, layouts and partials in the "normal" folder-structure of an ExtBase extension, there is no need to include the Typoscript of your extension. I have done this to keep things simple.

Next I've created the layout and the template for the backend module. Notice, that I have created a viewhelper named IncludeJQueryViewHelper, which automatically includes JQuery and JQueryUi with the nesceccary CSS files to the backend module.


{namespace h=derhansen\ExtbaseBemoduleAjax\ViewHelpers\Be}

<h:IncludeJQuery jquery="1" jqueryui="1" />

<f:be.container loadExtJs="0" loadPrototype="0" loadScriptaculous="0">
...
</f:be.container>

Also notice, that the f:be.container viewhelper is configured to disable extJs, prototype and scriptaculous.

In the template for the backend module I have placed some text, a JQuery UI Progressbar and a JQuery UI Button. I also created some Javascript code, which starts starts the progressbar and also retrieves the status of the progressbar by AJAX.

When the start-button is clicked, an AJAX request (startLongProcess) is called which starts a long taking process in our ExampleController. The AJAX request is asynchronous, so the process is not blocking the TYPO3 backend. Right after the long taking process is started, another AJAX request (checkLongProcess) is called which retrieves the status of the long taking process and updates the progressbar.

To keep things simple, the long taking action in the ExampleController just executes a for-loop 20 times and does a sleep(1) on each iteration. Below follows both the startLongProcess action, which starts the long process and the checkLongProcess action, which is used to update the progressbar.


/**
 * Example for a long process (just loops 20 seconds). Returns TRUE if process is finished
 *
 * @return bool TRUE if process is finished
 */
public function startLongProcessAction() {
 for ( $i = 1; $i <= 20; $i++) {
  /* Increase counter stored in session variable */
  session_start();
  $_SESSION['progval'] = $i * 5;
  session_write_close ();
  sleep(1);
 }

 /* Reset the counter in session variable to 0 */
 session_start();
 $_SESSION['progval'] = 0;
 session_write_close ();
 return json_encode(TRUE);
}

/**
 * Checks the status of the long process
 *
 * @return int Status of process in percent
 */
public function checkLongProcessAction() {
 session_start();
 if (!isset($_SESSION['progval'])) {
  $_SESSION['progval'] = 0;
 }
 session_write_close ();
 return json_encode($_SESSION['progval']);
}

Notice, that this example uses PHP session variables to store the actual state of the long taking process. You can also use a database or other techniques to store the actual state.

When working with PHP session variables inside a method, you have to keep in mind, that the session variable is stored, after the method is finished to prevent concurrent writes to the session. To store the session variable while the for-loop is running, you have to use session_write_close() to actually store the session variable.

Finally I updated ext_tables.php so the 2 new actions can be called by the module.

Conclusion
Creating a ExtBase backend module that uses AJAX to dynamically update content on the modules page is quite simple. You can use the same techniques for backend modules as for TYPO3 frontend plugins.

The complete code for the example shown here is available on Github

Saturday, March 2, 2013

Integrating a JQuery Cycle image slider in TYPO3 6.0 without the need of installing an extension

There are a lot of JQuery image slider or slideshow extensions in TYPO3 TER, which (hopefully) all do work very well. Integration is mostly very easy - just install the extension, include some static TS and configure the plugin and there you go with a nice "Out of the box" Image Slider. Thit is surely good for a lot of people using TYPO3.

But some extensions come with their own included version of JQuery, which can't be disabled. Others include a lot of inline CSS and/or JS into the frontend, which also can't be disabled. And some extensions do not work correctly with TYPO3 6.0.

On the way looking for the "perfect" solution for a JQuery Image Slider in TYPO3, I decided not to use an extension (no worry about extension updates, breaking changes or incompatibility), but integration the slider directly into the TYPO3 website using default and well known TYPO3 techniques. The advantages of this is: full flexibility, easy administration and easy usage for editors.

This article shows how to create a JQuery image slider using Jquery Cycle, which is generated from a normal TYPO3 image content element. The slider includes a bullet navigation depending on the number of images.

Prerequisites
You need a working TYPO3 6.0 (lower versions should work as well) installation with CSS Styled Content installed and at least one template, so you actually are able to insert content on a page and see it's output in the frontend.

Integration into TYPO3
First of all, you need download the JQuery Cycle Plugin and upload it somewhere in your fileadmin directory (in this example fileadmin/templates/js/jquery.cycle.all.js).

Next, create a new JS file (fileadmin/templates/js/slider.js), where you put the JS for the JQuery Cycle slider. Insert the following content to the file.

$(document).ready(function () {
    $(".imageslider .csc-textpic-imagewrap").cycle({
        fx:'fade',
        pause:1,
        pager:'.slidernav',
        pagerAnchorBuilder:function paginate(idx, el) {
            return '<a class="' + idx + '" href="#" >•</a>';
        }
    });
});

Now, include the JQuery Cycle Plugin and the newly created JS file to your template. If you have not already included a version of JQuery to your site, make sure to include one.

page.includeJS {
  jquery = http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js
  jquery.external = 1
  cycle = fileadmin/templates/js/jquery.cycle.all.js
  slider = fileadmin/templates/js/slider.js 
}

The slider also requires some CSS for positioning of the bullet navigation. Include the following CSS to your sites CSS file.

.imageslider {
    position: relative;
    width: 300px;
    height: 225px;
    overflow: hidden;
}

.slidernav {
    position: absolute;
    z-index: 10;
    top: 170px;
    right: 20px;
}

.slidernav a {
    text-decoration: none;
    color: #ffffff;
    font-size: 40px;
    margin: 0 0 0 5px;
}

.slidernav a.activeSlide {
    color: #bbbbbb;
}

/* remove default bottom margin */
.imageslider .csc-textpic-image {
  margin: 0;
}

Please notice, that in this example I set the width and height of the image slider to a width of 300 pixel and a height of 225 pixel. This is'nt really necessary, but it makes it easier to position the bullet navigation to the bottom right.

As I don't like to override the default settings of CSS styled content or tt_content, I create a new frame, which the editor can select in the frame-dropdown of each content element.

Include the following to your root Page TSConfig.

TCEFORM.tt_content.section_frame {
     addItems.100 = Slider 
}

Now you must enable the new frame and include the HTML tags for the slider with the following TS.

tt_content.stdWrap.innerWrap.cObject {
  100 = TEXT
  100.value = <div class="imageslider"><ul class="slidernav"></ul>|</div>
}

That's all - the JQuery Cycle image slider is now ready for usage.

Usage
Create a new content element with images only and insert some images.


Set the "Indentation and Frames" to "Slider", the width of the images and the image alignment to 1 column.

Save the content element and you're done.

If you open the page in the frontend, you should see an image slider like shown on the screenshot below.


Conclusion
I hope this article gives you a perspective on what is possible with TYPO3's image content element and just some lines of TS, JS and CSS. If you want a next and previous button for the slider, no problem - just use the "prev" and "next" option of JQuery Cycle plugin.

As you have seen, it is not always necessary to install an extension to integrate an image slider to TYPO3. With the shown solution, editors can use TYPO3's default content elements and the site administrator has full control of the sliders features and can use all nice options of the JQuery Cycle plugin.

Please notice, that everything shown in this article is just an example on how a JQuery Cycle image slider could be integrated into TYPO3. Feel free to modify the settings to your own needs.

Update 15.05.2013
You have to make sure that the JS file, which enables the JQuery Cycle slider, gets the DIV-tag, which contain the container elements for the images. Below is an example for images, which are aligned "above, center". The second line contains the part, where you select the DIV with elements to cycle.

$(document).ready(function () {
    $(".imageslider .csc-textpic-center-inner").cycle({
        fx:'fade',
        pause:1,
        pager:'.slidernav',
        pagerAnchorBuilder:function paginate(idx, el) {
            return '';
        }
    });
});