Cscott has uploaded a new change for review.
https://gerrit.wikimedia.org/r/190367
Change subject: WIP: infusion of PHP widgets with JS
......................................................................
WIP: infusion of PHP widgets with JS
So far this just serializes the PHP state in a form that can be read by JS.
Bug: T74716
Change-Id: Ifaf4e0c0e0a7860709fc47628954fd37cfabf2be
---
M demos/widgets.php
M php/Element.php
M php/Tag.php
M php/Widget.php
M php/elements/ButtonElement.php
M php/elements/FlaggedElement.php
M php/elements/GroupElement.php
M php/elements/IconElement.php
M php/elements/IndicatorElement.php
M php/elements/LabelElement.php
M php/elements/TabIndexedElement.php
M php/elements/TitledElement.php
M php/layouts/FieldLayout.php
M php/layouts/FormLayout.php
M php/layouts/GridLayout.php
M php/layouts/PanelLayout.php
M php/widgets/ButtonInputWidget.php
M php/widgets/ButtonWidget.php
M php/widgets/CheckboxInputWidget.php
M php/widgets/DropdownInputWidget.php
M php/widgets/InputWidget.php
M php/widgets/LabelWidget.php
M php/widgets/RadioInputWidget.php
M php/widgets/TextInputWidget.php
24 files changed, 318 insertions(+), 2 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/oojs/ui refs/changes/67/190367/1
diff --git a/demos/widgets.php b/demos/widgets.php
index 38ca94b..8feab82 100644
--- a/demos/widgets.php
+++ b/demos/widgets.php
@@ -37,6 +37,8 @@
<div class="oo-ui-demo-menu">
<?php
echo new OOUI\ButtonGroupWidget( array(
+ 'infusable' => true,
+ 'id' => 'theme-select',
'items' => array(
new OOUI\ButtonWidget( array(
'label' => 'MediaWiki',
@@ -49,6 +51,7 @@
)
) );
echo new OOUI\ButtonGroupWidget( array(
+ 'infusable' => true,
'items' => array(
new OOUI\ButtonWidget( array(
'label' => 'Vector',
@@ -61,6 +64,7 @@
)
) );
echo new OOUI\ButtonGroupWidget( array(
+ 'infusable' => true,
'items' => array(
new OOUI\ButtonWidget( array(
'label' => 'LTR',
@@ -140,13 +144,14 @@
foreach ( $styles as $style ) {
foreach ( $states as $state ) {
$buttonStyleShowcaseWidget->appendContent(
- new OOUI\ButtonWidget(
array_merge( $style, $state ) )
+ (new OOUI\ButtonWidget(
array_merge( $style, $state ) ) )->setInfusable( true )
);
}
$buttonStyleShowcaseWidget->appendContent( new OOUI\HtmlSnippet( '<br />' ) );
}
echo new OOUI\FieldsetLayout( array(
+ 'infusable' => true,
'label' => 'Simple buttons',
'items' => array(
new OOUI\FieldLayout(
@@ -377,6 +382,7 @@
)
) );
echo new OOUI\FieldsetLayout( array(
+ 'infusable' => true,
'label' => 'Button sets',
'items' => array(
new OOUI\FieldLayout(
@@ -427,6 +433,7 @@
)
) );
echo new OOUI\FieldsetLayout( array(
+ #'infusable' => true, # not infusable
'label' => 'Button style showcase',
'items' => array(
new OOUI\FieldLayout(
@@ -438,6 +445,7 @@
)
) );
echo new OOUI\FieldsetLayout( array(
+ 'infusable' => true,
'label' => 'Form widgets',
'items' => array(
new OOUI\FieldLayout(
@@ -585,6 +593,7 @@
)
) );
echo new OOUI\FieldsetLayout( array(
+ 'infusable' => true,
'label' => 'Other widgets',
'items' => array(
new OOUI\FieldLayout(
@@ -651,6 +660,7 @@
)
) );
echo new OOUI\FieldsetLayout( array(
+ 'infusable' => true,
'label' => 'Field layouts',
'help' => 'I am an additional, helpful
information. Lorem ipsum dolor sit amet, cibo pri ' .
"in, duo ex inimicus perpetua
complectitur, mel periculis similique at.\xE2\x80\x8E",
@@ -670,6 +680,7 @@
) );
$form = new OOUI\FormLayout( array(
+ 'infusable' => true,
'method' => 'GET',
'action' => 'widgets.php',
) );
@@ -727,6 +738,7 @@
echo $form;
echo new OOUI\FieldsetLayout( array(
+ 'infusable' => true,
'label' => 'PHP-specific',
'items' => array(
new OOUI\FieldLayout(
diff --git a/php/Element.php b/php/Element.php
index 35ab53a..d41b8fc 100644
--- a/php/Element.php
+++ b/php/Element.php
@@ -52,6 +52,9 @@
parent::__construct( $this->getTagName() );
// Initialization
+ if ( isset( $config['infusable'] ) && is_bool(
$config['infusable'] ) ) {
+ $this->setInfusable( $config['infusable'] );
+ }
if ( isset( $config['classes'] ) && is_array(
$config['classes'] ) ) {
$this->addClasses( $config['classes'] );
}
@@ -160,6 +163,16 @@
$this->mixins[] = $mixin;
}
+ public function serialize( $array ) {
+ foreach ( $this->mixins as $mixin ) {
+ if ( method_exists( $mixin, 'serialize' ) ) {
+ $array = $mixin->serialize( $array );
+ }
+ }
+ $array['_'] = preg_replace( '/^OOUI\\\\/', '', get_class( $this
) );
+ return $array;
+ }
+
/**
* Render element into HTML.
*
@@ -167,6 +180,9 @@
*/
public function toString() {
Theme::singleton()->updateElementClasses( $this );
+ if ( $this->getInfusable() ) {
+ $this->ensureInfusableId();
+ }
return parent::toString();
}
diff --git a/php/Tag.php b/php/Tag.php
index 6b8e578..83ec77a 100644
--- a/php/Tag.php
+++ b/php/Tag.php
@@ -41,6 +41,13 @@
*/
protected $elementGroup = null;
+ /**
+ * Infusion support.
+ *
+ * @var boolean Whether to serialize tag/element/widget state for
client-side use.
+ */
+ protected $infusable = false;
+
/* Methods */
/**
@@ -218,6 +225,60 @@
}
/**
+ * Enable widget for client-side infusion.
+ *
+ * @param boolean $infusable True to allow tag/element/widget to be
used client-side.
+ * @chainable
+ */
+ public function setInfusable( $infusable ) {
+ $this->infusable = $infusable;
+ return $this;
+ }
+
+ /**
+ * Get client-side infusability.
+ *
+ * @return boolean If this tag/element/widget can be used client-side.
+ */
+ public function getInfusable() {
+ return $this->infusable;
+ }
+
+ private static $id_cnt = 0;
+ /**
+ * Ensure that this given Tag is infusable and has a unique `id`
+ * attribute.
+ * @chainable
+ */
+ public function ensureInfusableId() {
+ $this->setInfusable(true);
+ if ( $this->getAttribute( 'id' ) == null ) {
+ $this->setAttributes( array( 'id' => "ooui-" . (
self::$id_cnt++ ) ) );
+ }
+ return $this;
+ }
+
+ public function serialize( $array ) {
+ return $array;
+ }
+ // not used for most widgets, which manage their own contents
+ public function serializeContent( $array ) {
+ $c = array();
+ foreach ( $this->content as $part ) {
+ if ( is_string( $part ) ) {
+ $c[] = $part;
+ } elseif ( $part instanceof Tag ) {
+ $part->ensureInfusableId();
+ $c[] = array( 'tag' => $part->getAttribute(
'id' ) );
+ } elseif ( $part instanceof HtmlSnippet ) {
+ $c[] = array( 'html' => (string)$part );
+ }
+ }
+ $array['content'] = $c;
+ return $array;
+ }
+
+ /**
* Render element into HTML.
*
* @return string HTML serialization
@@ -227,6 +288,14 @@
$attributesArray = $this->attributes;
if ( $this->classes ) {
$attributesArray['class'] = implode( ' ', array_unique(
$this->classes ) );
+ }
+
+ // Infusion support.
+ if ( $this->infusable ) {
+ $serialized = $this->serialize( array() );
+ if ( $serialized != null ) {
+ $attributesArray['data-ooui'] = json_encode(
$serialized );
+ }
}
$attributes = '';
@@ -263,7 +332,8 @@
}
}
- $attributes .= ' ' . $key . '="' . htmlspecialchars(
$value ) . '"';
+ $value = str_replace( '"', '"', htmlspecialchars(
$value, ENT_QUOTES ) );
+ $attributes .= ' ' . $key . "='" . $value . "'";
}
// Content
diff --git a/php/Widget.php b/php/Widget.php
index 365dc50..90a5abc 100644
--- a/php/Widget.php
+++ b/php/Widget.php
@@ -23,6 +23,7 @@
/**
* @param array $config Configuration options
* @param boolean $config['disabled'] Disable (default: false)
+ * @param string $config['id'] HTML id attribute for this widget
*/
public function __construct( array $config = array() ) {
// Initialize config
@@ -34,6 +35,9 @@
// Initialization
$this->addClasses( array( 'oo-ui-widget' ) );
$this->setDisabled( $config['disabled'] );
+ if ( isset( $config['id'] ) ) {
+ $this->setAttributes( array( 'id' => $config['id'] ) );
+ }
}
/**
@@ -60,4 +64,11 @@
return $this;
}
+
+ public function serialize( $array ) {
+ if ( $this->disabled ) {
+ $array['disabled'] = $this->disabled;
+ }
+ return parent::serialize( $array );
+ }
}
diff --git a/php/elements/ButtonElement.php b/php/elements/ButtonElement.php
index 57b2f57..2ba73fc 100644
--- a/php/elements/ButtonElement.php
+++ b/php/elements/ButtonElement.php
@@ -89,4 +89,14 @@
return $this;
}
+
+ public function serialize( $array ) {
+ if ( $this->framed != true ) {
+ $array['framed'] = $this->framed;
+ }
+ if ( $this->accessKey != null ) {
+ $array['accessKey'] = $this->accessKey;
+ }
+ return $array;
+ }
}
diff --git a/php/elements/FlaggedElement.php b/php/elements/FlaggedElement.php
index 9d21c83..651a2e6 100644
--- a/php/elements/FlaggedElement.php
+++ b/php/elements/FlaggedElement.php
@@ -123,4 +123,11 @@
return $this;
}
+
+ public function serialize( $array ) {
+ if ( !empty( $this->flags ) ) {
+ $array['flags'] = $this->getFlags();
+ }
+ return $array;
+ }
}
diff --git a/php/elements/GroupElement.php b/php/elements/GroupElement.php
index f720a84..2481395 100644
--- a/php/elements/GroupElement.php
+++ b/php/elements/GroupElement.php
@@ -121,4 +121,14 @@
return $this;
}
+
+ public function serialize( $array ) {
+ $itemIds = array();
+ foreach ( $this->items as $item ) {
+ $item->ensureInfusableId();
+ $itemIds[] = $item->getAttribute( 'id' );
+ }
+ $array['items'] = $itemIds;
+ return $array;
+ }
}
diff --git a/php/elements/IconElement.php b/php/elements/IconElement.php
index e0b280f..9874699 100644
--- a/php/elements/IconElement.php
+++ b/php/elements/IconElement.php
@@ -66,4 +66,11 @@
public function getIcon() {
return $this->icon;
}
+
+ public function serialize( $array ) {
+ if ( $this->icon != null ) {
+ $array['icon'] = $this->icon;
+ }
+ return $array;
+ }
}
diff --git a/php/elements/IndicatorElement.php
b/php/elements/IndicatorElement.php
index 73bda35..ecf4ae8 100644
--- a/php/elements/IndicatorElement.php
+++ b/php/elements/IndicatorElement.php
@@ -68,4 +68,11 @@
public function getIndicator() {
return $this->indicator;
}
+
+ public function serialize( $array ) {
+ if ( $this->indicator != null ) {
+ $array['indicator'] = $this->indicator;
+ }
+ return $array;
+ }
}
diff --git a/php/elements/LabelElement.php b/php/elements/LabelElement.php
index 90913b4..262afe0 100644
--- a/php/elements/LabelElement.php
+++ b/php/elements/LabelElement.php
@@ -67,4 +67,18 @@
public function getLabel() {
return $this->label;
}
+
+ public function serialize( $array ) {
+ if ( $this->label != null ) {
+ if ( is_string( $this->label ) ) {
+ $array['label'] = $this->label;
+ } else if ( $this->label instanceof Tag ) {
+ $this->label->ensureInfusableId();
+ $array['label'] = array( 'tag' =>
$this->label->getAttribute( 'id' ) );
+ } else if ( $this->label instanceof HtmlSnippet ) {
+ $array['label'] = array( 'html' =>
(string)$this->label );
+ }
+ }
+ return $array;
+ }
}
diff --git a/php/elements/TabIndexedElement.php
b/php/elements/TabIndexedElement.php
index 9a75bae..3c626ad 100644
--- a/php/elements/TabIndexedElement.php
+++ b/php/elements/TabIndexedElement.php
@@ -78,4 +78,11 @@
public function getTabIndex() {
return $this->tabIndex;
}
+
+ public function serialize( $array ) {
+ if ( $this->tabIndex !== 0 ) {
+ $array['tabIndex'] = $this->tabIndex;
+ }
+ return $array;
+ }
}
diff --git a/php/elements/TitledElement.php b/php/elements/TitledElement.php
index 0f21932..40f36c4 100644
--- a/php/elements/TitledElement.php
+++ b/php/elements/TitledElement.php
@@ -63,4 +63,11 @@
public function getTitle() {
return $this->title;
}
+
+ public function serialize( $array ) {
+ if ( $this->title != null ) {
+ $array['title'] = $this->title;
+ }
+ return $array;
+ }
}
diff --git a/php/layouts/FieldLayout.php b/php/layouts/FieldLayout.php
index 3e73fd6..a1545d0 100644
--- a/php/layouts/FieldLayout.php
+++ b/php/layouts/FieldLayout.php
@@ -124,4 +124,14 @@
return $this;
}
+
+ public function serialize( $array ) {
+ $this->fieldWidget->ensureInfusableId();
+ $array['fieldWidget'] = $this->fieldWidget->getAttribute( 'id'
);
+ $array['align'] = $this->align;
+ if ( $this->help != '' ) {
+ $array['help'] = $this->help->getTitle();
+ }
+ return parent::serialize( $array );
+ }
}
diff --git a/php/layouts/FormLayout.php b/php/layouts/FormLayout.php
index 5270a9b..564fdb0 100644
--- a/php/layouts/FormLayout.php
+++ b/php/layouts/FormLayout.php
@@ -27,4 +27,15 @@
->addClasses( array( 'oo-ui-formLayout' ) )
->setAttributes( array_intersect_key( $config,
array_flip( $attributeWhitelist ) ) );
}
+
+ public function serialize( $array ) {
+ foreach ( array( 'method', 'action', 'enctype' ) as $attr ) {
+ $value = $this->getAttribute( $attr );
+ if ( $value != null ) {
+ $array[$attr] = $value;
+ }
+ }
+ $array = $this->serializeContent( $array );
+ return parent::serialize( $array );
+ }
}
diff --git a/php/layouts/GridLayout.php b/php/layouts/GridLayout.php
index 0730766..8af60af 100644
--- a/php/layouts/GridLayout.php
+++ b/php/layouts/GridLayout.php
@@ -142,4 +142,16 @@
public function getPanel( $x, $y ) {
return $this->panels[ ( $x * count( $this->widths ) ) + $y ];
}
+
+ public function serialize( $array ) {
+ $p = array();
+ foreach ( $this->panels as $panel ) {
+ $panel->ensureInfusableId();
+ $p[] = $panel->getAttribute( 'id' );
+ }
+ $array['panels'] = $p;
+ $array['widths'] = $this->widths;
+ $array['heights'] = $this->heights;
+ return parent::serialize( $array );
+ }
}
diff --git a/php/layouts/PanelLayout.php b/php/layouts/PanelLayout.php
index 4c022b7..3468f16 100644
--- a/php/layouts/PanelLayout.php
+++ b/php/layouts/PanelLayout.php
@@ -36,4 +36,17 @@
$this->addClasses( array( 'oo-ui-panelLayout-expanded'
) );
}
}
+ public function serialize( $array ) {
+ if ( $this->hasClass( 'oo-ui-panelLayout-scrollable' ) ) {
+ $array['scrollable'] = true;
+ }
+ if ( $this->hasClass( 'oo-ui-panelLayout-padded' ) ) {
+ $array['padded'] = true;
+ }
+ if ( $this->hasClass( 'oo-ui-panelLayout-expanded' ) ) {
+ $array['expanded'] = true;
+ }
+ $array = $this->serializeContent( $array );
+ return parent::serialize( $array );
+ }
}
diff --git a/php/widgets/ButtonInputWidget.php
b/php/widgets/ButtonInputWidget.php
index 9f319c6..b909d07 100644
--- a/php/widgets/ButtonInputWidget.php
+++ b/php/widgets/ButtonInputWidget.php
@@ -106,4 +106,12 @@
}
return $this;
}
+
+ public function serialize( $array ) {
+ if ( $this->useInputTag ) {
+ $array['useInputTag'] = true;
+ }
+ $array['type'] = $this->input->getAttribute( 'type' );
+ return parent::serialize( $array );
+ }
}
diff --git a/php/widgets/ButtonWidget.php b/php/widgets/ButtonWidget.php
index b387eb4..a95b235 100644
--- a/php/widgets/ButtonWidget.php
+++ b/php/widgets/ButtonWidget.php
@@ -139,4 +139,17 @@
return $this;
}
+
+ public function serialize( $array ) {
+ if ( $this->href != null ) {
+ $array['href'] = $this->href;
+ }
+ if ( $this->target != null ) {
+ $array['target'] = $this->target;
+ }
+ if ( $this->nofollow != true ) {
+ $array['nofollow'] = $this->nofollow;
+ }
+ return parent::serialize( $array );
+ }
}
diff --git a/php/widgets/CheckboxInputWidget.php
b/php/widgets/CheckboxInputWidget.php
index d6e7790..07ecb64 100644
--- a/php/widgets/CheckboxInputWidget.php
+++ b/php/widgets/CheckboxInputWidget.php
@@ -60,4 +60,11 @@
public function isSelected() {
return $this->selected;
}
+
+ public function serialize( $array ) {
+ if ( $this->selected ) {
+ $array['selected'] = $this->selected;
+ }
+ return parent::serialize( $array );
+ }
}
diff --git a/php/widgets/DropdownInputWidget.php
b/php/widgets/DropdownInputWidget.php
index 042f1c7..2dfc87a 100644
--- a/php/widgets/DropdownInputWidget.php
+++ b/php/widgets/DropdownInputWidget.php
@@ -85,4 +85,15 @@
return $this;
}
+
+ public function serialize( $array ) {
+ $o = array();
+ foreach ( $this->options as $option ) {
+ $a = $option->serializeContent( array() );
+ $v = $option->getAttribute( 'value' );
+ $o[] = array( 'data' => $v, 'label' => $a['content'] );
+ }
+ $array['options'] = $o;
+ return parent::serialize( $array );
+ }
}
diff --git a/php/widgets/InputWidget.php b/php/widgets/InputWidget.php
index fa1ecbb..b8514b5 100644
--- a/php/widgets/InputWidget.php
+++ b/php/widgets/InputWidget.php
@@ -130,4 +130,15 @@
}
return $this;
}
+
+ public function serialize( $array ) {
+ $name = $this->input->getAttribute( 'name' );
+ if ( $name != null ) {
+ $array['name'] = $name;
+ }
+ if ( $this->value != '' ) {
+ $array['value'] = $this->value;
+ }
+ return parent::serialize( $array );
+ }
}
diff --git a/php/widgets/LabelWidget.php b/php/widgets/LabelWidget.php
index 65e3a3c..6eeeb33 100644
--- a/php/widgets/LabelWidget.php
+++ b/php/widgets/LabelWidget.php
@@ -38,4 +38,12 @@
// Initialization
$this->addClasses( array( 'oo-ui-labelWidget' ) );
}
+
+ public function serialize( $array ) {
+ if ( $this->input != null ) {
+ $this->input->ensureInfusableId();
+ $array['input'] = $this->input->getAttribute( 'id' );
+ }
+ return parent::serialize( $array );
+ }
}
diff --git a/php/widgets/RadioInputWidget.php b/php/widgets/RadioInputWidget.php
index 9c35aac..b44d383 100644
--- a/php/widgets/RadioInputWidget.php
+++ b/php/widgets/RadioInputWidget.php
@@ -50,4 +50,11 @@
public function isSelected() {
return $this->input->getAttribute( 'checked' ) === 'checked';
}
+
+ public function serialize( $array ) {
+ if ( $this->isSelected() ) {
+ $array['selected'] = true;
+ }
+ return parent::serialize( $array );
+ }
}
diff --git a/php/widgets/TextInputWidget.php b/php/widgets/TextInputWidget.php
index 57a9c6a..5e84277 100644
--- a/php/widgets/TextInputWidget.php
+++ b/php/widgets/TextInputWidget.php
@@ -115,4 +115,31 @@
public function isMultiline() {
return (bool)$this->multiline;
}
+
+ public function serialize( $array ) {
+ if ( $this->isMultiline() ) {
+ $array['multiline'] = true;
+ } else {
+ $type = $this->input->getAttribute( 'type' );
+ if ( $type != 'text' ) {
+ $array['type'] = $type;
+ }
+ }
+ if ( $this->isReadOnly() ) {
+ $array['readOnly'] = true;
+ }
+ $placeholder = $this->input->getAttribute( 'placeholder' );
+ if ( $placeholder != null ) {
+ $array['placeholder'] = $placeholder;
+ }
+ $maxlength = $this->input->getAttribute( 'maxlength' );
+ if ( $maxlength != null ) {
+ $array['maxLength'] = $maxlength;
+ }
+ $autofocus = $this->input->getAttribute( 'autofocus' );
+ if ( $autofocus != null ) {
+ $array['autofocus'] = true;
+ }
+ return parent::serialize( $array );
+ }
}
--
To view, visit https://gerrit.wikimedia.org/r/190367
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ifaf4e0c0e0a7860709fc47628954fd37cfabf2be
Gerrit-PatchSet: 1
Gerrit-Project: oojs/ui
Gerrit-Branch: master
Gerrit-Owner: Cscott <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits