Admin Menu Editor - Version 1.6

Version Description

  • Improved PHP 7 support.
  • Added a few more menu icons.
  • Added tabs to the settings page: "Admin Menu" and "Settings". These tabs replace the heading buttons that were previously used to switch between the menu editor and general plugin settings.
  • Added basic support for the special "customize" and "delete_site" meta capabilities.
  • Fixed a bug that prevented menu items with an empty slug (i.e. no URL) from showing up.
  • Fixed a bug where collapsing menu properties would flag the "Icon URL" field as having a custom value even if you hadn't actually changed it.
  • Fixed a rare WPML conflict that sometimes caused the admin menu to use a mix of different languages.
  • Improved compatibility with buggy plugins and themes that throw JavaScript errors in their DOM-ready handlers.
  • Renamed jquery.cookie.js to jquery.biscuit.js as a workaround for servers with overly aggressive ModSecurity configuration. Apparently, some servers block access to any URL that contains the text ".cookie".
  • Added a compatibility workaround for the DW Question & Answer plugin. The hidden "Welcome", "Changelog" and "Credits" menu items should no longer show up when you activate AME.
  • Added locking to reduce the risk of triggering a race condition when saving menu settings.
  • Removed the non-functional "Embed WP page" option.
  • Tested up to WordPress 4.5-RC1.
Download this release

Release Info

Developer whiteshadow
Plugin Icon 128x128 Admin Menu Editor
Version 1.6
Comparing to
See all releases

Code changes from version 1.5 to 1.6

Files changed (56) hide show
  1. css/menu-editor.css +18 -4
  2. css/menu-editor.scss +24 -5
  3. includes/PHP-CSS-Parser/CHANGELOG.md +49 -1
  4. includes/PHP-CSS-Parser/README.md +36 -23
  5. includes/PHP-CSS-Parser/lib/Sabberworm/CSS/CSSList/AtRuleBlockList.php +15 -3
  6. includes/PHP-CSS-Parser/lib/Sabberworm/CSS/CSSList/CSSBlockList.php +1 -1
  7. includes/PHP-CSS-Parser/lib/Sabberworm/CSS/CSSList/CSSList.php +40 -1
  8. includes/PHP-CSS-Parser/lib/Sabberworm/CSS/CSSList/Document.php +80 -69
  9. includes/PHP-CSS-Parser/lib/Sabberworm/CSS/CSSList/KeyFrame.php +56 -48
  10. includes/PHP-CSS-Parser/lib/Sabberworm/CSS/OutputFormat.php +289 -0
  11. includes/PHP-CSS-Parser/lib/Sabberworm/CSS/Parser.php +16 -12
  12. includes/PHP-CSS-Parser/lib/Sabberworm/CSS/Parsing/OutputException.php +9 -0
  13. includes/PHP-CSS-Parser/lib/Sabberworm/CSS/Property/AtRule.php +3 -2
  14. includes/PHP-CSS-Parser/lib/Sabberworm/CSS/Property/CSSNamespace.php +5 -1
  15. includes/PHP-CSS-Parser/lib/Sabberworm/CSS/Property/Charset.php +5 -1
  16. includes/PHP-CSS-Parser/lib/Sabberworm/CSS/Property/Import.php +5 -1
  17. includes/PHP-CSS-Parser/lib/Sabberworm/CSS/Property/Selector.php +29 -30
  18. includes/PHP-CSS-Parser/lib/Sabberworm/CSS/Renderable.php +8 -0
  19. includes/PHP-CSS-Parser/lib/Sabberworm/CSS/Rule/Rule.php +6 -2
  20. includes/PHP-CSS-Parser/lib/Sabberworm/CSS/RuleSet/AtRuleSet.php +11 -3
  21. includes/PHP-CSS-Parser/lib/Sabberworm/CSS/RuleSet/DeclarationBlock.php +26 -3
  22. includes/PHP-CSS-Parser/lib/Sabberworm/CSS/RuleSet/RuleSet.php +27 -3
  23. includes/PHP-CSS-Parser/lib/Sabberworm/CSS/Value/CSSFunction.php +5 -1
  24. includes/PHP-CSS-Parser/lib/Sabberworm/CSS/Value/{String.php → CSSString.php} +6 -2
  25. includes/PHP-CSS-Parser/lib/Sabberworm/CSS/Value/Color.php +9 -6
  26. includes/PHP-CSS-Parser/lib/Sabberworm/CSS/Value/Size.php +5 -1
  27. includes/PHP-CSS-Parser/lib/Sabberworm/CSS/Value/URL.php +7 -3
  28. includes/PHP-CSS-Parser/lib/Sabberworm/CSS/Value/Value.php +5 -2
  29. includes/PHP-CSS-Parser/lib/Sabberworm/CSS/Value/ValueList.php +6 -2
  30. includes/ameArray.php +11 -0
  31. includes/editor-page.php +36 -29
  32. includes/generate-menu-dashicons.php +1 -1
  33. includes/menu-editor-core.php +189 -76
  34. includes/menu-item.php +25 -13
  35. includes/menu.php +1 -1
  36. includes/reflection-callable.php +62 -0
  37. includes/settings-page.php +4 -4
  38. includes/shadow_plugin_framework.php +30 -13
  39. js/actor-manager.js +331 -0
  40. js/actor-manager.ts +425 -0
  41. js/admin-helpers.js +9 -0
  42. js/common.d.ts +3 -0
  43. js/jquery-json.d.ts +4 -0
  44. js/{jquery.cookie.js → jquery.biscuit.js} +0 -0
  45. js/jquery.d.ts +3203 -0
  46. js/jquery.json.js +196 -152
  47. js/knockout.d.ts +631 -0
  48. js/knockout.js +123 -0
  49. js/lodash-3.10.d.ts +15041 -0
  50. js/menu-editor.js +258 -539
  51. menu-editor.php +5 -1
  52. modules/actor-selector/actor-selector-template.php +6 -0
  53. modules/actor-selector/actor-selector.js +196 -0
  54. modules/actor-selector/actor-selector.php +61 -0
  55. modules/actor-selector/actor-selector.ts +260 -0
  56. readme.txt +17 -2
css/menu-editor.css CHANGED
@@ -1,6 +1,11 @@
1
/* Admin Menu Editor CSS file */
2
#ws_menu_editor {
3
min-width: 780px; }
4
5
.ws_main_container {
6
margin: 2px;
@@ -117,12 +122,21 @@
117
#ws_menu_editor #ws_save_menu {
118
margin-bottom: 20px; }
119
120
- #ws_menu_editor #ws_export_menu {
121
- margin-top: 12px; }
122
-
123
#ws_menu_editor #ws_toggle_editor_layout {
124
display: none; }
125
126
/*
127
* Menu components and widgets
128
*/
@@ -511,7 +525,7 @@ select.ws_dropdown optgroup option {
511
position: absolute; }
512
513
#ws_icon_selector.ws_with_more_icons {
514
- width: 504px; }
515
516
#ws_icon_selector .ws_icon_extra {
517
display: none; }
1
/* Admin Menu Editor CSS file */
2
#ws_menu_editor {
3
min-width: 780px; }
4
+ #ws_menu_editor #ws_actor_selector {
5
+ margin-top: 6px; }
6
+
7
+ .ame-is-free-version #ws_menu_editor {
8
+ margin-top: 9px; }
9
10
.ws_main_container {
11
margin: 2px;
122
#ws_menu_editor #ws_save_menu {
123
margin-bottom: 20px; }
124
125
#ws_menu_editor #ws_toggle_editor_layout {
126
display: none; }
127
128
+ #ws_menu_editor .ws_sidebar_button_separator {
129
+ display: block;
130
+ height: 4px;
131
+ margin: 0;
132
+ padding: 0; }
133
+
134
+ /*
135
+ * Page heading and tabs
136
+ */
137
+ #ws_ame_editor_heading {
138
+ float: left; }
139
+
140
/*
141
* Menu components and widgets
142
*/
525
position: absolute; }
526
527
#ws_icon_selector.ws_with_more_icons {
528
+ width: 540px; }
529
530
#ws_icon_selector .ws_icon_extra {
531
display: none; }
css/menu-editor.scss CHANGED
@@ -2,6 +2,14 @@
2
3
#ws_menu_editor {
4
min-width: 780px;
5
}
6
7
.ws_main_container {
@@ -172,14 +180,25 @@
172
margin-bottom: 20px;
173
}
174
175
- #ws_menu_editor #ws_export_menu {
176
- margin-top: 12px;
177
- }
178
-
179
#ws_menu_editor #ws_toggle_editor_layout {
180
display: none;
181
}
182
183
/*
184
* Menu components and widgets
185
*/
@@ -694,7 +713,7 @@ select.ws_dropdown optgroup option {
694
}
695
696
#ws_icon_selector.ws_with_more_icons {
697
- width: 504px;
698
}
699
700
#ws_icon_selector .ws_icon_extra {
2
3
#ws_menu_editor {
4
min-width: 780px;
5
+
6
+ #ws_actor_selector {
7
+ margin-top: 6px;
8
+ }
9
+ }
10
+
11
+ .ame-is-free-version #ws_menu_editor {
12
+ margin-top: 9px;
13
}
14
15
.ws_main_container {
180
margin-bottom: 20px;
181
}
182
183
#ws_menu_editor #ws_toggle_editor_layout {
184
display: none;
185
}
186
187
+ #ws_menu_editor .ws_sidebar_button_separator {
188
+ display: block;
189
+ height: 4px;
190
+ margin: 0;
191
+ padding: 0;
192
+ }
193
+
194
+ /*
195
+ * Page heading and tabs
196
+ */
197
+
198
+ #ws_ame_editor_heading {
199
+ float: left;
200
+ }
201
+
202
/*
203
* Menu components and widgets
204
*/
713
}
714
715
#ws_icon_selector.ws_with_more_icons {
716
+ width: 540px;
717
}
718
719
#ws_icon_selector .ws_icon_extra {
includes/PHP-CSS-Parser/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
# Revision History
2
3
## 5.0
4
5
### 5.0.0 (2013-03-20)
@@ -74,6 +105,23 @@
74
* *No backwards-incompatible changes*
75
* *No deprecations*
76
77
## 4.0
78
79
### 4.0.0 (2013-03-19)
@@ -118,4 +166,4 @@ Initial release of a stable public API.
118
119
## 0.9
120
121
- Last version not to use PSR-0 project organization semantics.
1
# Revision History
2
3
+ ## 7.0
4
+
5
+ ### 7.0.0 (2015-08-24)
6
+
7
+ * Compatibility with PHP 7. Well timed, eh?
8
+
9
+ #### Deprecations
10
+
11
+ * The `Sabberworm\CSS\Value\String` class has been renamed to `Sabberworm\CSS\Value\CSSString`.
12
+
13
+ ### 7.0.1 (2015-12-25)
14
+
15
+ * No more suppressed `E_NOTICE`
16
+ * *No deprecations*
17
+
18
+ ## 6.0
19
+
20
+ ### 6.0.0 (2014-07-03)
21
+
22
+ * Format output using Sabberworm\CSS\OutputFormat
23
+ * *No backwards-incompatible changes*
24
+
25
+ #### Deprecations
26
+
27
+ * The parse() method replaces __toString with an optional argument (instance of the OutputFormat class)
28
+
29
+ ### 6.0.1 (2015-08-24)
30
+
31
+ * Remove some declarations in interfaces incompatible with PHP 5.3 (< 5.3.9)
32
+ * *No deprecations*
33
+
34
## 5.0
35
36
### 5.0.0 (2013-03-20)
105
* *No backwards-incompatible changes*
106
* *No deprecations*
107
108
+ ### 5.1.2 (2013-10-30)
109
+
110
+ * Remove the use of consumeUntil in comment parsing. This makes it possible to parse comments such as “/** Perfectly valid **/”
111
+ * *No backwards-incompatible changes*
112
+ * *No deprecations*
113
+
114
+ ### 5.2.0 (2014-06-30)
115
+
116
+ * Support removing a selector from a declaration block using `$oBlock->removeSelector($mSelector)`
117
+ * Introduce a specialized exception (Sabberworm\CSS\Parsing\OuputException) for exceptions during output rendering
118
+
119
+ * *No deprecations*
120
+
121
+ #### Backwards-incompatible changes
122
+
123
+ * Outputting a declaration block that has no selectors throws an OuputException instead of outputting an invalid ` {…}` into the CSS document.
124
+
125
## 4.0
126
127
### 4.0.0 (2013-03-19)
166
167
## 0.9
168
169
+ Last version not to use PSR-0 project organization semantics.
includes/PHP-CSS-Parser/README.md CHANGED
@@ -1,6 +1,8 @@
1
PHP CSS Parser
2
--------------
3
4
A Parser for CSS Files written in PHP. Allows extraction of CSS files into a data structure, manipulation of said structure and output as (optimized) CSS.
5
6
## Usage
@@ -61,6 +63,10 @@ The resulting data structure consists mainly of five basic types: `CSSList`, `Ru
61
* `Document` – representing the root of a CSS file.
62
* `MediaQuery` – represents a subsection of a CSSList that only applies to a output device matching the contained media query.
63
64
#### RuleSet
65
66
`RuleSet` is a container for individual rules. The most common form of a rule set is one constrained by a selector. The following concrete subtypes exist:
@@ -70,17 +76,19 @@ The resulting data structure consists mainly of five basic types: `CSSList`, `Ru
70
71
Note: A `CSSList` can contain other `CSSList`s (and `Import`s as well as a `Charset`) while a `RuleSet` can only contain `Rule`s.
72
73
#### Rule
74
75
`Rule`s just have a key (the rule) and a value. These values are all instances of a `Value`.
76
77
#### Value
78
79
- `Value` is an abstract class that only defines the `__toString` method. The concrete subclasses for atomic value types are:
80
81
* `Size` – consists of a numeric `size` value and a unit.
82
* `Color` – colors can be input in the form #rrggbb, #rgb or schema(val1, val2, …) but are always stored as an array of ('s' => val1, 'c' => val2, 'h' => val3, …) and output in the second form.
83
- * `String` – this is just a wrapper for quoted strings to distinguish them from keywords; always output with double quotes.
84
* `URL` – URLs in CSS; always output in URL("") notation.
85
86
There is another abstract subclass of `Value`, `ValueList`. A `ValueList` represents a lists of `Value`s, separated by some separation character (mostly `,`, whitespace, or `/`). There are two types of `ValueList`s:
@@ -88,12 +96,6 @@ There is another abstract subclass of `Value`, `ValueList`. A `ValueList` repres
88
* `RuleValueList` – The default type, used to represent all multi-valued rules like `font: bold 12px/3 Helvetica, Verdana, sans-serif;` (where the value would be a whitespace-separated list of the primitive value `bold`, a slash-separated list and a comma-separated list).
89
* `CSSFunction` – A special kind of value that also contains a function name and where the values are the function’s arguments. Also handles equals-sign-separated argument lists like `filter: alpha(opacity=90);`.
90
91
- To access the items stored in a `CSSList` – like the document you got back when calling `$oCssParser->parse()` –, use `getContents()`, then iterate over that collection and use instanceof to check whether you’re dealing with another `CSSList`, a `RuleSet`, a `Import` or a `Charset`.
92
-
93
- To append a new item (selector, media query, etc.) to an existing `CSSList`, construct it using the constructor for this class and use the `append($oItem)` method.
94
-
95
- If you want to manipulate a `RuleSet`, use the methods `addRule(Rule $oRule)`, `getRules()` and `removeRule($mRule)` (which accepts either a Rule instance or a rule name; optionally suffixed by a dash to remove all related rules).
96
-
97
#### Convenience methods
98
99
There are a few convenience methods on Document to ease finding, manipulating and deleting rules:
@@ -104,8 +106,7 @@ There are a few convenience methods on Document to ease finding, manipulating an
104
105
## To-Do
106
107
- * More convenience methods [like `selectorsWithElement($sId/Class/TagName)`, `removeSelector($oSelector)`, `attributesOfType($sType)`, `removeAttributesOfType($sType)`]
108
- * Options for output (compact, verbose, etc.)
109
* Real multibyte support. Currently only multibyte charsets whose first 255 code points take up only one byte and are identical with ASCII are supported (yes, UTF-8 fits this description).
110
* Named color support (using `Color` instead of an anonymous string literal)
111
@@ -144,11 +145,23 @@ There are a few convenience methods on Document to ease finding, manipulating an
144
145
### Output
146
147
- To output the entire CSS document into a variable, just use `->__toString()`:
148
149
$oCssParser = new Sabberworm\CSS\Parser(file_get_contents('somefile.css'));
150
$oCssDocument = $oCssParser->parse();
151
- print $oCssDocument->__toString();
152
153
## Examples
154
@@ -180,8 +193,8 @@ To output the entire CSS document into a variable, just use `->__toString()`:
180
[0]=>
181
object(Sabberworm\CSS\Property\Charset)#6 (1) {
182
["sCharset":"Sabberworm\CSS\Property\Charset":private]=>
183
- object(Sabberworm\CSS\Value\String)#5 (1) {
184
- ["sString":"Sabberworm\CSS\Value\String":private]=>
185
string(5) "utf-8"
186
}
187
}
@@ -198,8 +211,8 @@ To output the entire CSS document into a variable, just use `->__toString()`:
198
["sRule":"Sabberworm\CSS\Rule\Rule":private]=>
199
string(11) "font-family"
200
["mValue":"Sabberworm\CSS\Rule\Rule":private]=>
201
- object(Sabberworm\CSS\Value\String)#9 (1) {
202
- ["sString":"Sabberworm\CSS\Value\String":private]=>
203
string(10) "CrassRoots"
204
}
205
["bIsImportant":"Sabberworm\CSS\Rule\Rule":private]=>
@@ -215,8 +228,8 @@ To output the entire CSS document into a variable, just use `->__toString()`:
215
["mValue":"Sabberworm\CSS\Rule\Rule":private]=>
216
object(Sabberworm\CSS\Value\URL)#11 (1) {
217
["oURL":"Sabberworm\CSS\Value\URL":private]=>
218
- object(Sabberworm\CSS\Value\String)#12 (1) {
219
- ["sString":"Sabberworm\CSS\Value\String":private]=>
220
string(15) "../media/cr.ttf"
221
}
222
}
@@ -351,7 +364,7 @@ To output the entire CSS document into a variable, just use `->__toString()`:
351
}
352
}
353
354
- #### Output (`__toString()`)
355
356
@charset "utf-8";@font-face {font-family: "CrassRoots";src: url("../media/cr.ttf");}html, body {font-size: 1.6em;}
357
@keyframes mymove {from {top: 0px;}
@@ -456,8 +469,8 @@ To output the entire CSS document into a variable, just use `->__toString()`:
456
[1]=>
457
string(9) "Helvetica"
458
[2]=>
459
- object(Sabberworm\CSS\Value\String)#14 (1) {
460
- ["sString":"Sabberworm\CSS\Value\String":private]=>
461
string(9) "Gill Sans"
462
}
463
[3]=>
@@ -487,7 +500,7 @@ To output the entire CSS document into a variable, just use `->__toString()`:
487
}
488
}
489
490
- #### Output (`__toString()`)
491
492
#header {margin: 10px 2em 1cm 2%;font-family: Verdana,Helvetica,"Gill Sans",sans-serif;color: red !important;}
493
@@ -504,7 +517,7 @@ To output the entire CSS document into a variable, just use `->__toString()`:
504
## Misc
505
506
* Legacy Support: The latest pre-PSR-0 version of this project can be checked with the `0.9.0` tag.
507
- * Running Tests: To run all unit tests for this project, have `phpunit` installed, `cd` to the `tests` dir and run `phpunit .`.
508
509
## License
510
1
PHP CSS Parser
2
--------------
3
4
+ [![build status](https://travis-ci.org/sabberworm/PHP-CSS-Parser.png)](https://travis-ci.org/sabberworm/PHP-CSS-Parser) [![HHVM Status](http://hhvm.h4cc.de/badge/sabberworm/php-css-parser.png)](http://hhvm.h4cc.de/package/sabberworm/php-css-parser)
5
+
6
A Parser for CSS Files written in PHP. Allows extraction of CSS files into a data structure, manipulation of said structure and output as (optimized) CSS.
7
8
## Usage
63
* `Document` – representing the root of a CSS file.
64
* `MediaQuery` – represents a subsection of a CSSList that only applies to a output device matching the contained media query.
65
66
+ To access the items stored in a `CSSList` – like the document you got back when calling `$oCssParser->parse()` –, use `getContents()`, then iterate over that collection and use instanceof to check whether you’re dealing with another `CSSList`, a `RuleSet`, a `Import` or a `Charset`.
67
+
68
+ To append a new item (selector, media query, etc.) to an existing `CSSList`, construct it using the constructor for this class and use the `append($oItem)` method.
69
+
70
#### RuleSet
71
72
`RuleSet` is a container for individual rules. The most common form of a rule set is one constrained by a selector. The following concrete subtypes exist:
76
77
Note: A `CSSList` can contain other `CSSList`s (and `Import`s as well as a `Charset`) while a `RuleSet` can only contain `Rule`s.
78
79
+ If you want to manipulate a `RuleSet`, use the methods `addRule(Rule $oRule)`, `getRules()` and `removeRule($mRule)` (which accepts either a Rule instance or a rule name; optionally suffixed by a dash to remove all related rules).
80
+
81
#### Rule
82
83
`Rule`s just have a key (the rule) and a value. These values are all instances of a `Value`.
84
85
#### Value
86
87
+ `Value` is an abstract class that only defines the `render` method. The concrete subclasses for atomic value types are:
88
89
* `Size` – consists of a numeric `size` value and a unit.
90
* `Color` – colors can be input in the form #rrggbb, #rgb or schema(val1, val2, …) but are always stored as an array of ('s' => val1, 'c' => val2, 'h' => val3, …) and output in the second form.
91
+ * `CSSString` – this is just a wrapper for quoted strings to distinguish them from keywords; always output with double quotes.
92
* `URL` – URLs in CSS; always output in URL("") notation.
93
94
There is another abstract subclass of `Value`, `ValueList`. A `ValueList` represents a lists of `Value`s, separated by some separation character (mostly `,`, whitespace, or `/`). There are two types of `ValueList`s:
96
* `RuleValueList` – The default type, used to represent all multi-valued rules like `font: bold 12px/3 Helvetica, Verdana, sans-serif;` (where the value would be a whitespace-separated list of the primitive value `bold`, a slash-separated list and a comma-separated list).
97
* `CSSFunction` – A special kind of value that also contains a function name and where the values are the function’s arguments. Also handles equals-sign-separated argument lists like `filter: alpha(opacity=90);`.
98
99
#### Convenience methods
100
101
There are a few convenience methods on Document to ease finding, manipulating and deleting rules:
106
107
## To-Do
108
109
+ * More convenience methods [like `selectorsWithElement($sId/Class/TagName)`, `attributesOfType($sType)`, `removeAttributesOfType($sType)`]
110
* Real multibyte support. Currently only multibyte charsets whose first 255 code points take up only one byte and are identical with ASCII are supported (yes, UTF-8 fits this description).
111
* Named color support (using `Color` instead of an anonymous string literal)
112
145
146
### Output
147
148
+ To output the entire CSS document into a variable, just use `->render()`:
149
150
$oCssParser = new Sabberworm\CSS\Parser(file_get_contents('somefile.css'));
151
$oCssDocument = $oCssParser->parse();
152
+ print $oCssDocument->render();
153
+
154
+ If you want to format the output, pass an instance of type `Sabberworm\CSS\OutputFormat`:
155
+
156
+ $oFormat = Sabberworm\CSS\OutputFormat::create()->indentWithSpaces(4)->setSpaceBetweenRules("\n");
157
+ print $oCssDocument->render($oFormat);
158
+
159
+ Or use one of the predefined formats:
160
+
161
+ print $oCssDocument->render(Sabberworm\CSS\OutputFormat::createPretty());
162
+ print $oCssDocument->render(Sabberworm\CSS\OutputFormat::createCompact());
163
+
164
+ To see what you can do with output formatting, look at the tests in `tests/Sabberworm/CSS/OutputFormatTest.php`.
165
166
## Examples
167
193
[0]=>
194
object(Sabberworm\CSS\Property\Charset)#6 (1) {
195
["sCharset":"Sabberworm\CSS\Property\Charset":private]=>
196
+ object(Sabberworm\CSS\Value\CSSString)#5 (1) {
197
+ ["sString":"Sabberworm\CSS\Value\CSSString":private]=>
198
string(5) "utf-8"
199
}
200
}
211
["sRule":"Sabberworm\CSS\Rule\Rule":private]=>
212
string(11) "font-family"
213
["mValue":"Sabberworm\CSS\Rule\Rule":private]=>
214
+ object(Sabberworm\CSS\Value\CSSString)#9 (1) {
215
+ ["sString":"Sabberworm\CSS\Value\CSSString":private]=>
216
string(10) "CrassRoots"
217
}
218
["bIsImportant":"Sabberworm\CSS\Rule\Rule":private]=>
228
["mValue":"Sabberworm\CSS\Rule\Rule":private]=>
229
object(Sabberworm\CSS\Value\URL)#11 (1) {
230
["oURL":"Sabberworm\CSS\Value\URL":private]=>
231
+ object(Sabberworm\CSS\Value\CSSString)#12 (1) {
232
+ ["sString":"Sabberworm\CSS\Value\CSSString":private]=>
233
string(15) "../media/cr.ttf"
234
}
235
}
364
}
365
}
366
367
+ #### Output (`render()`)
368
369
@charset "utf-8";@font-face {font-family: "CrassRoots";src: url("../media/cr.ttf");}html, body {font-size: 1.6em;}
370
@keyframes mymove {from {top: 0px;}
469
[1]=>
470
string(9) "Helvetica"
471
[2]=>
472
+ object(Sabberworm\CSS\Value\CSSString)#14 (1) {
473
+ ["sString":"Sabberworm\CSS\Value\CSSString":private]=>
474
string(9) "Gill Sans"
475
}
476
[3]=>
500
}
501
}
502
503
+ #### Output (`render()`)
504
505
#header {margin: 10px 2em 1cm 2%;font-family: Verdana,Helvetica,"Gill Sans",sans-serif;color: red !important;}
506
517
## Misc
518
519
* Legacy Support: The latest pre-PSR-0 version of this project can be checked with the `0.9.0` tag.
520
+ * Running Tests: To run all unit tests for this project, have `phpunit` installed and run `phpunit .`.
521
522
## License
523
includes/PHP-CSS-Parser/lib/Sabberworm/CSS/CSSList/AtRuleBlockList.php CHANGED
@@ -5,7 +5,7 @@ namespace Sabberworm\CSS\CSSList;
5
use Sabberworm\CSS\Property\AtRule;
6
7
/**
8
- * A RuleSet constructed by an unknown @-rule. @font-face rules are rendered into AtRule objects.
9
*/
10
class AtRuleBlockList extends CSSBlockList implements AtRule {
11
@@ -27,10 +27,22 @@ class AtRuleBlockList extends CSSBlockList implements AtRule {
27
}
28
29
public function __toString() {
30
- $sResult = "@{$this->sType} {$this->sArgs}{";
31
- $sResult .= parent::__toString();
32
$sResult .= '}';
33
return $sResult;
34
}
35
36
}
5
use Sabberworm\CSS\Property\AtRule;
6
7
/**
8
+ * A BlockList constructed by an unknown @-rule. @media rules are rendered into AtRuleBlockList objects.
9
*/
10
class AtRuleBlockList extends CSSBlockList implements AtRule {
11
27
}
28
29
public function __toString() {
30
+ return $this->render(new \Sabberworm\CSS\OutputFormat());
31
+ }
32
+
33
+ public function render(\Sabberworm\CSS\OutputFormat $oOutputFormat) {
34
+ $sArgs = $this->sArgs;
35
+ if($sArgs) {
36
+ $sArgs = ' ' . $sArgs;
37
+ }
38
+ $sResult = "@{$this->sType}$sArgs{$oOutputFormat->spaceBeforeOpeningBrace()}{";
39
+ $sResult .= parent::render($oOutputFormat);
40
$sResult .= '}';
41
return $sResult;
42
}
43
44
+ public function isRootList() {
45
+ return false;
46
+ }
47
+
48
}
includes/PHP-CSS-Parser/lib/Sabberworm/CSS/CSSList/CSSBlockList.php CHANGED
@@ -52,7 +52,7 @@ abstract class CSSBlockList extends CSSList {
52
}
53
}
54
} else {
55
- //Non-List Value or String (CSS identifier)
56
$aResult[] = $oElement;
57
}
58
}
52
}
53
}
54
} else {
55
+ //Non-List Value or CSSString (CSS identifier)
56
$aResult[] = $oElement;
57
}
58
}
includes/PHP-CSS-Parser/lib/Sabberworm/CSS/CSSList/CSSList.php CHANGED
@@ -33,9 +33,16 @@ abstract class CSSList {
33
$iKey = array_search($oItemToRemove, $this->aContents, true);
34
if ($iKey !== false) {
35
unset($this->aContents[$iKey]);
36
}
37
}
38
39
public function removeDeclarationBlockBySelector($mSelector, $bRemoveAll = false) {
40
if ($mSelector instanceof DeclarationBlock) {
41
$mSelector = $mSelector->getSelectors();
@@ -62,12 +69,44 @@ abstract class CSSList {
62
}
63
64
public function __toString() {
65
$sResult = '';
66
foreach ($this->aContents as $oContent) {
67
- $sResult .= $oContent->__toString();
68
}
69
return $sResult;
70
}
71
72
public function getContents() {
73
return $this->aContents;
33
$iKey = array_search($oItemToRemove, $this->aContents, true);
34
if ($iKey !== false) {
35
unset($this->aContents[$iKey]);
36
+ return true;
37
}
38
+ return false;
39
}
40
41
+ /**
42
+ * Removes a declaration block from the CSS list if it matches all given selectors.
43
+ * @param array|string $mSelector The selectors to match.
44
+ * @param boolean $bRemoveAll Whether to stop at the first declaration block found or remove all blocks
45
+ */
46
public function removeDeclarationBlockBySelector($mSelector, $bRemoveAll = false) {
47
if ($mSelector instanceof DeclarationBlock) {
48
$mSelector = $mSelector->getSelectors();
69
}
70
71
public function __toString() {
72
+ return $this->render(new \Sabberworm\CSS\OutputFormat());
73
+ }
74
+
75
+ public function render(\Sabberworm\CSS\OutputFormat $oOutputFormat) {
76
$sResult = '';
77
+ $bIsFirst = true;
78
+ $oNextLevel = $oOutputFormat;
79
+ if(!$this->isRootList()) {
80
+ $oNextLevel = $oOutputFormat->nextLevel();
81
+ }
82
foreach ($this->aContents as $oContent) {
83
+ $sRendered = $oOutputFormat->safely(function() use ($oNextLevel, $oContent) {
84
+ return $oContent->render($oNextLevel);
85
+ });
86
+ if($sRendered === null) {
87
+ continue;
88
+ }
89
+ if($bIsFirst) {
90
+ $bIsFirst = false;
91
+ $sResult .= $oNextLevel->spaceBeforeBlocks();
92
+ } else {
93
+ $sResult .= $oNextLevel->spaceBetweenBlocks();
94
+ }
95
+ $sResult .= $sRendered;
96
+ }
97
+
98
+ if(!$bIsFirst) {
99
+ // Had some output
100
+ $sResult .= $oOutputFormat->spaceAfterBlocks();
101
}
102
+
103
return $sResult;
104
}
105
+
106
+ /**
107
+ * Return true if the list can not be further outdented. Only important when rendering.
108
+ */
109
+ public abstract function isRootList();
110
111
public function getContents() {
112
return $this->aContents;
includes/PHP-CSS-Parser/lib/Sabberworm/CSS/CSSList/Document.php CHANGED
@@ -7,81 +7,92 @@ namespace Sabberworm\CSS\CSSList;
7
*/
8
class Document extends CSSBlockList {
9
10
- /**
11
- * Gets all DeclarationBlock objects recursively.
12
- */
13
- public function getAllDeclarationBlocks() {
14
- $aResult = array();
15
- $this->allDeclarationBlocks($aResult);
16
- return $aResult;
17
- }
18
19
- /**
20
- * @deprecated use getAllDeclarationBlocks()
21
- */
22
- public function getAllSelectors() {
23
- return $this->getAllDeclarationBlocks();
24
- }
25
26
- /**
27
- * Returns all RuleSet objects found recursively in the tree.
28
- */
29
- public function getAllRuleSets() {
30
- $aResult = array();
31
- $this->allRuleSets($aResult);
32
- return $aResult;
33
- }
34
35
- /**
36
- * Returns all Value objects found recursively in the tree.
37
- * @param (object|string) $mElement the CSSList or RuleSet to start the search from (defaults to the whole document). If a string is given, it is used as rule name filter (@see{RuleSet->getRules()}).
38
- * @param (bool) $bSearchInFunctionArguments whether to also return Value objects used as Function arguments.
39
- */
40
- public function getAllValues($mElement = null, $bSearchInFunctionArguments = false) {
41
- $sSearchString = null;
42
- if ($mElement === null) {
43
- $mElement = $this;
44
- } else if (is_string($mElement)) {
45
- $sSearchString = $mElement;
46
- $mElement = $this;
47
- }
48
- $aResult = array();
49
- $this->allValues($mElement, $aResult, $sSearchString, $bSearchInFunctionArguments);
50
- return $aResult;
51
- }
52
53
- /**
54
- * Returns all Selector objects found recursively in the tree.
55
- * Note that this does not yield the full DeclarationBlock that the selector belongs to (and, currently, there is no way to get to that).
56
- * @param $sSpecificitySearch An optional filter by specificity. May contain a comparison operator and a number or just a number (defaults to "==").
57
- * @example getSelectorsBySpecificity('>= 100')
58
- */
59
- public function getSelectorsBySpecificity($sSpecificitySearch = null) {
60
- if (is_numeric($sSpecificitySearch) || is_numeric($sSpecificitySearch[0])) {
61
- $sSpecificitySearch = "== $sSpecificitySearch";
62
- }
63
- $aResult = array();
64
- $this->allSelectors($aResult, $sSpecificitySearch);
65
- return $aResult;
66
- }
67
68
- /**
69
- * Expands all shorthand properties to their long value
70
- */
71
- public function expandShorthands() {
72
- foreach ($this->getAllDeclarationBlocks() as $oDeclaration) {
73
- $oDeclaration->expandShorthands();
74
- }
75
- }
76
77
- /*
78
- * Create shorthands properties whenever possible
79
- */
80
81
- public function createShorthands() {
82
- foreach ($this->getAllDeclarationBlocks() as $oDeclaration) {
83
- $oDeclaration->createShorthands();
84
- }
85
- }
86
87
}
7
*/
8
class Document extends CSSBlockList {
9
10
+ /**
11
+ * Gets all DeclarationBlock objects recursively.
12
+ */
13
+ public function getAllDeclarationBlocks() {
14
+ $aResult = array();
15
+ $this->allDeclarationBlocks($aResult);
16
+ return $aResult;
17
+ }
18
19
+ /**
20
+ * @deprecated use getAllDeclarationBlocks()
21
+ */
22
+ public function getAllSelectors() {
23
+ return $this->getAllDeclarationBlocks();
24
+ }
25
26
+ /**
27
+ * Returns all RuleSet objects found recursively in the tree.
28
+ */
29
+ public function getAllRuleSets() {
30
+ $aResult = array();
31
+ $this->allRuleSets($aResult);
32
+ return $aResult;
33
+ }
34
35
+ /**
36
+ * Returns all Value objects found recursively in the tree.
37
+ * @param (object|string) $mElement the CSSList or RuleSet to start the search from (defaults to the whole document). If a string is given, it is used as rule name filter (@see{RuleSet->getRules()}).
38
+ * @param (bool) $bSearchInFunctionArguments whether to also return Value objects used as Function arguments.
39
+ */
40
+ public function getAllValues($mElement = null, $bSearchInFunctionArguments = false) {
41
+ $sSearchString = null;
42
+ if ($mElement === null) {
43
+ $mElement = $this;
44
+ } else if (is_string($mElement)) {
45
+ $sSearchString = $mElement;
46
+ $mElement = $this;
47
+ }
48
+ $aResult = array();
49
+ $this->allValues($mElement, $aResult, $sSearchString, $bSearchInFunctionArguments);
50
+ return $aResult;
51
+ }
52
53
+ /**
54
+ * Returns all Selector objects found recursively in the tree.
55
+ * Note that this does not yield the full DeclarationBlock that the selector belongs to (and, currently, there is no way to get to that).
56
+ * @param $sSpecificitySearch An optional filter by specificity. May contain a comparison operator and a number or just a number (defaults to "==").
57
+ * @example getSelectorsBySpecificity('>= 100')
58
+ */
59
+ public function getSelectorsBySpecificity($sSpecificitySearch = null) {
60
+ if (is_numeric($sSpecificitySearch) || is_numeric($sSpecificitySearch[0])) {
61
+ $sSpecificitySearch = "== $sSpecificitySearch";
62
+ }
63
+ $aResult = array();
64
+ $this->allSelectors($aResult, $sSpecificitySearch);
65
+ return $aResult;
66
+ }
67
68
+ /**
69
+ * Expands all shorthand properties to their long value
70
+ */
71
+ public function expandShorthands() {
72
+ foreach ($this->getAllDeclarationBlocks() as $oDeclaration) {
73
+ $oDeclaration->expandShorthands();
74
+ }
75
+ }
76
77
+ /**
78
+ * Create shorthands properties whenever possible
79
+ */
80
+ public function createShorthands() {
81
+ foreach ($this->getAllDeclarationBlocks() as $oDeclaration) {
82
+ $oDeclaration->createShorthands();
83
+ }
84
+ }
85
86
+ // Override render() to make format argument optional
87
+ public function render(\Sabberworm\CSS\OutputFormat $oOutputFormat = null) {
88
+ if($oOutputFormat === null) {
89
+ $oOutputFormat = new \Sabberworm\CSS\OutputFormat();
90
+ }
91
+ return parent::render($oOutputFormat);
92
+ }
93
+
94
+ public function isRootList() {
95
+ return true;
96
+ }
97
98
}
includes/PHP-CSS-Parser/lib/Sabberworm/CSS/CSSList/KeyFrame.php CHANGED
@@ -1,48 +1,56 @@
1
- <?php
2
-
3
- namespace Sabberworm\CSS\CSSList;
4
-
5
- use Sabberworm\CSS\Property\AtRule;
6
-
7
- class KeyFrame extends CSSList implements AtRule {
8
-
9
- private $vendorKeyFrame;
10
- private $animationName;
11
-
12
- public function __construct() {
13
- parent::__construct();
14
- $this->vendorKeyFrame = null;
15
- $this->animationName = null;
16
- }
17
-
18
- public function setVendorKeyFrame($vendorKeyFrame) {
19
- $this->vendorKeyFrame = $vendorKeyFrame;
20
- }
21
-
22
- public function getVendorKeyFrame() {
23
- return $this->vendorKeyFrame;
24
- }
25
-
26
- public function setAnimationName($animationName) {
27
- $this->animationName = $animationName;
28
- }
29
-
30
- public function getAnimationName() {
31
- return $this->animationName;
32
- }
33
-
34
- public function __toString() {
35
- $sResult = "@{$this->vendorKeyFrame} {$this->animationName} {";
36
- $sResult .= parent::__toString();
37
- $sResult .= '}';
38
- return $sResult;
39
- }
40
-
41
- public function atRuleName() {
42
- return $this->vendorKeyFrame;
43
- }
44
-
45
- public function atRuleArgs() {
46
- return $this->animationName;
47
- }
48
- }
1
+ <?php
2
+
3
+ namespace Sabberworm\CSS\CSSList;
4
+
5
+ use Sabberworm\CSS\Property\AtRule;
6
+
7
+ class KeyFrame extends CSSList implements AtRule {
8
+
9
+ private $vendorKeyFrame;
10
+ private $animationName;
11
+
12
+ public function __construct() {
13
+ parent::__construct();
14
+ $this->vendorKeyFrame = null;
15
+ $this->animationName = null;
16
+ }
17
+
18
+ public function setVendorKeyFrame($vendorKeyFrame) {
19
+ $this->vendorKeyFrame = $vendorKeyFrame;
20
+ }
21
+
22
+ public function getVendorKeyFrame() {
23
+ return $this->vendorKeyFrame;
24
+ }
25
+
26
+ public function setAnimationName($animationName) {
27
+ $this->animationName = $animationName;
28
+ }
29
+
30
+ public function getAnimationName() {
31
+ return $this->animationName;
32
+ }
33
+
34
+ public function __toString() {
35
+ return $this->render(new \Sabberworm\CSS\OutputFormat());
36
+ }
37
+
38
+ public function render(\Sabberworm\CSS\OutputFormat $oOutputFormat) {
39
+ $sResult = "@{$this->vendorKeyFrame} {$this->animationName}{$oOutputFormat->spaceBeforeOpeningBrace()}{";
40
+ $sResult .= parent::render($oOutputFormat);
41
+ $sResult .= '}';
42
+ return $sResult;
43
+ }
44
+
45
+ public function isRootList() {
46
+ return false;
47
+ }
48
+
49
+ public function atRuleName() {
50
+ return $this->vendorKeyFrame;
51
+ }
52
+
53
+ public function atRuleArgs() {
54
+ return $this->animationName;
55
+ }
56
+ }
includes/PHP-CSS-Parser/lib/Sabberworm/CSS/OutputFormat.php ADDED
@@ -0,0 +1,289 @@
1
+ <?php
2
+
3
+ namespace Sabberworm\CSS;
4
+
5
+ use Sabberworm\CSS\Parsing\OutputException;
6
+
7
+ class OutputFormat {
8
+ /**
9
+ * Value format
10
+ */
11
+ // " means double-quote, ' means single-quote
12
+ public $sStringQuotingType = '"';
13
+ // Output RGB colors in hash notation if possible
14
+ public $bRGBHashNotation = true;
15
+
16
+ /**
17
+ * Declaration format
18
+ */
19
+ // Semicolon after the last rule of a declaration block can be omitted. To do that, set this false.
20
+ public $bSemicolonAfterLastRule = true;
21
+
22
+ /**
23
+ * Spacing
24
+ * Note that these strings are not sanity-checked: the value should only consist of whitespace
25
+ * Any newline character will be indented according to the current level.
26
+ * The triples (After, Before, Between) can be set using a wildcard (e.g. `$oFormat->set('Space*Rules', "\n");`)
27
+ */
28
+ public $sSpaceAfterRuleName = ' ';
29
+
30
+ public $sSpaceBeforeRules = '';
31
+ public $sSpaceAfterRules = '';
32
+ public $sSpaceBetweenRules = '';
33
+
34
+ public $sSpaceBeforeBlocks = '';
35
+ public $sSpaceAfterBlocks = '';
36
+ public $sSpaceBetweenBlocks = "\n";
37
+
38
+ // This is what’s printed before and after the comma if a declaration block contains multiple selectors.
39
+ public $sSpaceBeforeSelectorSeparator = '';
40
+ public $sSpaceAfterSelectorSeparator = ' ';
41
+ // This is what’s printed after the comma of value lists
42
+ public $sSpaceBeforeListArgumentSeparator = '';
43
+ public $sSpaceAfterListArgumentSeparator = '';
44
+
45
+ public $sSpaceBeforeOpeningBrace = ' ';
46
+
47
+ /**
48
+ * Indentation
49
+ */
50
+ // Indentation character(s) per level. Only applicable if newlines are used in any of the spacing settings.
51
+ public $sIndentation = "\t";
52
+
53
+ /**
54
+ * Output exceptions.
55
+ */
56
+ public $bIgnoreExceptions = false;
57
+
58
+
59
+ private $oFormatter = null;
60
+ private $oNextLevelFormat = null;
61
+ private $iIndentationLevel = 0;
62
+
63
+ public function __construct() {
64
+ }
65
+
66
+ public function get($sName) {
67
+ $aVarPrefixes = array('a', 's', 'm', 'b', 'f', 'o', 'c', 'i');
68
+ foreach($aVarPrefixes as $sPrefix) {
69
+ $sFieldName = $sPrefix.ucfirst($sName);
70
+ if(isset($this->$sFieldName)) {
71
+ return $this->$sFieldName;
72
+ }
73
+ }
74
+ return null;
75
+ }
76
+
77
+ public function set($aNames, $mValue) {
78
+ $aVarPrefixes = array('a', 's', 'm', 'b', 'f', 'o', 'c', 'i');
79
+ if(is_string($aNames) && strpos($aNames, '*') !== false) {
80
+ $aNames = array(str_replace('*', 'Before', $aNames), str_replace('*', 'Between', $aNames), str_replace('*', 'After', $aNames));
81
+ } else if(!is_array($aNames)) {
82
+ $aNames = array($aNames);
83
+ }
84
+ foreach($aVarPrefixes as $sPrefix) {
85
+ $bDidReplace = false;
86
+ foreach($aNames as $sName) {
87
+ $sFieldName = $sPrefix.ucfirst($sName);
88
+ if(isset($this->$sFieldName)) {
89
+ $this->$sFieldName = $mValue;
90
+ $bDidReplace = true;
91
+ }
92
+ }
93
+ if($bDidReplace) {
94
+ return $this;
95
+ }
96
+ }
97
+ // Break the chain so the user knows this option is invalid
98
+ return false;
99
+ }
100
+
101
+ public function __call($sMethodName, $aArguments) {
102
+ if(strpos($sMethodName, 'set') === 0) {
103
+ return $this->set(substr($sMethodName, 3), $aArguments[0]);
104
+ } else if(strpos($sMethodName, 'get') === 0) {
105
+ return $this->get(substr($sMethodName, 3));
106
+ } else if(method_exists('\\Sabberworm\\CSS\\OutputFormatter', $sMethodName)) {
107
+ return call_user_func_array(array($this->getFormatter(), $sMethodName), $aArguments);
108
+ } else {
109
+ throw new \Exception('Unknown OutputFormat method called: '.$sMethodName);
110
+ }
111
+ }
112
+
113
+ public function indentWithTabs($iNumber = 1) {
114
+ return $this->setIndentation(str_repeat("\t", $iNumber));
115
+ }
116
+
117
+ public function indentWithSpaces($iNumber = 2) {
118
+ return $this->setIndentation(str_repeat(" ", $iNumber));
119
+ }
120
+
121
+ public function nextLevel() {
122
+ if($this->oNextLevelFormat === null) {
123
+ $this->oNextLevelFormat = clone $this;
124
+ $this->oNextLevelFormat->iIndentationLevel++;
125
+ $this->oNextLevelFormat->oFormatter = null;
126
+ }
127
+ return $this->oNextLevelFormat;
128
+ }
129
+
130
+ public function beLenient() {
131
+ $this->bIgnoreExceptions = true;
132
+ }
133
+
134
+ public function getFormatter() {
135
+ if($this->oFormatter === null) {
136
+ $this->oFormatter = new OutputFormatter($this);
137
+ }
138
+ return $this->oFormatter;
139
+ }
140
+
141
+ public function level() {
142
+ return $this->iIndentationLevel;
143
+ }
144
+
145
+ public static function create() {
146
+ return new OutputFormat();
147
+ }
148
+
149
+ public static function createCompact() {
150
+ return self::create()->set('Space*Rules', "")->set('Space*Blocks', "")->setSpaceAfterRuleName('')->setSpaceBeforeOpeningBrace('')->setSpaceAfterSelectorSeparator('');
151
+ }
152
+
153
+ public static function createPretty() {
154
+ return self::create()->set('Space*Rules', "\n")->set('Space*Blocks', "\n")->setSpaceBetweenBlocks("\n\n")->set('SpaceAfterListArgumentSeparator', array('default' => '', ',' => ' '));
155
+ }
156
+ }
157
+
158
+ class OutputFormatter {
159
+ private $oFormat;
160
+
161
+ public function __construct(OutputFormat $oFormat) {
162
+ $this->oFormat = $oFormat;
163
+ }
164
+
165
+ public function space($sName, $sType = null) {
166
+ $sSpaceString = $this->oFormat->get("Space$sName");
167
+ // If $sSpaceString is an array, we have multple values configured depending on the type of object the space applies to
168
+ if(is_array($sSpaceString)) {
169
+ if($sType !== null && isset($sSpaceString[$sType])) {
170
+ $sSpaceString = $sSpaceString[$sType];
171
+ } else {
172
+ $sSpaceString = reset($sSpaceString);
173
+ }
174
+ }
175
+ return $this->prepareSpace($sSpaceString);
176
+ }
177
+
178
+ public function spaceAfterRuleName() {
179
+ return $this->space('AfterRuleName');
180
+ }
181
+
182
+ public function spaceBeforeRules() {
183
+ return $this->space('BeforeRules');
184
+ }
185
+
186
+ public function spaceAfterRules() {
187
+ return $this->space('AfterRules');
188
+ }
189
+
190
+ public function spaceBetweenRules() {
191
+ return $this->space('BetweenRules');
192
+ }
193
+
194
+ public function spaceBeforeBlocks() {
195
+ return $this->space('BeforeBlocks');
196
+ }
197
+
198
+ public function spaceAfterBlocks() {
199
+ return $this->space('AfterBlocks');
200
+ }
201
+
202
+ public function spaceBetweenBlocks() {
203
+ return $this->space('BetweenBlocks');
204
+ }
205
+
206
+ public function spaceBeforeSelectorSeparator() {
207
+ return $this->space('BeforeSelectorSeparator');
208
+ }
209
+
210
+ public function spaceAfterSelectorSeparator() {
211
+ return $this->space('AfterSelectorSeparator');
212
+ }
213
+
214
+ public function spaceBeforeListArgumentSeparator($sSeparator) {
215
+ return $this->space('BeforeListArgumentSeparator', $sSeparator);
216
+ }
217
+
218
+ public function spaceAfterListArgumentSeparator($sSeparator) {
219
+ return $this->space('AfterListArgumentSeparator', $sSeparator);
220
+ }
221
+
222
+ public function spaceBeforeOpeningBrace() {
223
+ return $this->space('BeforeOpeningBrace');
224
+ }
225
+
226
+ /**
227
+ * Runs the given code, either swallowing or passing exceptions, depending on the bIgnoreExceptions setting.
228
+ */
229
+ public function safely($cCode) {
230
+ if($this->oFormat->get('IgnoreExceptions')) {
231
+ // If output exceptions are ignored, run the code with exception guards
232
+ try {
233
+ return $cCode();
234
+ } catch (OutputException $e) {
235
+ return null;
236
+ } //Do nothing
237
+ } else {
238
+ // Run the code as-is
239
+ return $cCode();
240
+ }
241
+ }
242
+
243
+ /**
244
+ * Clone of the implode function but calls ->render with the current output format instead of __toString()
245
+ */
246
+ public function implode($sSeparator, $aValues, $bIncreaseLevel = false) {
247
+ $sResult = '';
248
+ $oFormat = $this->oFormat;
249
+ if($bIncreaseLevel) {
250
+ $oFormat = $oFormat->nextLevel();
251
+ }
252
+ $bIsFirst = true;
253
+ foreach($aValues as $mValue) {
254
+ if($bIsFirst) {
255
+ $bIsFirst = false;
256
+ } else {
257
+ $sResult .= $sSeparator;
258
+ }
259
+ if($mValue instanceof \Sabberworm\CSS\Renderable) {
260
+ $sResult .= $mValue->render($oFormat);
261
+ } else {
262
+ $sResult .= $mValue;
263
+ }
264
+ }
265
+ return $sResult;
266
+ }
267
+
268
+ public function removeLastSemicolon($sString) {
269
+ if($this->oFormat->get('SemicolonAfterLastRule')) {
270
+ return $sString;
271
+ }
272
+ $sString = explode(';', $sString);
273
+ if(count($sString) < 2) {
274
+ return $sString[0];
275
+ }
276
+ $sLast = array_pop($sString);
277
+ $sNextToLast = array_pop($sString);
278
+ array_push($sString, $sNextToLast.$sLast);
279
+ return implode(';', $sString);
280
+ }
281
+
282
+ private function prepareSpace($sSpaceString) {
283
+ return str_replace("\n", "\n".$this->indent(), $sSpaceString);
284
+ }
285
+
286
+ private function indent() {
287
+ return str_repeat($this->oFormat->sIndentation, $this->oFormat->level());
288
+ }
289
+ }
includes/PHP-CSS-Parser/lib/Sabberworm/CSS/Parser.php CHANGED
@@ -17,7 +17,7 @@ use Sabberworm\CSS\Value\RuleValueList;
17
use Sabberworm\CSS\Value\Size;
18
use Sabberworm\CSS\Value\Color;
19
use Sabberworm\CSS\Value\URL;
20
- use Sabberworm\CSS\Value\String;
21
use Sabberworm\CSS\Rule\Rule;
22
use Sabberworm\CSS\Parsing\UnexpectedTokenException;
23
@@ -139,13 +139,13 @@ class Parser {
139
if ($sPrefix !== null && !is_string($sPrefix)) {
140
throw new \Exception('Wrong namespace prefix '.$sPrefix);
141
}
142
- if (!($mUrl instanceof String || $mUrl instanceof URL)) {
143
throw new \Exception('Wrong namespace url of invalid type '.$mUrl);
144
}
145
return new CSSNamespace($mUrl, $sPrefix);
146
} else {
147
//Unknown other at rule (font-face or such)
148
- $sArgs = $this->consumeUntil('{', false, true);
149
$this->consumeWhiteSpace();
150
$bUseRuleSet = true;
151
foreach($this->blockRules as $sBlockRuleName) {
@@ -214,7 +214,7 @@ class Parser {
214
}
215
$this->consume($sQuote);
216
}
217
- return new String($sResult);
218
}
219
220
private function parseCharacter($bIsForIdentifier) {
@@ -414,9 +414,12 @@ class Parser {
414
415
$sUnit = null;
416
foreach ($this->aSizeUnits as $iLength => &$aValues) {
417
- if(($sUnit = @$aValues[strtolower($this->peek($iLength))]) !== null) {
418
- $this->consume($iLength);
419
- break;
420
}
421
}
422
return new Size(floatval($sSize), $sUnit, $bForColor);
@@ -518,7 +521,7 @@ class Parser {
518
}
519
520
private function consumeExpression($mExpression) {
521
- $aMatches;
522
if (preg_match($mExpression, $this->inputLeft(), $aMatches, PREG_OFFSET_CAPTURE) === 1) {
523
return $this->consume($aMatches[0][0]);
524
}
@@ -546,10 +549,10 @@ class Parser {
546
547
private function consumeComment() {
548
if ($this->comes('/*')) {
549
- $this->consume(2);
550
- while ($this->consumeUntil('*', false, true)) {
551
- if ($this->comes('/')) {
552
- $this->consume(1);
553
return true;
554
}
555
}
@@ -567,6 +570,7 @@ class Parser {
567
$start = $this->iCurrentPosition;
568
569
while (($char = $this->consume(1)) !== '') {
570
if (in_array($char, $aEnd)) {
571
if ($bIncludeEnd) {
572
$out .= $char;
17
use Sabberworm\CSS\Value\Size;
18
use Sabberworm\CSS\Value\Color;
19
use Sabberworm\CSS\Value\URL;
20
+ use Sabberworm\CSS\Value\CSSString;
21
use Sabberworm\CSS\Rule\Rule;
22
use Sabberworm\CSS\Parsing\UnexpectedTokenException;
23
139
if ($sPrefix !== null && !is_string($sPrefix)) {
140
throw new \Exception('Wrong namespace prefix '.$sPrefix);
141
}
142
+ if (!($mUrl instanceof CSSString || $mUrl instanceof URL)) {
143
throw new \Exception('Wrong namespace url of invalid type '.$mUrl);
144
}
145
return new CSSNamespace($mUrl, $sPrefix);
146
} else {
147
//Unknown other at rule (font-face or such)
148
+ $sArgs = trim($this->consumeUntil('{', false, true));
149
$this->consumeWhiteSpace();
150
$bUseRuleSet = true;
151
foreach($this->blockRules as $sBlockRuleName) {
214
}
215
$this->consume($sQuote);
216
}
217
+ return new CSSString($sResult);
218
}
219
220
private function parseCharacter($bIsForIdentifier) {
414
415
$sUnit = null;
416
foreach ($this->aSizeUnits as $iLength => &$aValues) {
417
+ $sKey = strtolower($this->peek($iLength));
418
+ if(array_key_exists($sKey, $aValues)) {
419
+ if (($sUnit = $aValues[$sKey]) !== null) {
420
+ $this->consume($iLength);
421
+ break;
422
+ }
423
}
424
}
425
return new Size(floatval($sSize), $sUnit, $bForColor);
521
}
522
523
private function consumeExpression($mExpression) {
524
+ $aMatches = null;
525
if (preg_match($mExpression, $this->inputLeft(), $aMatches, PREG_OFFSET_CAPTURE) === 1) {
526
return $this->consume($aMatches[0][0]);
527
}
549
550
private function consumeComment() {
551
if ($this->comes('/*')) {
552
+ $this->consume(1);
553
+ while ($this->consume(1) !== '') {
554
+ if ($this->comes('*/')) {
555
+ $this->consume(2);
556
return true;
557
}
558
}
570
$start = $this->iCurrentPosition;
571
572
while (($char = $this->consume(1)) !== '') {
573
+ $this->consumeComment();
574
if (in_array($char, $aEnd)) {
575
if ($bIncludeEnd) {
576
$out .= $char;
includes/PHP-CSS-Parser/lib/Sabberworm/CSS/Parsing/OutputException.php ADDED
@@ -0,0 +1,9 @@
1
+ <?php
2
+
3
+ namespace Sabberworm\CSS\Parsing;
4
+
5
+ /**
6
+ * Thrown if the CSS parsers attempts to print something invalid
7
+ */
8
+ class OutputException extends \Exception {
9
+ }
includes/PHP-CSS-Parser/lib/Sabberworm/CSS/Property/AtRule.php CHANGED
@@ -2,12 +2,13 @@
2
3
namespace Sabberworm\CSS\Property;
4
5
- interface AtRule {
6
const BLOCK_RULES = 'media/document/supports/region-style/font-feature-values';
7
// Since there are more set rules than block rules, we’re whitelisting the block rules and have anything else be treated as a set rule.
8
const SET_RULES = 'font-face/counter-style/page/swash/styleset/annotation'; //…and more font-specific ones (to be used inside font-feature-values)
9
10
public function atRuleName();
11
public function atRuleArgs();
12
- public function __toString();
13
}
2
3
namespace Sabberworm\CSS\Property;
4
5
+ use Sabberworm\CSS\Renderable;
6
+
7
+ interface AtRule extends Renderable {
8
const BLOCK_RULES = 'media/document/supports/region-style/font-feature-values';
9
// Since there are more set rules than block rules, we’re whitelisting the block rules and have anything else be treated as a set rule.
10
const SET_RULES = 'font-face/counter-style/page/swash/styleset/annotation'; //…and more font-specific ones (to be used inside font-feature-values)
11
12
public function atRuleName();
13
public function atRuleArgs();
14
}
includes/PHP-CSS-Parser/lib/Sabberworm/CSS/Property/CSSNamespace.php CHANGED
@@ -15,7 +15,11 @@ class CSSNamespace implements AtRule {
15
}
16
17
public function __toString() {
18
- return '@namespace '.($this->sPrefix === null ? '' : $this->sPrefix.' ').$this->mUrl->__toString().';';
19
}
20
21
public function getUrl() {
15
}
16
17
public function __toString() {
18
+ return $this->render(new \Sabberworm\CSS\OutputFormat());
19
+ }
20
+
21
+ public function render(\Sabberworm\CSS\OutputFormat $oOutputFormat) {
22
+ return '@namespace '.($this->sPrefix === null ? '' : $this->sPrefix.' ').$this->mUrl->render($oOutputFormat).';';
23
}
24
25
public function getUrl() {
includes/PHP-CSS-Parser/lib/Sabberworm/CSS/Property/Charset.php CHANGED
@@ -26,7 +26,11 @@ class Charset implements AtRule {
26
}
27
28
public function __toString() {
29
- return "@charset {$this->sCharset->__toString()};";
30
}
31
32
public function atRuleName() {
26
}
27
28
public function __toString() {
29
+ return $this->render(new \Sabberworm\CSS\OutputFormat());
30
+ }
31
+
32
+ public function render(\Sabberworm\CSS\OutputFormat $oOutputFormat) {
33
+ return "@charset {$this->sCharset->render($oOutputFormat)};";
34
}
35
36
public function atRuleName() {
includes/PHP-CSS-Parser/lib/Sabberworm/CSS/Property/Import.php CHANGED
@@ -25,7 +25,11 @@ class Import implements AtRule {
25
}
26
27
public function __toString() {
28
- return "@import ".$this->oLocation->__toString().($this->sMediaQuery === null ? '' : ' '.$this->sMediaQuery).';';
29
}
30
31
public function atRuleName() {
25
}
26
27
public function __toString() {
28
+ return $this->render(new \Sabberworm\CSS\OutputFormat());
29
+ }
30
+
31
+ public function render(\Sabberworm\CSS\OutputFormat $oOutputFormat) {
32
+ return "@import ".$this->oLocation->render($oOutputFormat).($this->sMediaQuery === null ? '' : ' '.$this->sMediaQuery).';';
33
}
34
35
public function atRuleName() {
includes/PHP-CSS-Parser/lib/Sabberworm/CSS/Property/Selector.php CHANGED
@@ -7,34 +7,33 @@ namespace Sabberworm\CSS\Property;
7
*/
8
class Selector {
9
10
- const
11
- NON_ID_ATTRIBUTES_AND_PSEUDO_CLASSES_RX = '/
12
- (\.[\w]+) # classes
13
- |
14
- \[(\w+) # attributes
15
- |
16
- (\:( # pseudo classes
17
- link|visited|active
18
- |hover|focus
19
- |lang
20
- |target
21
- |enabled|disabled|checked|indeterminate
22
- |root
23
- |nth-child|nth-last-child|nth-of-type|nth-last-of-type
24
- |first-child|last-child|first-of-type|last-of-type
25
- |only-child|only-of-type
26
- |empty|contains
27
- ))
28
- /ix',
29
- ELEMENTS_AND_PSEUDO_ELEMENTS_RX = '/
30
- ((^|[\s\+\>\~]+)[\w]+ # elements
31
- |
32
- \:{1,2}( # pseudo-elements
33
- after|before
34
- |first-letter|first-line
35
- |selection
36
- )
37
- )/ix';
38
39
private $sSelector;
40
private $iSpecificity;
@@ -63,7 +62,7 @@ class Selector {
63
if ($this->iSpecificity === null) {
64
$a = 0;
65
/// @todo should exclude \# as well as "#"
66
- $aMatches;
67
$b = substr_count($this->sSelector, '#');
68
$c = preg_match_all(self::NON_ID_ATTRIBUTES_AND_PSEUDO_CLASSES_RX, $this->sSelector, $aMatches);
69
$d = preg_match_all(self::ELEMENTS_AND_PSEUDO_ELEMENTS_RX, $this->sSelector, $aMatches);
@@ -72,4 +71,4 @@ class Selector {
72
return $this->iSpecificity;
73
}
74
75
- }
7
*/
8
class Selector {
9
10
+ //Regexes for specificity calculations
11
+ const NON_ID_ATTRIBUTES_AND_PSEUDO_CLASSES_RX = '/
12
+ (\.[\w]+) # classes
13
+ |
14
+ \[(\w+) # attributes
15
+ |
16
+ (\:( # pseudo classes
17
+ link|visited|active
18
+ |hover|focus
19
+ |lang
20
+ |target
21
+ |enabled|disabled|checked|indeterminate
22
+ |root
23
+ |nth-child|nth-last-child|nth-of-type|nth-last-of-type
24
+ |first-child|last-child|first-of-type|last-of-type
25
+ |only-child|only-of-type
26
+ |empty|contains
27
+ ))
28
+ /ix';
29
+
30
+ const ELEMENTS_AND_PSEUDO_ELEMENTS_RX = '/
31
+ ((^|[\s\+\>\~]+)[\w]+ # elements
32
+ |
33
+ \:{1,2}( # pseudo-elements
34
+ after|before|first-letter|first-line|selection
35
+ ))
36
+ /ix';
37
38
private $sSelector;
39
private $iSpecificity;
62
if ($this->iSpecificity === null) {
63
$a = 0;
64
/// @todo should exclude \# as well as "#"
65
+ $aMatches = null;
66
$b = substr_count($this->sSelector, '#');
67
$c = preg_match_all(self::NON_ID_ATTRIBUTES_AND_PSEUDO_CLASSES_RX, $this->sSelector, $aMatches);
68
$d = preg_match_all(self::ELEMENTS_AND_PSEUDO_ELEMENTS_RX, $this->sSelector, $aMatches);
71
return $this->iSpecificity;
72
}
73
74
+ }
includes/PHP-CSS-Parser/lib/Sabberworm/CSS/Renderable.php ADDED
@@ -0,0 +1,8 @@
1
+ <?php
2
+
3
+ namespace Sabberworm\CSS;
4
+
5
+ interface Renderable {
6
+ public function __toString();
7
+ public function render(\Sabberworm\CSS\OutputFormat $oOutputFormat);
8
+ }
includes/PHP-CSS-Parser/lib/Sabberworm/CSS/Rule/Rule.php CHANGED
@@ -126,9 +126,13 @@ class Rule {
126
}
127
128
public function __toString() {
129
- $sResult = "{$this->sRule}: ";
130
if ($this->mValue instanceof Value) { //Can also be a ValueList
131
- $sResult .= $this->mValue->__toString();
132
} else {
133
$sResult .= $this->mValue;
134
}
126
}
127
128
public function __toString() {
129
+ return $this->render(new \Sabberworm\CSS\OutputFormat());
130
+ }
131
+
132
+ public function render(\Sabberworm\CSS\OutputFormat $oOutputFormat) {
133
+ $sResult = "{$this->sRule}:{$oOutputFormat->spaceAfterRuleName()}";
134
if ($this->mValue instanceof Value) { //Can also be a ValueList
135
+ $sResult .= $this->mValue->render($oOutputFormat);
136
} else {
137
$sResult .= $this->mValue;
138
}
includes/PHP-CSS-Parser/lib/Sabberworm/CSS/RuleSet/AtRuleSet.php CHANGED
@@ -5,7 +5,7 @@ namespace Sabberworm\CSS\RuleSet;
5
use Sabberworm\CSS\Property\AtRule;
6
7
/**
8
- * A RuleSet constructed by an unknown @-rule. @font-face rules are rendered into AtRule objects.
9
*/
10
class AtRuleSet extends RuleSet implements AtRule {
11
@@ -27,8 +27,16 @@ class AtRuleSet extends RuleSet implements AtRule {
27
}
28
29
public function __toString() {
30
- $sResult = "@{$this->sType} {$this->sArgs}{";
31
- $sResult .= parent::__toString();
32
$sResult .= '}';
33
return $sResult;
34
}
5
use Sabberworm\CSS\Property\AtRule;
6
7
/**
8
+ * A RuleSet constructed by an unknown @-rule. @font-face rules are rendered into AtRuleSet objects.
9
*/
10
class AtRuleSet extends RuleSet implements AtRule {
11
27
}
28
29
public function __toString() {
30
+ return $this->render(new \Sabberworm\CSS\OutputFormat());
31
+ }
32
+
33
+ public function render(\Sabberworm\CSS\OutputFormat $oOutputFormat) {
34
+ $sArgs = $this->sArgs;
35
+ if($sArgs) {
36
+ $sArgs = ' ' . $sArgs;
37
+ }
38
+ $sResult = "@{$this->sType}$sArgs{$oOutputFormat->spaceBeforeOpeningBrace()}{";
39
+ $sResult .= parent::render($oOutputFormat);
40
$sResult .= '}';
41
return $sResult;
42
}
includes/PHP-CSS-Parser/lib/Sabberworm/CSS/RuleSet/DeclarationBlock.php CHANGED
@@ -9,6 +9,7 @@ use Sabberworm\CSS\Value\Value;
9
use Sabberworm\CSS\Value\Size;
10
use Sabberworm\CSS\Value\Color;
11
use Sabberworm\CSS\Value\URL;
12
13
/**
14
* Declaration blocks are the parts of a css file which denote the rules belonging to a selector.
@@ -36,6 +37,20 @@ class DeclarationBlock extends RuleSet {
36
}
37
}
38
39
/**
40
* @deprecated use getSelectors()
41
*/
@@ -576,9 +591,17 @@ class DeclarationBlock extends RuleSet {
576
}
577
578
public function __toString() {
579
- $sResult = implode(', ', $this->aSelectors) . ' {';
580
- $sResult .= parent::__toString();
581
- $sResult .= '}' . "\n";
582
return $sResult;
583
}
584
9
use Sabberworm\CSS\Value\Size;
10
use Sabberworm\CSS\Value\Color;
11
use Sabberworm\CSS\Value\URL;
12
+ use Sabberworm\CSS\Parsing\OutputException;
13
14
/**
15
* Declaration blocks are the parts of a css file which denote the rules belonging to a selector.
37
}
38
}
39
40
+ // remove one of the selector of the block
41
+ public function removeSelector($mSelector) {
42
+ if($mSelector instanceof Selector) {
43
+ $mSelector = $mSelector->getSelector();
44
+ }
45
+ foreach($this->aSelectors as $iKey => $oSelector) {
46
+ if($oSelector->getSelector() === $mSelector) {
47
+ unset($this->aSelectors[$iKey]);
48
+ return true;
49
+ }
50
+ }
51
+ return false;
52
+ }
53
+
54
/**
55
* @deprecated use getSelectors()
56
*/
591
}
592
593
public function __toString() {
594
+ return $this->render(new \Sabberworm\CSS\OutputFormat());
595
+ }
596
+
597
+ public function render(\Sabberworm\CSS\OutputFormat $oOutputFormat) {
598
+ if(count($this->aSelectors) === 0) {
599
+ // If all the selectors have been removed, this declaration block becomes invalid
600
+ throw new OutputException("Attempt to print declaration block with missing selector");
601
+ }
602
+ $sResult = $oOutputFormat->implode($oOutputFormat->spaceBeforeSelectorSeparator() . ',' . $oOutputFormat->spaceAfterSelectorSeparator(), $this->aSelectors) . $oOutputFormat->spaceBeforeOpeningBrace() . '{';
603
+ $sResult .= parent::render($oOutputFormat);
604
+ $sResult .= '}';
605
return $sResult;
606
}
607
includes/PHP-CSS-Parser/lib/Sabberworm/CSS/RuleSet/RuleSet.php CHANGED
@@ -3,12 +3,13 @@
3
namespace Sabberworm\CSS\RuleSet;
4
5
use Sabberworm\CSS\Rule\Rule;
6
7
/**
8
* RuleSet is a generic superclass denoting rules. The typical example for rule sets are declaration block.
9
* However, unknown At-Rules (like @font-face) are also rule sets.
10
*/
11
- abstract class RuleSet {
12
13
private $aRules;
14
@@ -83,13 +84,36 @@ abstract class RuleSet {
83
}
84
85
public function __toString() {
86
$sResult = '';
87
foreach ($this->aRules as $aRules) {
88
foreach($aRules as $oRule) {
89
- $sResult .= $oRule->__toString();
90
}
91
}
92
- return $sResult;
93
}
94
95
}
3
namespace Sabberworm\CSS\RuleSet;
4
5
use Sabberworm\CSS\Rule\Rule;
6
+ use Sabberworm\CSS\Renderable;
7
8
/**
9
* RuleSet is a generic superclass denoting rules. The typical example for rule sets are declaration block.
10
* However, unknown At-Rules (like @font-face) are also rule sets.
11
*/
12
+ abstract class RuleSet implements Renderable {
13
14
private $aRules;
15
84
}
85
86
public function __toString() {
87
+ return $this->render(new \Sabberworm\CSS\OutputFormat());
88
+ }
89
+
90
+ public function render(\Sabberworm\CSS\OutputFormat $oOutputFormat) {
91
$sResult = '';
92
+ $bIsFirst = true;
93
foreach ($this->aRules as $aRules) {
94
foreach($aRules as $oRule) {
95
+ $sRendered = $oOutputFormat->safely(function() use ($oRule, $oOutputFormat) {
96
+ return $oRule->render($oOutputFormat->nextLevel());
97
+ });
98
+ if($sRendered === null) {
99
+ continue;
100
+ }
101
+ if($bIsFirst) {
102
+ $bIsFirst = false;
103
+ $sResult .= $oOutputFormat->nextLevel()->spaceBeforeRules();
104
+ } else {
105
+ $sResult .= $oOutputFormat->nextLevel()->spaceBetweenRules();
106
+ }
107
+ $sResult .= $sRendered;
108
}
109
}
110
+
111
+ if(!$bIsFirst) {
112
+ // Had some output
113
+ $sResult .= $oOutputFormat->spaceAfterRules();
114
+ }
115
+
116
+ return $oOutputFormat->removeLastSemicolon($sResult);
117
}
118
119
}
includes/PHP-CSS-Parser/lib/Sabberworm/CSS/Value/CSSFunction.php CHANGED
@@ -28,7 +28,11 @@ class CSSFunction extends ValueList {
28
}
29
30
public function __toString() {
31
- $aArguments = parent::__toString();
32
return "{$this->sName}({$aArguments})";
33
}
34
28
}
29
30
public function __toString() {
31
+ return $this->render(new \Sabberworm\CSS\OutputFormat());
32
+ }
33
+
34
+ public function render(\Sabberworm\CSS\OutputFormat $oOutputFormat) {
35
+ $aArguments = parent::render($oOutputFormat);
36
return "{$this->sName}({$aArguments})";
37
}
38
includes/PHP-CSS-Parser/lib/Sabberworm/CSS/Value/{String.php → CSSString.php} RENAMED
@@ -2,7 +2,7 @@
2
3
namespace Sabberworm\CSS\Value;
4
5
- class String extends PrimitiveValue {
6
7
private $sString;
8
@@ -19,9 +19,13 @@ class String extends PrimitiveValue {
19
}
20
21
public function __toString() {
22
$sString = addslashes($this->sString);
23
$sString = str_replace("\n", '\A', $sString);
24
- return '"' . $sString . '"';
25
}
26
27
}
2
3
namespace Sabberworm\CSS\Value;
4
5
+ class CSSString extends PrimitiveValue {
6
7
private $sString;
8
19
}
20
21
public function __toString() {
22
+ return $this->render(new \Sabberworm\CSS\OutputFormat());
23
+ }
24
+
25
+ public function render(\Sabberworm\CSS\OutputFormat $oOutputFormat) {
26
$sString = addslashes($this->sString);
27
$sString = str_replace("\n", '\A', $sString);
28
+ return $oOutputFormat->getStringQuotingType() . $sString . $oOutputFormat->getStringQuotingType();
29
}
30
31
}
includes/PHP-CSS-Parser/lib/Sabberworm/CSS/Value/Color.php CHANGED
@@ -22,17 +22,20 @@ class Color extends CSSFunction {
22
}
23
24
public function __toString() {
25
// Shorthand RGB color values
26
- // TODO: Include in output settings (once they’re done)
27
- if(implode('', array_keys($this->aComponents)) === 'rgb') {
28
$sResult = sprintf(
29
'%02x%02x%02x',
30
- $this->aComponents['r']->__toString(),
31
- $this->aComponents['g']->__toString(),
32
- $this->aComponents['b']->__toString()
33
);
34
return '#'.(($sResult[0] == $sResult[1]) && ($sResult[2] == $sResult[3]) && ($sResult[4] == $sResult[5]) ? "$sResult[0]$sResult[2]$sResult[4]" : $sResult);
35
}
36
- return parent::__toString();
37
}
38
}
22
}
23
24
public function __toString() {
25
+ return $this->render(new \Sabberworm\CSS\OutputFormat());
26
+ }
27
+
28
+ public function render(\Sabberworm\CSS\OutputFormat $oOutputFormat) {
29
// Shorthand RGB color values
30
+ if($oOutputFormat->getRGBHashNotation() && implode('', array_keys($this->aComponents)) === 'rgb') {
31
$sResult = sprintf(
32
'%02x%02x%02x',
33
+ $this->aComponents['r']->getSize(),
34
+ $this->aComponents['g']->getSize(),
35
+ $this->aComponents['b']->getSize()
36
);
37
return '#'.(($sResult[0] == $sResult[1]) && ($sResult[2] == $sResult[3]) && ($sResult[4] == $sResult[5]) ? "$sResult[0]$sResult[2]$sResult[4]" : $sResult);
38
}
39
+ return parent::render($oOutputFormat);
40
}
41
}
includes/PHP-CSS-Parser/lib/Sabberworm/CSS/Value/Size.php CHANGED
@@ -5,7 +5,7 @@ namespace Sabberworm\CSS\Value;
5
class Size extends PrimitiveValue {
6
7
const ABSOLUTE_SIZE_UNITS = 'px/cm/mm/mozmm/in/pt/pc/vh/vw/vm/vmin/vmax/rem'; //vh/vw/vm(ax)/vmin/rem are absolute insofar as they don’t scale to the immediate parent (only the viewport)
8
- const RELATIVE_SIZE_UNITS = '%/em/ex/ch';
9
const NON_SIZE_UNITS = 'deg/grad/rad/s/ms/turns/Hz/kHz';
10
11
private $fSize;
@@ -60,6 +60,10 @@ class Size extends PrimitiveValue {
60
}
61
62
public function __toString() {
63
$l = localeconv();
64
$sPoint = preg_quote($l['decimal_point'], '/');
65
return preg_replace(array("/$sPoint/", "/^(-?)0\./"), array('.', '$1.'), $this->fSize) . ($this->sUnit === null ? '' : $this->sUnit);
5
class Size extends PrimitiveValue {
6
7
const ABSOLUTE_SIZE_UNITS = 'px/cm/mm/mozmm/in/pt/pc/vh/vw/vm/vmin/vmax/rem'; //vh/vw/vm(ax)/vmin/rem are absolute insofar as they don’t scale to the immediate parent (only the viewport)
8
+ const RELATIVE_SIZE_UNITS = '%/em/ex/ch/fr';
9
const NON_SIZE_UNITS = 'deg/grad/rad/s/ms/turns/Hz/kHz';
10
11
private $fSize;
60
}
61
62
public function __toString() {
63
+ return $this->render(new \Sabberworm\CSS\OutputFormat());
64
+ }
65
+
66
+ public function render(\Sabberworm\CSS\OutputFormat $oOutputFormat) {
67
$l = localeconv();
68
$sPoint = preg_quote($l['decimal_point'], '/');
69
return preg_replace(array("/$sPoint/", "/^(-?)0\./"), array('.', '$1.'), $this->fSize) . ($this->sUnit === null ? '' : $this->sUnit);
includes/PHP-CSS-Parser/lib/Sabberworm/CSS/Value/URL.php CHANGED
@@ -7,11 +7,11 @@ class URL extends PrimitiveValue {
7
8
private $oURL;
9
10
- public function __construct(String $oURL) {
11
$this->oURL = $oURL;
12
}
13
14
- public function setURL(String $oURL) {
15
$this->oURL = $oURL;
16
}
17
@@ -20,7 +20,11 @@ class URL extends PrimitiveValue {
20
}
21
22
public function __toString() {
23
- return "url({$this->oURL->__toString()})";
24
}
25
26
}
7
8
private $oURL;
9
10
+ public function __construct(CSSString $oURL) {
11
$this->oURL = $oURL;
12
}
13
14
+ public function setURL(CSSString $oURL) {
15
$this->oURL = $oURL;
16
}
17
20
}
21
22
public function __toString() {
23
+ return $this->render(new \Sabberworm\CSS\OutputFormat());
24
+ }
25
+
26
+ public function render(\Sabberworm\CSS\OutputFormat $oOutputFormat) {
27
+ return "url({$this->oURL->render($oOutputFormat)})";
28
}
29
30
}
includes/PHP-CSS-Parser/lib/Sabberworm/CSS/Value/Value.php CHANGED
@@ -2,7 +2,10 @@
2
3
namespace Sabberworm\CSS\Value;
4
5
- abstract class Value {
6
7
- public abstract function __toString();
8
}
2
3
namespace Sabberworm\CSS\Value;
4
5
+ use Sabberworm\CSS\Renderable;
6
7
+ abstract class Value implements Renderable {
8
+ //Methods are commented out because re-declaring them here is a fatal error in PHP < 5.3.9
9
+ //public abstract function __toString();
10
+ //public abstract function render(\Sabberworm\CSS\OutputFormat $oOutputFormat);
11
}
includes/PHP-CSS-Parser/lib/Sabberworm/CSS/Value/ValueList.php CHANGED
@@ -35,8 +35,12 @@ abstract class ValueList extends Value {
35
$this->sSeparator = $sSeparator;
36
}
37
38
- function __toString() {
39
- return implode($this->sSeparator, $this->aComponents);
40
}
41
42
}
35
$this->sSeparator = $sSeparator;
36
}
37
38
+ public function __toString() {
39
+ return $this->render(new \Sabberworm\CSS\OutputFormat());
40
+ }
41
+
42
+ public function render(\Sabberworm\CSS\OutputFormat $oOutputFormat) {
43
+ return $oOutputFormat->implode($oOutputFormat->spaceBeforeListArgumentSeparator($this->sSeparator) . $this->sSeparator . $oOutputFormat->spaceAfterListArgumentSeparator($this->sSeparator), $this->aComponents);
44
}
45
46
}
includes/ameArray.php ADDED
@@ -0,0 +1,11 @@
1
+ <?php
2
+
3
+ /**
4
+ * Array utility functions, a la Lodash.
5
+ */
6
+ class ameArray {
7
+ public static function get($array, $path, $default = null) {
8
+ //todo
9
+ return $default;
10
+ }
11
+ }
includes/editor-page.php CHANGED
@@ -9,6 +9,13 @@ $is_second_toolbar_visible = isset($_COOKIE['ame-show-second-toolbar']) && (intv
9
$is_compact_layout_enabled = isset($_COOKIE['ame-compact-layout']) && (intval($_COOKIE['ame-compact-layout']) === 1);
10
$is_multisite = is_multisite();
11
12
$icons = array(
13
'cut' => '/gnome-icon-theme/edit-cut-blue.png',
14
'copy' => '/gion/edit-copy.png',
@@ -47,13 +54,13 @@ if ( !apply_filters('admin_menu_editor_is_pro', false) ){
47
}
48
49
?>
50
- <div class="wrap">
51
- <?php echo '<', WPMenuEditor::$admin_heading_tag, '>'; ?>
52
<?php echo apply_filters('admin_menu_editor-self_page_title', 'Menu Editor'); ?>
53
- <a href="<?php echo esc_attr($editor_data['settings_page_url']); ?>" class="add-new-h2" id="ws_plugin_settings_button"
54
- title="Configure plugin settings">Settings</a>
55
<?php echo '</', WPMenuEditor::$admin_heading_tag, '>'; ?>
56
57
<?php
58
if ( !empty($_GET['message']) ){
59
if ( intval($_GET['message']) == 1 ){
@@ -68,7 +75,6 @@ $extrasDirectory = dirname(__FILE__) . '/../extras';
68
if ( apply_filters('admin_menu_editor_is_pro', false) ) {
69
include $extrasDirectory . '/menu-color-dialog.php';
70
include $extrasDirectory . '/copy-permissions-dialog.php';
71
- include $extrasDirectory . '/modules/visible-users/visible-users-template.php';
72
}
73
74
function ame_output_sort_buttons($icons) {
@@ -84,7 +90,7 @@ function ame_output_sort_buttons($icons) {
84
85
?>
86
87
- <div id='ws_menu_editor' class="<?php
88
if ( $is_compact_layout_enabled ) {
89
echo 'ws_compact_layout';
90
} else {
@@ -92,12 +98,7 @@ function ame_output_sort_buttons($icons) {
92
}
93
?>">
94
95
- <div id="ws_actor_selector_container">
96
- <ul id="ws_actor_selector" class="subsubsub" style="display: none;">
97
- <!-- Contents will be generated by JS -->
98
- </ul>
99
- <div class="clear"></div>
100
- </div>
101
102
<div>
103
@@ -246,7 +247,6 @@ function ame_output_sort_buttons($icons) {
246
<input type="hidden" name="data" id="ws_data" value="">
247
<input type="hidden" name="data_length" id="ws_data_length" value="">
248
<input type="hidden" name="selected_actor" id="ws_selected_actor" value="">
249
- <input type="hidden" name="visible_users" id="ws_visible_users_json" value="">
250
<input type="button" id='ws_save_menu' class="button-primary ws_main_button" value="Save Changes" />
251
</form>
252
@@ -394,23 +394,35 @@ function ame_output_sort_buttons($icons) {
394
//The rest of Dashicons. Some icons were manually removed as they wouldn't look good as menu icons.
395
$dashicons = array(
396
'admin-site', 'admin-home',
397
- 'align-center', 'align-left', 'align-none', 'align-right', 'analytics', 'art', 'awards', 'backup',
398
- 'book', 'book-alt', 'businessman', 'calendar', 'camera', 'cart', 'category', 'chart-area', 'chart-bar',
399
- 'chart-line', 'chart-pie', 'clock', 'cloud', 'desktop', 'dismiss', 'download', 'edit', 'editor-customchar',
400
'editor-distractionfree', 'editor-help', 'editor-insertmore',
401
'editor-justify', 'editor-kitchensink', 'editor-ol', 'editor-paste-text',
402
'editor-paste-word', 'editor-quote', 'editor-removeformatting', 'editor-rtl', 'editor-spellcheck',
403
'editor-ul', 'editor-unlink', 'editor-video',
404
- 'email', 'email-alt', 'exerpt-view', 'facebook', 'facebook-alt', 'feedback', 'flag', 'format-aside',
405
'format-audio', 'format-chat', 'format-gallery', 'format-image', 'format-quote', 'format-status',
406
- 'format-video', 'forms', 'googleplus', 'groups', 'hammer', 'id', 'id-alt', 'image-crop',
407
- 'image-flip-horizontal', 'image-flip-vertical', 'image-rotate-left', 'image-rotate-right', 'images-alt',
408
- 'images-alt2', 'info', 'leftright', 'lightbulb', 'list-view', 'location', 'location-alt', 'lock', 'marker',
409
- 'menu', 'migrate', 'minus', 'networking', 'no', 'no-alt', 'performance', 'plus', 'portfolio', 'post-status',
410
- 'pressthis', 'products', 'redo', 'rss', 'screenoptions', 'search', 'share', 'share-alt',
411
'share-alt2', 'share1', 'shield', 'shield-alt', 'slides', 'smartphone', 'smiley', 'sort', 'sos', 'star-empty',
412
- 'star-filled', 'star-half', 'tablet', 'tag', 'testimonial', 'translation', 'twitter', 'undo',
413
- 'update', 'upload', 'vault', 'video-alt', 'video-alt2', 'video-alt3', 'visibility', 'welcome-add-page',
414
'welcome-comments', 'welcome-learn-more', 'welcome-view-site', 'welcome-widgets-menus', 'welcome-write-blog',
415
'wordpress', 'wordpress-alt', 'yes'
416
);
@@ -557,8 +569,3 @@ if ( apply_filters('admin_menu_editor_is_pro', false) ) {
557
var defaultMenu = <?php echo $editor_data['default_menu_js']; ?>;
558
var customMenu = <?php echo $editor_data['custom_menu_js']; ?>;
559
</script>
560
-
561
- <?php
562
-
563
- //Let the Pro version script output it's extra HTML & scripts.
564
- do_action('admin_menu_editor-footer');
9
$is_compact_layout_enabled = isset($_COOKIE['ame-compact-layout']) && (intval($_COOKIE['ame-compact-layout']) === 1);
10
$is_multisite = is_multisite();
11
12
+ $wrap_classes = array('wrap');
13
+ if ( $is_pro_version ) {
14
+ $wrap_classes[] = 'ame-is-pro-version';
15
+ } else {
16
+ $wrap_classes[] = 'ame-is-free-version';
17
+ }
18
+
19
$icons = array(
20
'cut' => '/gnome-icon-theme/edit-cut-blue.png',
21
'copy' => '/gion/edit-copy.png',
54
}
55
56
?>
57
+ <div class="<?php echo esc_attr(implode(' ', $wrap_classes)); ?>">
58
+ <?php echo '<', WPMenuEditor::$admin_heading_tag, ' id="ws_ame_editor_heading">'; ?>
59
<?php echo apply_filters('admin_menu_editor-self_page_title', 'Menu Editor'); ?>
60
<?php echo '</', WPMenuEditor::$admin_heading_tag, '>'; ?>
61
62
+ <?php do_action('admin_menu_editor-display_tabs'); ?>
63
+
64
<?php
65
if ( !empty($_GET['message']) ){
66
if ( intval($_GET['message']) == 1 ){
75
if ( apply_filters('admin_menu_editor_is_pro', false) ) {
76
include $extrasDirectory . '/menu-color-dialog.php';
77
include $extrasDirectory . '/copy-permissions-dialog.php';
78
}
79
80
function ame_output_sort_buttons($icons) {
90
91
?>
92
93
+ <div id='ws_menu_editor' style="visibility: hidden;" class="<?php
94
if ( $is_compact_layout_enabled ) {
95
echo 'ws_compact_layout';
96
} else {
98
}
99
?>">
100
101
+ <?php include dirname(__FILE__) . '/../modules/actor-selector/actor-selector-template.php'; ?>
102
103
<div>
104
247
<input type="hidden" name="data" id="ws_data" value="">
248
<input type="hidden" name="data_length" id="ws_data_length" value="">
249
<input type="hidden" name="selected_actor" id="ws_selected_actor" value="">
250
<input type="button" id='ws_save_menu' class="button-primary ws_main_button" value="Save Changes" />
251
</form>
252
394
//The rest of Dashicons. Some icons were manually removed as they wouldn't look good as menu icons.
395
$dashicons = array(
396
'admin-site', 'admin-home',
397
+ 'album', 'align-center', 'align-left', 'align-none', 'align-right',
398
+ 'analytics', 'archive', 'art', 'awards', 'backup', 'book', 'book-alt',
399
+ 'building', 'businessman', 'calendar', 'calendar-alt', 'camera', 'carrot',
400
+ 'cart', 'category', 'chart-area', 'chart-bar', 'chart-line', 'chart-pie',
401
+ 'clipboard', 'clock', 'cloud', 'desktop', 'dismiss', 'download', 'edit', 'editor-code', 'editor-contract', 'editor-customchar',
402
'editor-distractionfree', 'editor-help', 'editor-insertmore',
403
'editor-justify', 'editor-kitchensink', 'editor-ol', 'editor-paste-text',
404
'editor-paste-word', 'editor-quote', 'editor-removeformatting', 'editor-rtl', 'editor-spellcheck',
405
'editor-ul', 'editor-unlink', 'editor-video',
406
+ 'email', 'email-alt', 'exerpt-view', 'external', 'facebook',
407
+ 'facebook-alt', 'feedback', 'filter', 'flag', 'format-aside',
408
'format-audio', 'format-chat', 'format-gallery', 'format-image', 'format-quote', 'format-status',
409
+ 'format-video', 'forms', 'googleplus', 'grid-view', 'groups',
410
+ 'hammer', 'heart', 'hidden', 'id', 'id-alt', 'image-crop', 'image-filter',
411
+ 'image-flip-horizontal', 'image-flip-vertical', 'image-rotate',
412
+ 'image-rotate-left', 'image-rotate-right', 'images-alt',
413
+ 'images-alt2', 'index-card', 'info', 'leftright', 'lightbulb', 'list-view',
414
+ 'location', 'location-alt', 'lock', 'marker',
415
+ 'media-archive', 'media-audio', 'media-code', 'media-default', 'media-video', 'megaphone',
416
+ 'menu', 'microphone', 'migrate', 'minus', 'money', 'nametag', 'networking', 'no',
417
+ 'no-alt', 'palmtree', 'performance', 'phone', 'playlist-audio',
418
+ 'playlist-video', 'plus', 'plus-alt', 'portfolio', 'post-status', 'post-trash',
419
+ 'pressthis', 'products', 'redo', 'rss', 'schedule',
420
+ 'screenoptions', 'search', 'share', 'share-alt',
421
'share-alt2', 'share1', 'shield', 'shield-alt', 'slides', 'smartphone', 'smiley', 'sort', 'sos', 'star-empty',
422
+ 'star-filled', 'star-half', 'sticky', 'store', 'tablet', 'tag',
423
+ 'tagcloud', 'testimonial', 'text', 'thumbs-down', 'thumbs-up', 'translation', 'twitter', 'undo',
424
+ 'universal-access', 'universal-access-alt', 'unlock',
425
+ 'update', 'upload', 'vault', 'video-alt', 'video-alt2', 'video-alt3', 'visibility', 'warning', 'welcome-add-page',
426
'welcome-comments', 'welcome-learn-more', 'welcome-view-site', 'welcome-widgets-menus', 'welcome-write-blog',
427
'wordpress', 'wordpress-alt', 'yes'
428
);
569
var defaultMenu = <?php echo $editor_data['default_menu_js']; ?>;
570
var customMenu = <?php echo $editor_data['custom_menu_js']; ?>;
571
</script>
includes/generate-menu-dashicons.php CHANGED
@@ -49,7 +49,7 @@ foreach($blocks as $block) {
49
foreach($rules as $rule) {
50
/** @var Sabberworm\CSS\Rule\Rule $rule */
51
$value = $rule->getValue();
52
- if ($value instanceof Sabberworm\CSS\Value\String) {
53
//The parser defaults to UTF-8. Convert the char to a hexadecimal escape code
54
//so we don't have to worry about our CSS charset.
55
$char = ltrim(bin2hex(iconv('UTF-8', 'UCS-4', $value->getString())), '0');
49
foreach($rules as $rule) {
50
/** @var Sabberworm\CSS\Rule\Rule $rule */
51
$value = $rule->getValue();
52
+ if ($value instanceof Sabberworm\CSS\Value\CSSString) {
53
//The parser defaults to UTF-8. Convert the char to a hexadecimal escape code
54
//so we don't have to worry about our CSS charset.
55
$char = ltrim(bin2hex(iconv('UTF-8', 'UCS-4', $value->getString())), '0');
includes/menu-editor-core.php CHANGED
@@ -92,6 +92,16 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
92
*/
93
private $menu_url_blacklist = array();
94
95
function init(){
96
$this->sitewide_options = true;
97
@@ -172,6 +182,10 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
172
//BuddyPress 2.3.4
173
'index.php?page=bp-about' => true,
174
'index.php?page=bp-credits' => true,
175
);
176
177
//AJAXify screen options
@@ -216,6 +230,25 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
216
add_action('deleted_user_meta', array($this, 'clear_user_role_cache'), 10, 2);
217
//There's also a "set_user_role" hook, but it's only called by WP_User::set_role and not WP_User::add_role.
218
//It's also redundant - WP_User::set_role updates user meta, so the above hooks already cover it.
219
}
220
221
function init_finish() {
@@ -312,7 +345,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
312
apply_filters('admin_menu_editor-self_menu_title', 'Menu Editor'),
313
apply_filters('admin_menu_editor-capability', 'manage_options'),
314
'menu_editor',
315
- array(&$this, 'page_menu_editor')
316
);
317
//Output our JS & CSS on that page only
318
add_action("admin_print_scripts-$page", array($this, 'enqueue_scripts'), 1);
@@ -332,6 +365,9 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
332
333
//Make a placeholder for our screen options (hacky)
334
add_meta_box("ws-ame-screen-options", "[AME placeholder]", '__return_false', $page);
335
}
336
337
//Store the "original" menus for later use in the editor
@@ -350,7 +386,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
350
}
351
352
//Generate item templates from the default menu.
353
- $templateBuilder = new AmeMenuTemplateBuilder();
354
$this->item_templates = $templateBuilder->build(
355
$this->default_wp_menu,
356
$this->default_wp_submenu,
@@ -572,11 +608,18 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
572
//jQuery Form plugin. This is a more recent version than the one included with WP.
573
wp_register_auto_versioned_script('ame-jquery-form', plugins_url('js/jquery.form.js', $this->plugin_file), array('jquery'));
574
//jQuery cookie plugin
575
- wp_register_auto_versioned_script('jquery-cookie', plugins_url('js/jquery.cookie.js', $this->plugin_file), array('jquery'));
576
577
//Lodash library
578
wp_register_auto_versioned_script('ame-lodash', plugins_url('js/lodash.min.js', $this->plugin_file));
579
580
//Modules
581
wp_register_auto_versioned_script(
582
'ame-access-editor',
@@ -592,7 +635,8 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
592
'jquery', 'jquery-ui-sortable', 'jquery-ui-dialog', 'jquery-ui-tabs',
593
'ame-jquery-form', 'jquery-ui-droppable', 'jquery-qtip',
594
'jquery-sort', 'jquery-json', 'jquery-cookie',
595
- 'wp-color-picker', 'ame-lodash', 'ame-access-editor',
596
);
597
wp_register_auto_versioned_script(
598
'menu-editor',
@@ -600,27 +644,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
600
apply_filters('admin_menu_editor-editor_script_dependencies', $editor_dependencies)
601
);
602
603
- //Add only certain scripts to the settings sub-section.
604
- if ( $this->is_settings_page() ) {
605
- wp_enqueue_script('jquery-qtip');
606
- return;
607
- }
608
-
609
- //Add all scripts to our editor page, but not the settings sub-section
610
- //that shares the same page slug. Some of the scripts would crash otherwise.
611
- if ( !$this->is_editor_page() ) {
612
- return;
613
- }
614
-
615
- wp_enqueue_script('menu-editor');
616
-
617
- //We use WordPress media uploader to let the user upload custom menu icons (WP 3.5+).
618
- if ( function_exists('wp_enqueue_media') ) {
619
- wp_enqueue_media();
620
- }
621
-
622
- //Remove the default jQuery Form plugin to prevent conflicts with our custom version.
623
- wp_dequeue_script('jquery-form');
624
625
//Actors (roles and users) are used in the permissions UI, so we need to pass them along.
626
$actors = array();
@@ -666,14 +690,39 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
666
//Compatibility workaround: Get the real roles of the current user even if other plugins corrupt the list.
667
$users[$current_user->get('user_login')]['roles'] = array_values($this->get_user_roles($current_user));
668
669
- //Keep only those visible users that were successfully loaded.
670
- //(array_values reindexes the array and gets rid of gaps.)
671
- $visible_users = array_values(array_intersect($visible_users, array_keys($users)));
672
673
- $actors['user:' . $current_user->get('user_login')] = sprintf(
674
- 'Current user (%s)',
675
- $current_user->get('user_login')
676
- );
677
678
$showExtraIcons = (boolean)$this->options['show_extra_icons'];
679
if ( isset($_COOKIE['ame-show-extra-icons']) && is_numeric($_COOKIE['ame-show-extra-icons']) ) {
@@ -709,11 +758,8 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
709
'embeddedPageTemplateId' => ameMenuItem::embeddedPageTemplateId,
710
711
'actors' => $actors,
712
- 'roles' => $roles,
713
- 'users' => $users,
714
'currentUserLogin' => $current_user->get('user_login'),
715
'selectedActor' => isset($this->get['selected_actor']) ? strval($this->get['selected_actor']) : null,
716
- 'visibleUsers' => $visible_users,
717
718
'postTypes' => $this->get_post_type_details(),
719
'taxonomies' => $this->get_taxonomy_details(),
@@ -863,6 +909,8 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
863
$scheme = $this->options['ui_colour_scheme'];
864
wp_enqueue_style('menu-editor-colours-' . $scheme);
865
wp_enqueue_style('wp-color-picker');
866
}
867
868
/**
@@ -1006,21 +1054,21 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
1006
'defaults' => $unclickableDefaults,
1007
);
1008
1009
- $templates[ameMenuItem::embeddedPageTemplateId] = array(
1010
- 'name' => '< Embed WP page >',
1011
- 'used' => true,
1012
- 'defaults' => array_merge(
1013
- $itemDefaults,
1014
- array(
1015
- 'file' => '#automatically-generated',
1016
- 'url' => '#automatically-generated',
1017
- 'menu_title' => 'Embedded Page',
1018
- 'page_heading' => ameMenuItem::embeddedPagePlaceholderHeading,
1019
)
1020
- )
1021
- );
1022
1023
- if ( $this->is_pro_version() ) {
1024
//The Pro version has a [wp-logout-url] shortcode. Lets make it easier o use
1025
//by adding it to the "Target page" dropdown.
1026
$logoutDefaults = array_merge(
@@ -1185,8 +1233,8 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
1185
$positions_by_template[$template_id] = ameMenuItem::get($entry, 'position', 0);
1186
1187
//Add the new entry to the menu tree
1188
- if ( !empty($template['defaults']['parent']) ) {
1189
- if (isset($tree[$template['defaults']['parent']])) {
1190
//Okay, insert the item.
1191
$tree[$template['defaults']['parent']]['items'][] = $entry;
1192
} else {
@@ -1200,7 +1248,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
1200
1201
//Move orphaned items back to their original parents.
1202
foreach($orphans as $item) {
1203
- $defaultParent = !empty($item['defaults']['parent']) ? $item['defaults']['parent'] : null;
1204
if ( isset($defaultParent) && isset($tree[$defaultParent]) ) {
1205
$tree[$defaultParent]['items'][] = $item;
1206
} else {
@@ -1441,7 +1489,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
1441
* @return array Menu item in the internal format.
1442
*/
1443
private function prepare_for_output($item, $item_type = 'menu', $parent = array()) {
1444
- $parent_file = isset($parent['file']) ? $parent['file'] : '';
1445
1446
// Special case : plugin pages that have been moved from a sub-menu to a different
1447
// menu or the top level. We'll need to adjust the file field to point to the correct URL.
@@ -1494,6 +1542,9 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
1494
}
1495
}
1496
1497
//Apply defaults & filters
1498
$item = ameMenuItem::apply_defaults($item);
1499
$item = ameMenuItem::apply_filters($item, $item_type, $parent_file); //may cause side-effects
@@ -1531,7 +1582,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
1531
1532
//Used later to determine the current page based on URL.
1533
if ( empty($item['url']) ) {
1534
- $original_parent = !empty($item['defaults']['parent']) ? $item['defaults']['parent'] : $parent_file;
1535
$item['url'] = ameMenuItem::generate_url($item['file'], $original_parent);
1536
}
1537
@@ -1550,7 +1601,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
1550
}
1551
1552
//WPML support: Use translated menu titles where available.
1553
- if ( !$item['separator'] && function_exists('icl_t') ) {
1554
$item['menu_title'] = icl_t(
1555
self::WPML_CONTEXT,
1556
$this->get_wpml_name_for($item, 'menu_title'),
@@ -1674,7 +1725,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
1674
}
1675
1676
$action = isset($this->post['action']) ? $this->post['action'] : (isset($this->get['action']) ? $this->get['action'] : '');
1677
- do_action('admin_menu_editor-header', $action);
1678
1679
if ( !empty($action) ) {
1680
$this->handle_form_submission($this->post, $action);
@@ -1692,14 +1743,19 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
1692
}
1693
}
1694
1695
- $sub_section = isset($this->get['sub_section']) ? $this->get['sub_section'] : null;
1696
- if ( $sub_section === 'settings' ) {
1697
$this->display_plugin_settings_ui();
1698
- } else if ($sub_section == 'generate-menu-dashicons') {
1699
require dirname(__FILE__) . '/generate-menu-dashicons.php';
1700
- } else {
1701
$this->display_editor_ui();
1702
}
1703
}
1704
1705
private function handle_form_submission($post, $action = '') {
@@ -1745,15 +1801,6 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
1745
//Save the custom menu
1746
$this->set_custom_menu($menu);
1747
1748
- //Save the list of visible users.
1749
- if ( isset($this->post['visible_users']) && is_string($this->post['visible_users']) ) {
1750
- $visible_users = json_decode($this->post['visible_users']);
1751
- if ( is_array($visible_users) ) {
1752
- $this->options['visible_users'] = array_unique(array_map('strval', $visible_users));
1753
- $this->save_options();
1754
- }
1755
- }
1756
-
1757
//Redirect back to the editor and display the success message.
1758
//Also, automatically select the last selected actor (convenience feature).
1759
$query = array('message' => 1);
@@ -1917,6 +1964,24 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
1917
require dirname(__FILE__) . '/editor-page.php';
1918
}
1919
1920
/**
1921
* Display the plugin settings page.
1922
*/
@@ -1949,7 +2014,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
1949
protected function is_editor_page() {
1950
return is_admin()
1951
&& isset($this->get['page']) && ($this->get['page'] == 'menu_editor')
1952
- && ( !isset($this->get['sub_section']) || empty($this->get['sub_section']) );
1953
}
1954
1955
/**
@@ -1959,7 +2024,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
1959
*/
1960
protected function is_settings_page() {
1961
return is_admin()
1962
- && isset($this->get['sub_section']) && ($this->get['sub_section'] == 'settings')
1963
&& isset($this->get['page']) && ($this->get['page'] == 'menu_editor');
1964
}
1965
@@ -2009,6 +2074,12 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
2009
2010
if ( $item['template_id'] !== '' ) {
2011
$required_cap = ameMenuItem::get($item, 'access_level');
2012
foreach ($item['grant_access'] as $grant => $has_access) {
2013
if ( $has_access ) {
2014
if ( !isset($caps[$grant]) ) {
@@ -2039,6 +2110,15 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
2039
return $array1;
2040
}
2041
2042
/**
2043
* Create a virtual 'super_admin' capability that only super admins have.
2044
* This function accomplishes that by by filtering 'user_has_cap' calls.
@@ -2251,6 +2331,11 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
2251
return false;
2252
}
2253
2254
if ( $this->user_cap_cache_enabled && isset($this->cached_user_caps[$capability]) ) {
2255
return $this->cached_user_caps[$capability];
2256
}
@@ -2581,12 +2666,30 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
2581
}
2582
}
2583
2584
public function enqueue_helper_scripts() {
2585
wp_enqueue_script(
2586
'ame-helper-script',
2587
plugins_url('js/admin-helpers.js', $this->plugin_file),
2588
- array('jquery'),
2589
- '20140312'
2590
);
2591
2592
//The helper script needs to know the custom page heading (if any) to apply it.
@@ -2626,6 +2729,16 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
2626
return null;
2627
}
2628
2629
2630
/**
2631
* Log a security-related message.
@@ -2697,7 +2810,7 @@ class WPMenuEditor extends MenuEd_ShadowPluginFramework {
2697
2698
/**
2699
* Prepare WPML translation strings for all menu and page titles
2700
- * in the specified menu.
2701
*
2702
* @param array $custom_menu
2703
* @return array Associative array of strings that can be translated, indexed by unique name.
@@ -3158,9 +3271,9 @@ class ameMenuTemplateBuilder {
3158
*
3159
* @param array $wpItem
3160
* @param int $position
3161
- * @param string $parent