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( '&quot;', '"', 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

Reply via email to