User:Amr M. Elabsy/Blogs/Third Blog:The First Real Output

Abstract edit

In the First month of my Google Summer of Code participation, I made the "Text with autocomplete", "Textarea with autocomplete", "Date Picker", "DateTime Picker" input types and "#forminput" stop using jQuery UI. That involves converting "Text(area) with autocomplete" into stubs for "Tokens" and "Combobox", make "#forminput" call the functions of "Combobox", and replace "Date Picker" and "DateTime Picker" with the corresponding Widgets in OOUI, "DateInputWidget" and "DateTimeInputWidget". Almost every step of them needed some working and handling, that will be discussed.

Introduction edit

The project "Remove use of jQuery UI in Extension:PageForms" aims to delete the usage of the deprecated Library jQuery UI, which is used in many functionalities, Autocomplete, date and date time picker, Tree input type and The Tables. The first month has witnessed finishing almost half of the whole project, which is counted as a great progress. When getting rid of jQuery UI, some another libraries are used, Select2.js for autocompletion, OOUI for Date(Time) Picker, and the other libraries for the other functionalities will be discussed later, in another blog.

Body edit

As it was Timelined at the proposal, by the end of the first month, the usage of the jQuery UI should be removed in the Autocomplete, but fortunately, it was achieved, and more.

"Text with autocomplete" and "Textarea with autocomplete" edit

The two input types are similar to "text" and "textarea", but they also provide autocompletion - on one or multiple values. They used to call the function "attachAutocomplete()" which calls function from jQuery UI. On the other hand, PageForms has other two input types, "Tokens" and "Combobox", and both of them are using the library Select2.js.

To understand the process that took place, we need to know the difference between the for input types. The two input types "Text(area) with autocomplete" can hold single value, or multiple values, both depending on the parameter "|list" in defining the input. "Tokens" is used to hold multiple values, and "Combobox" is used to hold a single value. Thus, both "text with autocomplete" and "textarea with autocomplete" can be converted into stubs for both "Tokens" and "Combobox", this depends on the parameter "|list".

One solution was to create two new JS classes for them, and handle the whole process as it is handled in "Tokens" or "Combobox". But a much better solution, was to convert the php classes into the corresponding php classes.

This is example of the idea

class textWithAutocomplete {
	public static function foo()
	{
		return Tokens::foo();
	}
}

but in this case it will only calls the functions only from "Tokens", so we need to define some kind of variable to determine whether or not it is a list, to call the suitable class and methods. So I defined a static attribute called "$alias" which is determined by the value of the parameter "|list". And then call the suitable method in this way.

public static function foo() {
    return call_user_func( self::alias . "::foo" );
}

The problem is, how to define the attribute "$alias". The suitable answer is defining it in the constructor of the class, but even this has a problem. The constructor is only called when I create a new instance of the class, and most of the functions are static, and the constructor might not be even called. So, an idea came out of the Singleton Design Pattern thinking, to generate the "$alias" in a safe and reliable way. The idea is to define a new function that returns it, if it exists, otherwise, it returns the default value (assumed to be "Combobox") in this way.

protected static function getAlias() {
    if ( isset( self::$alias ) ) {
        return self::$alias;
    } else {
        return 'PFComboBoxInput';
    }
}

And then change the previous block of code, to call "self::getAlias()" instead of "self::$alias".

This approach was applied for the all methods in the class "PFTextWithAutocompleteInput", but what about the "textarea with autocomplete"?! The same exactly thing should be happened there also, so, simply it can inherent from the previous class, and modify only the function "getName()".

In this way, both "Text with autocomplete" and "Textarea with autocomplete" get rid of using jQuery UI.

Patch: Convert the jQuery UI Autocomplete inputs to Aliases for Select2 Ones

#forminput edit

When you create a form and need to get into it, you find an input, where you write the name of the Page that will be created of edited by this form, this input is called " #forminput ". This input can holds only a single value, so it can be converted into a "Combobox". The modification didn't need to take place in php, instead it was happened in JavaScript. Let's see how the autocompletion of the input is called.

if ( $('.pfFormInput').length > 0 ) {
	$('.autocompleteInput').attachAutocomplete();
}

So, it only calls the function "attachAutocomplete()"?! Yes, it does. So, it can simply calls the "Combobox" class, in this way.

if ( $('.pfFormInput').length > 0 ) {
	var combobox = new pf.select2.combobox();
	combobox.apply($('.autocompleteInput'));
}

There is only one change, the "Combobox" layout has an arrow, which may be strange for the user, so, a little change in CSS was made, to hide it.

Patch: Make the #forminput use Select2 for autocomplete

Datepicker and DateTimePicker edit

There are two widgets in OOUI that are aliases for those, "DateInputWidget" and "DateTimeInputWidget", so if we manage to use them, that will be enough. There was a patch that uses the "DateTimeInputWidget" here, the problem with this patch is, it adds a new input type, instead of replace the existing one, which means the jQuery UI will still be used. So the patch is used as reference to enable the OOUI for PageForms, and modify the dependencies in extension.json file and finally get the html text. Previously, the method "getHtmlText()" was manually written and calls the method "genericTextHTML()", but now, we can simply call the class "DateInputWidget" or "DateTimeInputWidget" in OOUI php, in this way

public function getHtmlText() {
	$widget = new DateInputWidget( array(
		'type' => 'date',
		'name' => $this->mInputName,
		'value' => $this->mCurrentValue,
		'id' => 'input_' . $this->mInputNumber,
		'classes' => array( 'ext-pageforms-datetimewidget' ),
		'infusable' => true,
	) );

	return $widget->toString();
}

but this is not enough, because, in this way, the widget cannot be handled in JavaScript, so we need do call the function infuse() in JavaScript like this

oo.ui.infuse( $( '.ext-pageforms-datewidget' ) );

This sounds good, but a new problem was appeared, that there is a difference in the parameter names, and the date format. So, we defined a new method "getConvertedFormat()" to convert the format the user enters, into the format the Widget expects. Also, the parameters names problem was solved be defining a new method "getOptions()" that convert every single parameter in the old DatePicker, into the corresponding parameter in the OOUI Widget, and then merge this array to the array passed to the DateInputWidget class.

Patch: Make the Datetimepicker and Datepicker use OOUI

Conclusion edit

As a conclusion of the first month, half of the project has been finished. The "Text with autocomplete" and "Textarea with autocomplete" inputs types, was converted into stubs (aliases) for the Select2 inputs types "Tokens" and "Combobox" depending on the parameter |list. The #forminput was converted into Combobox and had a small modification in the layout to hide its arrow, because it would be strange for the user. The DatePicker and DateTimePicker was converted into the corresponding Widgets in OOUI, and their parameters and date format was handled.