1<?php
2
3namespace OOUI;
4
5/**
6 * Element with named flags that can be added, removed, listed and checked.
7 *
8 * A flag, when set, adds a CSS class on the `$element` by combining `oo-ui-flaggedElement-` with
9 * the flag name. Flags are primarily useful for styling.
10 *
11 * @abstract
12 */
13trait FlaggedElement {
14	/**
15	 * Flags.
16	 *
17	 * @var bool[]
18	 * @phan-var array<string,bool>
19	 */
20	protected $flags = [];
21
22	/**
23	 * @var Element
24	 */
25	protected $flagged;
26
27	/**
28	 * @param array $config Configuration options
29	 *      - string|string[] $config['flags'] Flags describing importance and functionality, e.g.
30	 *          'primary', 'safe', 'progressive', or 'destructive'.
31	 */
32	public function initializeFlaggedElement( array $config = [] ) {
33		// Properties
34		$this->flagged = $config['flagged'] ?? $this;
35
36		// Initialization
37		$this->setFlags( $config['flags'] ?? null );
38
39		$this->registerConfigCallback( function ( &$config ) {
40			if ( !empty( $this->flags ) ) {
41				$config['flags'] = $this->getFlags();
42			}
43		} );
44	}
45
46	/**
47	 * Check if a flag is set.
48	 *
49	 * @param string $flag Name of flag
50	 * @return bool Has flag
51	 */
52	public function hasFlag( $flag ) {
53		return isset( $this->flags[$flag] );
54	}
55
56	/**
57	 * Get the names of all flags set.
58	 *
59	 * @return string[] Flag names
60	 */
61	public function getFlags() {
62		return array_keys( $this->flags );
63	}
64
65	/**
66	 * Clear all flags.
67	 *
68	 * @return $this
69	 */
70	public function clearFlags() {
71		$remove = [];
72		$classPrefix = 'oo-ui-flaggedElement-';
73
74		foreach ( $this->flags as $flag => $value ) {
75			$remove[] = $classPrefix . $flag;
76		}
77
78		$this->flagged->removeClasses( $remove );
79		$this->flags = [];
80
81		return $this;
82	}
83
84	/**
85	 * Add one or more flags.
86	 *
87	 * @param string|array $flags One or more flags to add, or an array keyed by flag name
88	 *   containing boolean set/remove instructions.
89	 * @return $this
90	 */
91	public function setFlags( $flags ) {
92		$add = [];
93		$remove = [];
94		$classPrefix = 'oo-ui-flaggedElement-';
95
96		if ( is_string( $flags ) ) {
97			// Set
98			if ( !isset( $this->flags[$flags] ) ) {
99				$this->flags[$flags] = true;
100				$add[] = $classPrefix . $flags;
101			}
102		} elseif ( is_array( $flags ) ) {
103			foreach ( $flags as $key => $value ) {
104				if ( is_numeric( $key ) ) {
105					// Set
106					if ( !isset( $this->flags[$value] ) ) {
107						$this->flags[$value] = true;
108						$add[] = $classPrefix . $value;
109					}
110				} else {
111					if ( $value ) {
112						// Set
113						if ( !isset( $this->flags[$key] ) ) {
114							$this->flags[$key] = true;
115							$add[] = $classPrefix . $key;
116						}
117					} else {
118						// Remove
119						if ( isset( $this->flags[$key] ) ) {
120							unset( $this->flags[$key] );
121							$remove[] = $classPrefix . $key;
122						}
123					}
124				}
125			}
126		}
127
128		$this->flagged
129			->addClasses( $add )
130			->removeClasses( $remove );
131
132		return $this;
133	}
134}
135