Scroll Back To Top - Version 1.0

Version Description

  • Initial Release

=

Download this release

Release Info

Developer joesexton00
Plugin Icon wp plugin Scroll Back To Top
Version 1.0
Comparing to
See all releases

Version 1.0

Files changed (40) hide show
  1. assets/js/admin.js +24 -0
  2. assets/js/scroll-back-to-top.js +91 -0
  3. assets/lib/jquery-textfill/CHANGES.mkd +74 -0
  4. assets/lib/jquery-textfill/COPYING +20 -0
  5. assets/lib/jquery-textfill/Makefile +9 -0
  6. assets/lib/jquery-textfill/README.mkd +106 -0
  7. assets/lib/jquery-textfill/css/index.css +57 -0
  8. assets/lib/jquery-textfill/img/ChimpThinking.png +0 -0
  9. assets/lib/jquery-textfill/img/Computer2.png +0 -0
  10. assets/lib/jquery-textfill/img/ComputerGlare.png +0 -0
  11. assets/lib/jquery-textfill/index.html +38 -0
  12. assets/lib/jquery-textfill/jquery.textfill.js +149 -0
  13. assets/lib/jquery-textfill/jquery.textfill.min.js +17 -0
  14. assets/lib/jquery-textfill/js/index.js +13 -0
  15. assets/lib/jquery-textfill/js/tests.js +364 -0
  16. assets/lib/jquery-textfill/tests.html +17 -0
  17. assets/lib/jquery-textfill/textfill.jquery.json +35 -0
  18. assets/screenshot-1.png +0 -0
  19. assets/screenshot-2.png +0 -0
  20. assets/screenshot-3.png +0 -0
  21. assets/screenshot-4.png +0 -0
  22. assets/screenshot-5.png +0 -0
  23. controller/SBTT_AdminMenuController.php +48 -0
  24. controller/SBTT_FrontendController.php +283 -0
  25. framework/JmsAdminSettingsPage.php +959 -0
  26. framework/JmsBootstrap.php +178 -0
  27. framework/JmsController.php +420 -0
  28. framework/JmsUserOptionsCollection.php +234 -0
  29. framework/readme.md +3 -0
  30. model/SBTT_Options.php +261 -0
  31. readme.txt +77 -0
  32. scroll-back-to-top.php +12 -0
  33. view/dynamic-styles.php +94 -0
  34. view/framework/admin/partials/checkbox_input.php +22 -0
  35. view/framework/admin/partials/radio_input.php +23 -0
  36. view/framework/admin/partials/required_indicator.php +1 -0
  37. view/framework/admin/partials/text_input.php +22 -0
  38. view/framework/admin/partials/textarea_input.php +13 -0
  39. view/framework/admin/settings.php +45 -0
  40. view/scroll-button.php +9 -0
assets/js/admin.js ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function($){
2
+ $(function(){
3
+ sbttLoaded();
4
+ $('[name="scroll-back-to-top[label_type]"]').on('change', sbttLoaded);
5
+ });
6
+
7
+ function sbttLoaded(){
8
+ if($('[name="scroll-back-to-top[label_type]"]:checked').val() == 'text'){
9
+ $('[name="scroll-back-to-top[icon_size]"]').prop('disabled', true);
10
+ $('[name="scroll-back-to-top[label_text]"]').prop('disabled', false);
11
+ $('[name="scroll-back-to-top[font_size]"]').prop('disabled', false);
12
+ if(!$('[name="scroll-back-to-top[font_size]"]').val()){
13
+ $('[name="scroll-back-to-top[font_size]"]').val(12);
14
+ }
15
+ } else {
16
+ $('[name="scroll-back-to-top[icon_size]"]').prop('disabled', false);
17
+ $('[name="scroll-back-to-top[label_text]"]').prop('disabled', true);
18
+ $('[name="scroll-back-to-top[font_size]"]').prop('disabled', true);
19
+ if(!$('[name="scroll-back-to-top[icon_size]"]:checked').val()){
20
+ $('[name="scroll-back-to-top[icon_size]"][value="fa-2x"]').prop('checked', true);
21
+ }
22
+ }
23
+ }
24
+ })(jQuery);
assets/js/scroll-back-to-top.js ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function($){
2
+
3
+ $(function(){
4
+ if(typeof scrollBackToTop.autoFontSize !== 'undefined' && scrollBackToTop.autoFontSize){
5
+ $('.scroll-back-to-top-wrapper').textfill({ maxFontPixels: 36 });
6
+ }
7
+
8
+ $('.scroll-back-to-top-wrapper').on('click', function(){
9
+ if(typeof scrollBackToTop.scrollDuration !== 'undefined'){
10
+ scrollToElement("body", scrollBackToTop.scrollDuration, 0);
11
+ }
12
+ });
13
+
14
+ $(document).on( 'scroll', function(){
15
+
16
+ if ($(window).scrollTop() > 100) {
17
+ $('.scroll-back-to-top-wrapper').addClass('show');
18
+ } else {
19
+ $('.scroll-back-to-top-wrapper').removeClass('show');
20
+ }
21
+ });
22
+ });
23
+
24
+ function scrollToElement(selector, time, verticalOffset) {
25
+
26
+ time = typeof(time) != 'undefined' ? time : 1000;
27
+ verticalOffset = typeof(verticalOffset) != 'undefined' ? verticalOffset : 0;
28
+ element = $(selector);
29
+ offset = element.offset();
30
+ offsetTop = offset.top + verticalOffset;
31
+ $('html, body').animate({scrollTop: offsetTop}, parseInt(time), 'linear');
32
+ }
33
+
34
+ function isFullyVisible(el) {
35
+
36
+ if ( ! el.length ) {
37
+ return false;
38
+ }
39
+
40
+ if ( el instanceof jQuery ) {
41
+ el = el[0];
42
+ }
43
+
44
+ var top = el.offsetTop;
45
+ var left = el.offsetLeft;
46
+ var width = el.offsetWidth;
47
+ var height = el.offsetHeight;
48
+
49
+ while(el.offsetParent) {
50
+ el = el.offsetParent;
51
+ top += el.offsetTop;
52
+ left += el.offsetLeft;
53
+ }
54
+
55
+ return (
56
+ top >= window.pageYOffset &&
57
+ left >= window.pageXOffset &&
58
+ (top + height) <= (window.pageYOffset + window.innerHeight) &&
59
+ (left + width) <= (window.pageXOffset + window.innerWidth)
60
+ );
61
+ }
62
+
63
+ function isPartiallyVisible(el) {
64
+
65
+ if ( ! el.length ) {
66
+ return false;
67
+ }
68
+
69
+ if ( el instanceof jQuery ) {
70
+ el = el[0];
71
+ }
72
+
73
+ var top = el.offsetTop;
74
+ var left = el.offsetLeft;
75
+ var width = el.offsetWidth;
76
+ var height = el.offsetHeight;
77
+
78
+ while(el.offsetParent) {
79
+ el = el.offsetParent;
80
+ top += el.offsetTop;
81
+ left += el.offsetLeft;
82
+ }
83
+
84
+ return (
85
+ top < (window.pageYOffset + window.innerHeight) &&
86
+ left < (window.pageXOffset + window.innerWidth) &&
87
+ (top + height) > window.pageYOffset &&
88
+ (left + width) > window.pageXOffset
89
+ );
90
+ }
91
+ })(jQuery);
assets/lib/jquery-textfill/CHANGES.mkd ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ CHANGES
2
+ =======
3
+
4
+ ## Future
5
+
6
+ * drop `callback` callback
7
+
8
+ ## Development
9
+
10
+ ## Version 0.4.0 (2013-08-16T17:17:02Z)
11
+
12
+ * add tests for callbacks
13
+ * add `fail` callback (#15)
14
+ * deprecate `callback` callback with `success` callback
15
+ * fix `widthOnly` option (#4)
16
+
17
+ Height will not cause failure when `widthOnly` is set as long as width can fit into the container.
18
+
19
+ ## Version 0.3.5 (2013-05-08T00:40:22Z)
20
+
21
+ * merge patch for compatibility to ZeptoJS (by sagens42 #13)
22
+
23
+ ## Version 0.3.4 (2013-04-10T03:55:51Z)
24
+
25
+ * fix error when no console.debug.
26
+ * add test for debug flag.
27
+
28
+ ## Version 0.3.3 (2013-03-25T23:35:21Z)
29
+
30
+ * retag for including the manefest in the tag.
31
+
32
+ ## Version 0.3.2 (2013-02-09T02:43:32Z)
33
+
34
+ * fix introduced global variable fontSize by `_sizing()`
35
+ * fix container too small for bigger font size setting (#11)
36
+
37
+ ## Version 0.3.1 (2013-01-27T05:10:51Z)
38
+
39
+ * Add `debug` option.
40
+ * Fix a couple of bugs, they didn't size up as big as possible
41
+
42
+ ## Version 0.3 (2013-01-04T16:27:52Z)
43
+
44
+ * Allow to use *MaxFontPixels <= 0* to make sizing as big as possible.
45
+
46
+ ## Version 0.2.1 (2012-11-11T07:04:20Z)
47
+
48
+ * Add explicitWidth and explicitHeight options (#6)
49
+
50
+ ## Version 0.2 (2012-07-02T17:13:27Z)
51
+
52
+ * Fix resizing algorithm (#3)
53
+ * Add option widthOnly for header tags (#4)
54
+
55
+ ## Version 0.1.3 (2012-03-27T04:03:30Z)
56
+
57
+ * Add callbacks for each filled and all filled. (by alex-pex #2)
58
+
59
+ ## Version 0.1.2 (2012-01-29T12:46:12Z)
60
+
61
+ * Use binary search instead of plain do-while to accelerate the function.
62
+ (by acsaga #1)
63
+
64
+ ## Version 0.1.1
65
+
66
+ Add minFontPixels parameter
67
+
68
+ ## 2012-01-16T16:56:32Z
69
+
70
+ This project was moved to GitHub and licensed under the MIT License.
71
+
72
+ ## Version 0.1
73
+
74
+ Released in May 2009.
assets/lib/jquery-textfill/COPYING ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Copyright (c) 2012-2013 Yu-Jie Lin
2
+ Copyright (c) 2009 Russ Painter
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ this software and associated documentation files (the "Software"), to deal in
6
+ the Software without restriction, including without limitation the rights to
7
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8
+ of the Software, and to permit persons to whom the Software is furnished to do
9
+ so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
assets/lib/jquery-textfill/Makefile ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ all: jquery.textfill.min.js
2
+
3
+ jquery.textfill.min.js: jquery.textfill.js
4
+ curl --data output_info=compiled_code --data-urlencode js_code@jquery.textfill.js http://closure-compiler.appspot.com/compile > jquery.textfill.min.js
5
+
6
+ clean:
7
+ rm -f jquery.textfill.min.js
8
+
9
+ .PHONY: clean
assets/lib/jquery-textfill/README.mkd ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery TextFill
2
+ ===============
3
+
4
+ **[jQuery TextFill][index]** resizes text to fit into a container and makes font size as big as possible.
5
+
6
+ This jQuery plugin was created by Russ Painter around May 2009, beginning with a StackOverflow [question][soq]. In very early 2012, Yu-Jie Lin helped to move the project to GitHub with version 0.1 and obtained the clearly stated open source licensing from Russ.
7
+
8
+ [soq]: http://stackoverflow.com/questions/687998/auto-size-dynamic-text-to-fill-fixed-size-container
9
+ [index]: http://jquery-textfill.github.io/jquery-textfill/index.html
10
+
11
+ Usage
12
+ -----
13
+
14
+ ```html
15
+ <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
16
+ <script src="http://jquery-textfill.github.io/jquery-textfill/jquery.textfill.min.js"></script>
17
+ ```
18
+
19
+ The code above uses minified version. By default options, you need to put text inside of `<span/>`:
20
+
21
+ ```html
22
+ <div class='textfill' style='width:100px;height:50px;'>
23
+ <span>The quick brown fox jumps over the lazy dog</span>
24
+ </div>
25
+ ```
26
+
27
+ ### Initialization
28
+
29
+ ```js
30
+ $(selector).textfill(options);
31
+ ```
32
+
33
+ For example,
34
+
35
+ ```html
36
+ <script>
37
+ $(function(){
38
+ $('.textfill').textfill({ maxFontPixels: 36 });
39
+ });
40
+ </script>
41
+ ```
42
+
43
+ ### Options
44
+
45
+ Name | Description | Default
46
+ --- | --- | ---
47
+ `debug` | output debug message to console | `false`
48
+ `minFontPixels` | minimal font size | 4
49
+ `maxFontPixels` | sizing up the text as big as possible to this setting. For *size <= 0*, the text is sized to as big as the container can accommodate | 40
50
+ `innerTag` | the element tag to resize, select by `$(innerTag + ':visible:first', container)` | `span`
51
+ `success` | callback when a resizing is successful
52
+ `fail` | callback when a resizing is failed
53
+ `complete` | callback when all elements are done
54
+ `widthOnly` | only resizing for width restraint, this is intentionally used with CSS `white-space: nowrap` for header tags
55
+ `explicitWidth` | explicit width
56
+ `explicitHeight` | explicit height
57
+
58
+ Help and Support
59
+ ----------------
60
+
61
+ ### Reporting bug
62
+
63
+ When report a bug, please reproduce the bug using [Gist][] or [jsFiddle][] as a template. Environment can be different and some may be fine, some may be not. **Please make sure you can clearly demonstrate the bug** unless the bug is super easy to spot like `a < b` should be `a <= b`.
64
+
65
+ When reproduce a bug, it's important that CSS matches the page where you encounter the bug, it could be crucial that container's and innertag's styles have to be exactly the same.
66
+
67
+ Please also provide enough information about your system and browser, if necessary, here is a template:
68
+
69
+ TextFill version:
70
+ jQuery version:
71
+ Font family:
72
+ OS/Version:
73
+ Browser/Version:
74
+
75
+ Since TextFill 0.3.1, there is debugging option, can be enabled by `debug: true`, you can also include those messages.
76
+
77
+ [Gist]: https://gist.github.com/4650697
78
+ [jsFiddle]: http://jsfiddle.net/livibetter/3gMFG/
79
+
80
+ *If you can not provide a bug reprouction, then please do not report*, I could not fix something I can't see.
81
+
82
+ ### Contributing
83
+
84
+ You are very welcome to contribute whatever you can, but **please do not**:
85
+
86
+ * Update version number.
87
+ * Generate minified file.
88
+
89
+ These tasks are for releasing, contributors should not take on them.
90
+
91
+ Before you submit, make sure:
92
+
93
+ * Coding style generally matches.
94
+ * Pass all [tests][] previously have passed.
95
+ * *Optional* Update [`README`](README.mkd) if necessary.
96
+ * *Optional* Update [`CHANGES`](CHANGES.mkd) if worth mentioning.
97
+
98
+ [tests]: http://jquery-textfill.github.io/jquery-textfill/tests.html
99
+
100
+ License
101
+ -------
102
+
103
+ It is licensed under the MIT License, see [`COPYING`](COPYING) file.
104
+
105
+ Copyright (c) 2012-2013 Yu-Jie Lin
106
+ Copyright (c) 2009 Russ Painter
assets/lib/jquery-textfill/css/index.css ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ body {
2
+ background-color: #ddf;
3
+ }
4
+
5
+ #dyntext {
6
+ width: 400px;
7
+ }
8
+
9
+ .monkeythink {
10
+ position: relative;
11
+ float: left;
12
+ width: 200px;
13
+ height: 286px;
14
+ background-image: url("../img/ChimpThinking.png");
15
+ }
16
+
17
+ .monkeythink .jtextfill {
18
+ position: absolute;
19
+ top: 30px;
20
+ left: 20px;
21
+ width: 150px;
22
+ height: 70px;
23
+ background-color: #fff;
24
+ text-align: center;
25
+ }
26
+
27
+ .monkeythink .jtextfill span {
28
+ font-family: "Happy Monkey";
29
+ }
30
+
31
+ .computer {
32
+ position: relative;
33
+ float: right;
34
+ width: 450px;
35
+ height: 424px;
36
+ background-image: url("../img/Computer2.png");
37
+ }
38
+
39
+ .computer .jtextfill {
40
+ position: absolute;
41
+ top: 70px;
42
+ left: 85px;
43
+ width: 285px;
44
+ height: 210px;
45
+ color: #8f8;
46
+ }
47
+
48
+ .computer .jtextfill span {
49
+ font-family: "VT323";
50
+ }
51
+
52
+ .computerglare {
53
+ position: absolute;
54
+ width: 450px;
55
+ height: 424px;
56
+ background-image: url("../img/ComputerGlare.png");
57
+ }
assets/lib/jquery-textfill/img/ChimpThinking.png ADDED
Binary file
assets/lib/jquery-textfill/img/Computer2.png ADDED
Binary file
assets/lib/jquery-textfill/img/ComputerGlare.png ADDED
Binary file
assets/lib/jquery-textfill/index.html ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8"/>
5
+ <title>jQuery Plugin: Text Fill</title>
6
+ <link href='http://fonts.googleapis.com/css?family=VT323|Happy+Monkey' rel='stylesheet' type='text/css'/>
7
+ <link href="css/index.css" rel="stylesheet" type="text/css"/>
8
+ <script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
9
+ <script src="jquery.textfill.js" ></script>
10
+ <script src="js/index.js" ></script>
11
+ </head>
12
+
13
+ <body>
14
+ <div>
15
+ <h1>Example of TextFill jQuery Plugin</h1>
16
+ <div>
17
+ <label for="dyntext">What is monkey thinking?</label>
18
+ <input type="text" id="dyntext" value="e=mc²"></input>
19
+ </div>
20
+ <div>
21
+ <label for="maxsize">Maximal font size in pixels?</label>
22
+ <input type="text" id="maxsize" value="0"></input>
23
+ </div>
24
+ <hr />
25
+ <div class="monkeythink">
26
+ <div class="jtextfill">
27
+ <span class="dyntextval">e=mc²</span>
28
+ </div>
29
+ </div>
30
+ <div class="computer">
31
+ <div class="jtextfill">
32
+ <span class="dyntextval">e=mc²</span>
33
+ </div>
34
+ <div class="computerglare"></div>
35
+ </div>
36
+ </div>
37
+ </body>
38
+ </html>
assets/lib/jquery-textfill/jquery.textfill.js ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * @preserve textfill
3
+ * @name jquery.textfill.js
4
+ * @author Russ Painter
5
+ * @author Yu-Jie Lin
6
+ * @version 0.4.0
7
+ * @date 2013-08-16
8
+ * @copyright (c) 2012-2013 Yu-Jie Lin
9
+ * @copyright (c) 2009 Russ Painter
10
+ * @license MIT License
11
+ * @homepage https://github.com/jquery-textfill/jquery-textfill
12
+ * @example http://jquery-textfill.github.io/jquery-textfill/index.html
13
+ */
14
+ ; (function($) {
15
+ /**
16
+ * Resizes an inner element's font so that the inner element completely fills the outer element.
17
+ * @param {Object} Options which are maxFontPixels (default=40), innerTag (default='span')
18
+ * @return All outer elements processed
19
+ */
20
+ $.fn.textfill = function(options) {
21
+ var defaults = {
22
+ debug: false,
23
+ maxFontPixels: 40,
24
+ minFontPixels: 4,
25
+ innerTag: 'span',
26
+ widthOnly: false,
27
+ success: null, // callback when a resizing is done
28
+ callback: null, // callback when a resizing is done (deprecated, use success)
29
+ fail: null, // callback when a resizing is failed
30
+ complete: null, // callback when all is done
31
+ explicitWidth: null,
32
+ explicitHeight: null
33
+ };
34
+ var Opts = $.extend(defaults, options);
35
+
36
+ function _debug() {
37
+ if (!Opts.debug
38
+ || typeof console == 'undefined'
39
+ || typeof console.debug == 'undefined') {
40
+ return;
41
+ }
42
+
43
+ console.debug.apply(console, arguments);
44
+ }
45
+
46
+ function _warn() {
47
+ if (typeof console == 'undefined'
48
+ || typeof console.warn == 'undefined') {
49
+ return;
50
+ }
51
+
52
+ console.warn.apply(console, arguments);
53
+ }
54
+
55
+ function _debug_sizing(prefix, ourText, maxHeight, maxWidth, minFontPixels, maxFontPixels) {
56
+ function _m(v1, v2) {
57
+ var marker = ' / ';
58
+ if (v1 > v2) {
59
+ marker = ' > ';
60
+ } else if (v1 == v2) {
61
+ marker = ' = ';
62
+ }
63
+ return marker;
64
+ }
65
+
66
+ _debug(
67
+ prefix +
68
+ 'font: ' + ourText.css('font-size') +
69
+ ', H: ' + ourText.height() + _m(ourText.height(), maxHeight) + maxHeight +
70
+ ', W: ' + ourText.width() + _m(ourText.width() , maxWidth) + maxWidth +
71
+ ', minFontPixels: ' + minFontPixels +
72
+ ', maxFontPixels: ' + maxFontPixels
73
+ );
74
+ }
75
+
76
+ function _sizing(prefix, ourText, func, max, maxHeight, maxWidth, minFontPixels, maxFontPixels) {
77
+ _debug_sizing(prefix + ': ', ourText, maxHeight, maxWidth, minFontPixels, maxFontPixels);
78
+ while (minFontPixels < maxFontPixels - 1) {
79
+ var fontSize = Math.floor((minFontPixels + maxFontPixels) / 2)
80
+ ourText.css('font-size', fontSize);
81
+ if (func.call(ourText) <= max) {
82
+ minFontPixels = fontSize;
83
+ if (func.call(ourText) == max) {
84
+ break;
85
+ }
86
+ } else {
87
+ maxFontPixels = fontSize;
88
+ }
89
+ _debug_sizing(prefix + ': ', ourText, maxHeight, maxWidth, minFontPixels, maxFontPixels);
90
+ }
91
+ ourText.css('font-size', maxFontPixels);
92
+ if (func.call(ourText) <= max) {
93
+ minFontPixels = maxFontPixels;
94
+ _debug_sizing(prefix + '* ', ourText, maxHeight, maxWidth, minFontPixels, maxFontPixels);
95
+ }
96
+ return minFontPixels;
97
+ }
98
+
99
+ this.each(function() {
100
+ var ourText = $(Opts.innerTag + ':visible:first', this);
101
+ // Use explicit dimensions when specified
102
+ var maxHeight = Opts.explicitHeight || $(this).height();
103
+ var maxWidth = Opts.explicitWidth || $(this).width();
104
+ var oldFontSize = ourText.css('font-size');
105
+ var fontSize;
106
+
107
+ _debug('Opts: ', Opts);
108
+ _debug('Vars:' +
109
+ ' maxHeight: ' + maxHeight +
110
+ ', maxWidth: ' + maxWidth
111
+ );
112
+
113
+ var minFontPixels = Opts.minFontPixels;
114
+ var maxFontPixels = Opts.maxFontPixels <= 0 ? maxHeight : Opts.maxFontPixels;
115
+ var HfontSize = undefined;
116
+ if (!Opts.widthOnly) {
117
+ HfontSize = _sizing('H', ourText, $.fn.height, maxHeight, maxHeight, maxWidth, minFontPixels, maxFontPixels);
118
+ }
119
+ var WfontSize = _sizing('W', ourText, $.fn.width, maxWidth, maxHeight, maxWidth, minFontPixels, maxFontPixels);
120
+
121
+ if (Opts.widthOnly) {
122
+ ourText.css('font-size', WfontSize);
123
+ } else {
124
+ ourText.css('font-size', Math.min(HfontSize, WfontSize));
125
+ }
126
+ _debug('Final: ' + ourText.css('font-size'));
127
+
128
+ if (ourText.width() > maxWidth
129
+ || (ourText.height() > maxHeight && !Opts.widthOnly)
130
+ ) {
131
+ ourText.css('font-size', oldFontSize);
132
+ if (Opts.fail) {
133
+ Opts.fail(this);
134
+ }
135
+ } else if (Opts.success) {
136
+ Opts.success(this);
137
+ } else if (Opts.callback) {
138
+ _warn('callback is deprecated, use success, instead');
139
+ // call callback on each result
140
+ Opts.callback(this);
141
+ }
142
+ });
143
+
144
+ // call complete when all is complete
145
+ if (Opts.complete) Opts.complete(this);
146
+
147
+ return this;
148
+ };
149
+ })(window.jQuery);
assets/lib/jquery-textfill/jquery.textfill.min.js ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ textfill
3
+ @name jquery.textfill.js
4
+ @author Russ Painter
5
+ @author Yu-Jie Lin
6
+ @version 0.4.0
7
+ @date 2013-08-16
8
+ @copyright (c) 2012-2013 Yu-Jie Lin
9
+ @copyright (c) 2009 Russ Painter
10
+ @license MIT License
11
+ @homepage https://github.com/jquery-textfill/jquery-textfill
12
+ @example http://jquery-textfill.github.io/jquery-textfill/index.html
13
+ */
14
+ (function(e){e.fn.textfill=function(q){function m(){a.debug&&("undefined"!=typeof console&&"undefined"!=typeof console.debug)&&console.debug.apply(console,arguments)}function r(){"undefined"!=typeof console&&"undefined"!=typeof console.warn&&console.warn.apply(console,arguments)}function n(a,b,d,h,f,k){function c(a,b){var c=" / ";a>b?c=" > ":a==b&&(c=" = ");return c}m(a+"font: "+b.css("font-size")+", H: "+b.height()+c(b.height(),d)+d+", W: "+b.width()+c(b.width(),h)+h+", minFontPixels: "+f+", maxFontPixels: "+
15
+ k)}function p(a,b,d,h,f,k,c,l){for(n(a+": ",b,f,k,c,l);c<l-1;){var e=Math.floor((c+l)/2);b.css("font-size",e);if(d.call(b)<=h){if(c=e,d.call(b)==h)break}else l=e;n(a+": ",b,f,k,c,l)}b.css("font-size",l);d.call(b)<=h&&(c=l,n(a+"* ",b,f,k,c,l));return c}var a=e.extend({debug:!1,maxFontPixels:40,minFontPixels:4,innerTag:"span",widthOnly:!1,success:null,callback:null,fail:null,complete:null,explicitWidth:null,explicitHeight:null},q);this.each(function(){var g=e(a.innerTag+":visible:first",this),b=a.explicitHeight||
16
+ e(this).height(),d=a.explicitWidth||e(this).width(),h=g.css("font-size");m("Opts: ",a);m("Vars: maxHeight: "+b+", maxWidth: "+d);var f=a.minFontPixels,k=0>=a.maxFontPixels?b:a.maxFontPixels,c=void 0;a.widthOnly||(c=p("H",g,e.fn.height,b,b,d,f,k));f=p("W",g,e.fn.width,d,b,d,f,k);a.widthOnly?g.css("font-size",f):g.css("font-size",Math.min(c,f));m("Final: "+g.css("font-size"));g.width()>d||g.height()>b&&!a.widthOnly?(g.css("font-size",h),a.fail&&a.fail(this)):a.success?a.success(this):a.callback&&(r("callback is deprecated, use success, instead"),
17
+ a.callback(this))});a.complete&&a.complete(this);return this}})(window.jQuery);
assets/lib/jquery-textfill/js/index.js ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ function update() {
2
+ var size = parseInt($('#maxsize').val(), 10);
3
+ if (!isNaN(size)) {
4
+ $('.dyntextval').html($('#dyntext').val());
5
+ $('.jtextfill').textfill({debug: true, maxFontPixels: size});
6
+ }
7
+ }
8
+
9
+ $(function () {
10
+ $('#maxsize').keyup(update);
11
+ $('#dyntext').keyup(update);
12
+ update()
13
+ });
assets/lib/jquery-textfill/js/tests.js ADDED
@@ -0,0 +1,364 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var JTF = 'jtf';
2
+
3
+
4
+ function setup(opts) {
5
+ var $t = $('#qunit-fixture');
6
+ var $d = $('<div/>', opts.div).appendTo($t);
7
+ var $s = $('<span/>', opts.span).appendTo($d);
8
+ }
9
+
10
+
11
+ test('capped at 10px', function () {
12
+ setup({
13
+ div: {
14
+ id: JTF,
15
+ width: 285,
16
+ height: 210
17
+ },
18
+ span: {
19
+ css: {
20
+ 'font-family': 'VT323',
21
+ },
22
+ text: 'test'
23
+ }
24
+ });
25
+
26
+ var $jtf = $('#' + JTF);
27
+ var $span = $jtf.find('span');
28
+ $jtf.textfill({debug: true, maxFontPixels: 10});
29
+ equal($span.css('font-size'), '10px');
30
+ });
31
+
32
+
33
+ test('size up to max', function () {
34
+ setup({
35
+ div: {
36
+ id: JTF,
37
+ width: 285,
38
+ height: 210
39
+ },
40
+ span: {
41
+ css: {
42
+ 'font-family': 'VT323',
43
+ },
44
+ text: 'test'
45
+ }
46
+ });
47
+
48
+ var $jtf = $('#' + JTF);
49
+ var $span = $jtf.find('span');
50
+ $jtf.textfill({debug: true, maxFontPixels: 0});
51
+ equal($span.css('font-size'), '172px');
52
+ });
53
+
54
+
55
+ test('width be maxWidth', function () {
56
+ setup({
57
+ div: {
58
+ id: JTF,
59
+ width: 196,
60
+ height: 210
61
+ },
62
+ span: {
63
+ css: {
64
+ 'font-family': 'VT323',
65
+ },
66
+ text: 'test'
67
+ }
68
+ });
69
+
70
+ var $jtf = $('#' + JTF);
71
+ var $span = $jtf.find('span');
72
+ $jtf.textfill({debug: true, maxFontPixels: 0});
73
+ equal($span.css('font-size'), '119px');
74
+ });
75
+
76
+
77
+ test('height be maxHeight', function () {
78
+ setup({
79
+ div: {
80
+ id: JTF,
81
+ width: 285,
82
+ height: 158
83
+ },
84
+ span: {
85
+ css: {
86
+ 'font-family': 'VT323',
87
+ },
88
+ text: 'test'
89
+ }
90
+ });
91
+
92
+ var $jtf = $('#' + JTF);
93
+ var $span = $jtf.find('span');
94
+ $jtf.textfill({debug: true, maxFontPixels: 0});
95
+ equal($span.css('font-size'), '158px');
96
+ });
97
+
98
+
99
+ test('minFontPixels too big to fit in', function () {
100
+ setup({
101
+ div: {
102
+ id: JTF,
103
+ width: 40,
104
+ height: 40
105
+ },
106
+ span: {
107
+ css: {
108
+ 'font-family': 'VT323',
109
+ 'font-size': '20px',
110
+ },
111
+ text: 'test'
112
+ }
113
+ });
114
+
115
+ var $jtf = $('#' + JTF);
116
+ var $span = $jtf.find('span');
117
+ $jtf.textfill({debug: true, minFontPixels: 100, maxFontPixels: 0});
118
+ equal($span.css('font-size'), '20px');
119
+ });
120
+
121
+
122
+ test('minFontPixels too big to fit in, but widthOnly = True and width fits', function () {
123
+ // @ fontSize = 60 => H > 10, W = 100
124
+ setup({
125
+ div: {
126
+ id: JTF,
127
+ // just enough to fit in with minFontPixels
128
+ width: 100,
129
+ // H is busted, but widthOnly = True, so ignored
130
+ height: 10
131
+ },
132
+ span: {
133
+ css: {
134
+ 'font-family': 'VT323',
135
+ 'font-size': '20px',
136
+ },
137
+ text: 'test'
138
+ }
139
+ });
140
+
141
+ var $jtf = $('#' + JTF);
142
+ var $span = $jtf.find('span');
143
+ $jtf.textfill({
144
+ debug: true,
145
+ minFontPixels: 20,
146
+ maxFontPixels: 100,
147
+ widthOnly: true
148
+ });
149
+ equal($span.css('font-size'), '60px');
150
+ });
151
+
152
+
153
+ test('minFontPixels too big to fit in, W/H both fail, even widthOnly = True', function () {
154
+ setup({
155
+ div: {
156
+ id: JTF,
157
+ width: 10,
158
+ height: 10
159
+ },
160
+ span: {
161
+ css: {
162
+ 'font-family': 'VT323',
163
+ 'font-size': '20px',
164
+ },
165
+ text: 'test'
166
+ }
167
+ });
168
+
169
+ var $jtf = $('#' + JTF);
170
+ var $span = $jtf.find('span');
171
+ $jtf.textfill({
172
+ debug: true,
173
+ minFontPixels: 20,
174
+ maxFontPixels: 100,
175
+ widthOnly: true
176
+ });
177
+ equal($span.css('font-size'), '20px');
178
+ });
179
+
180
+
181
+ /*************/
182
+ /* callbacks */
183
+ /*************/
184
+
185
+ test('success callback', 1, function() {
186
+ setup({
187
+ div: {
188
+ id: JTF,
189
+ width: 285,
190
+ height: 210
191
+ },
192
+ span: {
193
+ css: {
194
+ 'font-family': 'VT323',
195
+ },
196
+ text: 'test'
197
+ }
198
+ });
199
+
200
+ var $jtf = $('#' + JTF);
201
+ var $span = $jtf.find('span');
202
+ $jtf.textfill({
203
+ debug: true,
204
+ maxFontPixels: 0,
205
+ success: function(e) {
206
+ equal(e, $jtf[0]);
207
+ }
208
+ });
209
+ });
210
+
211
+
212
+ test('callback callback (deprecated)', 1, function() {
213
+ setup({
214
+ div: {
215
+ id: JTF,
216
+ width: 285,
217
+ height: 210
218
+ },
219
+ span: {
220
+ css: {
221
+ 'font-family': 'VT323',
222
+ },
223
+ text: 'test'
224
+ }
225
+ });
226
+
227
+ var $jtf = $('#' + JTF);
228
+ var $span = $jtf.find('span');
229
+ $jtf.textfill({
230
+ debug: true,
231
+ maxFontPixels: 0,
232
+ callback: function(e) {
233
+ equal(e, $jtf[0]);
234
+ }
235
+ });
236
+ });
237
+
238
+
239
+ test('fail callback', 1, function () {
240
+ setup({
241
+ div: {
242
+ id: JTF,
243
+ width: 40,
244
+ height: 40
245
+ },
246
+ span: {
247
+ css: {
248
+ 'font-family': 'VT323',
249
+ 'font-size': '20px',
250
+ },
251
+ text: 'test'
252
+ }
253
+ });
254
+
255
+ var $jtf = $('#' + JTF);
256
+ var $span = $jtf.find('span');
257
+ $jtf.textfill({
258
+ debug: true,
259
+ minFontPixels: 100,
260
+ maxFontPixels: 0,
261
+ fail: function(e) {
262
+ equal(e, $jtf[0]);
263
+ }
264
+ });
265
+ });
266
+
267
+
268
+ test('complete callback', 2, function() {
269
+ setup({
270
+ div: {
271
+ id: JTF,
272
+ width: 285,
273
+ height: 210
274
+ },
275
+ span: {
276
+ css: {
277
+ 'font-family': 'VT323',
278
+ },
279
+ text: 'test'
280
+ }
281
+ });
282
+
283
+ var $jtf = $('#' + JTF);
284
+ $jtf.textfill({
285
+ debug: true,
286
+ maxFontPixels: 0,
287
+ callback: function(e) {
288
+ equal(e, $jtf[0]);
289
+ },
290
+ complete: function(e) {
291
+ equal(e, $jtf);
292
+ }
293
+ });
294
+ });
295
+
296
+
297
+ /****************/
298
+ /* debug option */
299
+ /****************/
300
+
301
+ module('debug option', {
302
+ setup: function () {
303
+ if (console.debug_original) {
304
+ throw 'console.debug_original already has value.';
305
+ }
306
+ console.debug_original = console.debug;
307
+ console.debug_called = false;
308
+ console.debug = function () {
309
+ console.debug_called = true;
310
+ }
311
+ },
312
+ teardown: function () {
313
+ if (!console.debug_original) {
314
+ throw 'console.debug_original is empty.';
315
+ }
316
+ console.debug = console.debug_original;
317
+ console.debug_original = undefined;
318
+ console.debug_called = undefined;
319
+ }
320
+ });
321
+
322
+
323
+ test('debug used', function () {
324
+ setup({
325
+ div: {
326
+ id: JTF,
327
+ width: 285,
328
+ height: 210
329
+ },
330
+ span: {
331
+ css: {
332
+ 'font-family': 'VT323',
333
+ },
334
+ text: 'test'
335
+ }
336
+ });
337
+
338
+ var $jtf = $('#' + JTF);
339
+ $jtf.textfill({debug: true, maxFontPixels: 10});
340
+ equal(console.debug_called, true);
341
+ });
342
+
343
+
344
+ test('debug not used', function () {
345
+ setup({
346
+ div: {
347
+ id: JTF,
348
+ width: 285,
349
+ height: 210
350
+ },
351
+ span: {
352
+ css: {
353
+ 'font-family': 'VT323',
354
+ },
355
+ text: 'test'
356
+ }
357
+ });
358
+
359
+ var $jtf = $('#' + JTF);
360
+ $jtf.textfill({debug: false, maxFontPixels: 10});
361
+ equal(console.debug_called, false);
362
+ });
363
+
364
+
assets/lib/jquery-textfill/tests.html ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8"/>
5
+ <title>Tests of jQuery Plugin: Text Fill</title>
6
+ <link href='http://fonts.googleapis.com/css?family=VT323' rel='stylesheet' type='text/css'/>
7
+ <link href='http://code.jquery.com/qunit/qunit-1.11.0.css' rel='stylesheet' type='text/css'/>
8
+ <script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
9
+ <script src='http://code.jquery.com/qunit/qunit-1.11.0.js'></script>
10
+ <script src='jquery.textfill.js'></script>
11
+ <script src='js/tests.js'></script>
12
+ </head>
13
+ <body>
14
+ <div id="qunit"></div>
15
+ <div id="qunit-fixture"></div>
16
+ </body>
17
+ </html>
assets/lib/jquery-textfill/textfill.jquery.json ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "textfill",
3
+ "version": "0.4.0",
4
+ "title": "jQuery TextFill",
5
+ "author": {
6
+ "name": "jQuery TextFill contributors",
7
+ "url": "https://github.com/jquery-textfill/jquery-textfill"
8
+ },
9
+ "licenses": [
10
+ {
11
+ "type": "MIT",
12
+ "url": "https://github.com/jquery-textfill/jquery-textfill/blob/master/COPYING"
13
+ }
14
+ ],
15
+ "dependencies": {
16
+ "jquery": "*"
17
+ },
18
+
19
+ "description": "Resizing text to fit into container.",
20
+ "keywords": [
21
+ "resize",
22
+ "text"
23
+ ],
24
+ "homepage": "https://github.com/jquery-textfill/jquery-textfill",
25
+ "docs": "https://github.com/jquery-textfill/jquery-textfill",
26
+ "demo": "http://jquery-textfill.github.io/jquery-textfill/index.html",
27
+ "bugs": "https://github.com/jquery-textfill/jquery-textfill/issues",
28
+ "maintainers": [
29
+ {
30
+ "name": "Yu-Jie Lin",
31
+ "email": "livibetter@gmail.com",
32
+ "url": "http://yjl.im"
33
+ }
34
+ ]
35
+ }
assets/screenshot-1.png ADDED
Binary file
assets/screenshot-2.png ADDED
Binary file
assets/screenshot-3.png ADDED
Binary file
assets/screenshot-4.png ADDED
Binary file
assets/screenshot-5.png ADDED
Binary file
controller/SBTT_AdminMenuController.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * SBTT Admin Menu Controller class
4
+ *
5
+ * @author Joe Sexton <joe@josephmsexton.com>
6
+ * @package WordPress
7
+ * @subpackage scroll-back-to-top
8
+ */
9
+ if ( !class_exists( 'SBTT_AdminMenuController' ) ){
10
+ class SBTT_AdminMenuController extends JmsAdminSettingsPage {
11
+
12
+ /**
13
+ * register Wordpress actions and filters
14
+ */
15
+ protected function _init() {
16
+
17
+ $options = new SBTT_Options();
18
+ $this->addOptionsPage(
19
+ __( 'Scroll Back to Top Settings', $this->textDomain() ),
20
+ __( 'Scroll Back to Top', $this->textDomain() ),
21
+ $options
22
+ );
23
+ }
24
+
25
+ /**
26
+ * enqueue admin scripts
27
+ */
28
+ public function enqueueAdminScripts() {
29
+
30
+ $this->enqueueScript( 'sbtt-admin', 'admin' );
31
+ }
32
+
33
+ /**
34
+ * enqueue admin styles
35
+ */
36
+ public function enqueueAdminStyles() {
37
+ $this->enqueueCdnStyle( 'font-awesome', '//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css' );
38
+ }
39
+
40
+ /**
41
+ * on plugin activation init default options
42
+ */
43
+ public function onActivation() {
44
+
45
+ $this->options->initDefaultOptions();
46
+ }
47
+ }
48
+ }
controller/SBTT_FrontendController.php ADDED
@@ -0,0 +1,283 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * SBTT Frontend Controller class
4
+ *
5
+ * @author Joe Sexton <joe@josephmsexton.com>
6
+ * @package WordPress
7
+ * @subpackage scroll-back-to-top
8
+ */
9
+ if ( !class_exists( 'SBTT_FrontEndController' ) ){
10
+ class SBTT_FrontEndController extends JmsController {
11
+
12
+ /**
13
+ * @var array
14
+ */
15
+ protected $args;
16
+
17
+ /**
18
+ * @var SBTT_Options
19
+ */
20
+ protected $options;
21
+
22
+ /**
23
+ * Register Wordpress actions and filters
24
+ */
25
+ protected function _init() {
26
+
27
+ $this->options = new SBTT_Options();
28
+ $this->args = $this->_getScrollButtonArgs();
29
+
30
+ $this->_preprocessArgs();
31
+
32
+ add_action('wp_head', array( $this, 'headSection' ) );
33
+ add_action('wp_footer', array( $this, 'footerSection' ) );
34
+ }
35
+
36
+ /**
37
+ * Enqueue scripts
38
+ *
39
+ * @return false if not enabled
40
+ */
41
+ public function enqueueScripts(){
42
+
43
+ if ( !$this->isAuthorized() ) {
44
+ return false;
45
+ }
46
+
47
+ $dependencies = array( 'jquery' );
48
+ $vars = array( 'scrollBackToTop' => array() );
49
+
50
+ if ( isset($this->args['scroll_duration']) ) {
51
+ $vars['scrollBackToTop']['scrollDuration'] = $this->args['scroll_duration'];
52
+ }
53
+
54
+ if ( isset($this->args['fade_duration']) ) {
55
+ $vars['scrollBackToTop']['fadeDuration'] = $this->args['fade_duration'];
56
+ }
57
+
58
+ // load textfill js only if using auto font sizing
59
+ if ( isset($this->args['label_type']) && isset($this->args['font_size']) && $this->args['font_size'] == '0px' ) {
60
+ $this->enqueueCdnScript('text-fill', 'http://jquery-textfill.github.io/jquery-textfill/jquery.textfill.min.js' );
61
+ $dependencies = array( 'jquery', 'text-fill' );
62
+ $vars['scrollBackToTop']['autoFontSize'] = true;
63
+ }
64
+
65
+ $this->enqueueScript( 'scroll-back-to-top', 'scroll-back-to-top', $dependencies, null, true, $vars );
66
+ }
67
+
68
+ /**
69
+ * Enqueue styles
70
+ *
71
+ * @return false if not enabled
72
+ */
73
+ public function enqueueStyles(){
74
+
75
+ if ( !$this->isAuthorized() ) {
76
+ return false;
77
+ }
78
+
79
+ // Only need the font pack if using icons, not text
80
+ if ( isset( $this->args['label_type'] ) && $this->args['label_type'] != 'text' ) {
81
+ $this->enqueueCdnStyle( 'font-awesome', '//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css' );
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Render head markup
87
+ *
88
+ * @return false if not enabled
89
+ */
90
+ public function headSection(){
91
+
92
+ if ( !$this->isAuthorized() ) {
93
+ return false;
94
+ }
95
+
96
+ echo apply_filters( 'sbtt_styles', $this->render( 'dynamic-styles', $this->args, false ) );
97
+ }
98
+
99
+ /**
100
+ * Render footer markup
101
+ *
102
+ * @return false if not enabled
103
+ */
104
+ public function footerSection(){
105
+
106
+ if ( !$this->isAuthorized() ) {
107
+ return false;
108
+ }
109
+
110
+ echo apply_filters( 'sbtt_button_markup', $this->render( 'scroll-button', $this->args, false ) );
111
+ }
112
+
113
+ /**
114
+ * Get options
115
+ *
116
+ * @return array
117
+ */
118
+ protected function _getScrollButtonArgs() {
119
+
120
+ return get_option( $this->options->optionsKey() );
121
+ }
122
+
123
+ /**
124
+ * Preprocess variables
125
+ */
126
+ protected function _preprocessArgs() {
127
+
128
+ $this->_processFade();
129
+ $this->_processHorizontalAlignment();
130
+ $this->_processVerticalAlignment();
131
+ $this->_processVerticalAlignment();
132
+ $this->_processBorderRadii();
133
+ $this->_processSize();
134
+ $this->_processOpacity();
135
+ $this->_processIconSize();
136
+ }
137
+
138
+ /**
139
+ * Process fade
140
+ */
141
+ protected function _processFade(){
142
+
143
+ if ( isset( $this->args['fade_duration'] ) ) {
144
+ $this->args['fade_duration'] = number_format( ( $this->args['fade_duration'] ) / 1000, 1 );
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Process horizontal alignment
150
+ */
151
+ protected function _processHorizontalAlignment(){
152
+
153
+ if ( isset( $this->args['align_x'] ) && isset( $this->args['margin_x'] )) {
154
+
155
+ if ( $this->args['align_x'] == 'right' ) {
156
+
157
+ $this->args['css_right'] = $this->args['margin_x'] . 'px';
158
+
159
+ } elseif ( $this->args['align_x'] == 'left' ) {
160
+
161
+ $this->args['css_left'] = $this->args['margin_x'] . 'px';
162
+
163
+ } elseif ( $this->args['align_x'] == 'center' ) {
164
+
165
+ $this->args['css_left'] = '50%';
166
+ $this->args['margin_left'] = isset( $this->args['size_w'] ) ? (string)( $this->args['size_w'] / -2 ) . 'px' : '0px';
167
+ }
168
+ }
169
+ }
170
+
171
+ /**
172
+ * Process vertical alignment
173
+ */
174
+ protected function _processVerticalAlignment(){
175
+
176
+ if ( isset( $this->args['align_y'] ) && isset( $this->args['margin_y'] )) {
177
+
178
+ if ( $this->args['align_y'] == 'bottom' ) {
179
+
180
+ $this->args['css_bottom'] = $this->args['margin_y'] . 'px';
181
+
182
+ } elseif ( $this->args['align_y'] == 'top' ) {
183
+
184
+ $this->args['css_top'] = $this->args['margin_y'] . 'px';
185
+
186
+ }
187
+ }
188
+ }
189
+
190
+ /**
191
+ * Process border radii
192
+ */
193
+ protected function _processBorderRadii(){
194
+
195
+ // Border Radius
196
+ // Because the button could be touching the edge of the screen,
197
+ // check that margin is greater than border radius for corners that touch.
198
+ if (
199
+ !isset( $this->args['border_radius'] ) ||
200
+ !isset( $this->args['align_x'] ) ||
201
+ !isset( $this->args['align_y'] ) ||
202
+ !isset( $this->args['margin_x'] ) ||
203
+ !isset( $this->args['margin_y'] )
204
+ ) {
205
+ return false;
206
+ }
207
+
208
+ $x_sides = array( 'left', 'right' );
209
+ $y_sides = array( 'top', 'bottom' );
210
+
211
+ foreach ( $x_sides as $x_side ) {
212
+ foreach ( $y_sides as $y_side ) {
213
+
214
+ if (
215
+ !( $this->args['align_x'] == $x_side && $this->args['margin_x'] == 0 ) && // touching left or right
216
+ !( $this->args['align_y'] == $y_side && $this->args['margin_y'] == 0 ) // touching top or bottom
217
+ ) {
218
+ $this->args["border_radius_{$y_side}_{$x_side}"] = (string)$this->args['border_radius'] . 'px';
219
+ }
220
+ }
221
+ }
222
+
223
+ return true;
224
+ }
225
+
226
+ /**
227
+ * Process size
228
+ */
229
+ protected function _processSize(){
230
+
231
+ if ( isset( $this->args['size_w'] ) ) {
232
+ $this->args['size_w'] = (string)$this->args['size_w'] . 'px';
233
+ }
234
+ if ( isset( $this->args['size_h'] ) ) {
235
+ $this->args['size_h'] = (string)($this->args['size_h'] - 2) . 'px';
236
+ $this->args['padding_top'] = '2px';
237
+ }
238
+ }
239
+
240
+ /**
241
+ * Process opacity
242
+ */
243
+ protected function _processOpacity(){
244
+
245
+ if ( isset( $this->args['opacity'] ) ) {
246
+ $this->args['opacity'] = number_format( ( $this->args['opacity'] ) / 100, 1 );
247
+ }
248
+ }
249
+
250
+ /**
251
+ * Process icon size
252
+ */
253
+ protected function _processIconSize(){
254
+
255
+ // Text size
256
+ if ( isset( $this->args['font_size'] ) ) {
257
+ $this->args['font_size'] = (string)$this->args['font_size'] . 'px';
258
+ }
259
+
260
+ // Default icon size
261
+ if ( !isset( $this->args['icon_size'] ) ) {
262
+ $this->args['icon_size'] = 'fa-2x';
263
+ }
264
+ }
265
+
266
+ /**
267
+ * Scroll button allowed right now?
268
+ *
269
+ * @return bool
270
+ */
271
+ public function isAuthorized(){
272
+
273
+ if ( isset( $this->args['enabled'] ) ) {
274
+ if ( $this->args['enabled'] == 'public' ) {
275
+ return true;
276
+ } elseif ( $this->args['enabled'] == 'preview' && is_user_logged_in() ) {
277
+ return true;
278
+ }
279
+ }
280
+ return false;
281
+ }
282
+
283
+ }}
framework/JmsAdminSettingsPage.php ADDED
@@ -0,0 +1,959 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Admin Settings Page class
4
+ * This is an abstract implementation of an admin menu settings page
5
+ *
6
+ * @author Joe Sexton <joe@josephmsexton.com>
7
+ * @package WordPress
8
+ * @subpackage JMS Plugin Framework
9
+ * @version 1.2
10
+ * @uses JmsController
11
+ * @uses JmsUserOptionsCollection
12
+ */
13
+ if ( !class_exists( 'JmsAdminSettingsPage' ) ){
14
+ abstract class JmsAdminSettingsPage extends JmsController {
15
+
16
+ /**
17
+ * @var string
18
+ */
19
+ protected $settingsPageTitle = '';
20
+
21
+ /**
22
+ * @var string
23
+ */
24
+ protected $settingsMenuTitle = '';
25
+
26
+ /**
27
+ * @var string
28
+ */
29
+ protected $settingsMenuSlug = '';
30
+
31
+ /**
32
+ * @var JmsUserOptionsCollection
33
+ */
34
+ protected $options = '';
35
+
36
+ /**
37
+ * @var string
38
+ */
39
+ protected $icon = '';
40
+
41
+ /**
42
+ * @var string
43
+ */
44
+ protected $menuPosition = null;
45
+
46
+ /**
47
+ * @var string
48
+ */
49
+ protected $manageSettingsCapability = 'manage_options';
50
+
51
+ /**
52
+ * settings page title
53
+ *
54
+ * @return string
55
+ */
56
+ public function settingsPageTitle() {
57
+
58
+ return $this->settingsPageTitle;
59
+ }
60
+
61
+ /**
62
+ * settings menu title
63
+ *
64
+ * @return string
65
+ */
66
+ public function settingsMenuTitle() {
67
+
68
+ return $this->settingsMenuTitle;
69
+ }
70
+
71
+ /**
72
+ * settings menu slug
73
+ *
74
+ * @return string
75
+ */
76
+ public function settingsMenuSlug() {
77
+
78
+ return $this->settingsMenuSlug;
79
+ }
80
+
81
+ /**
82
+ * manage settings capability
83
+ *
84
+ * @return string
85
+ */
86
+ public function manageSettingsCapability() {
87
+
88
+ return $this->manageSettingsCapability;
89
+ }
90
+
91
+ /**
92
+ * init admin settings page
93
+ *
94
+ * @param string $settingsPageTitle
95
+ * @param string $settingsMenuTitle
96
+ * @param JmsUserOptionsCollection $options
97
+ * @param string $menuMethod
98
+ */
99
+ protected function _initAdminSettingsPage( $settingsPageTitle, $settingsMenuTitle, JmsUserOptionsCollection $options, $menuMethod ){
100
+
101
+ add_action( 'admin_enqueue_scripts', array( $this, 'enqueueAdminSettingsPageScripts' ) );
102
+ add_action( 'admin_enqueue_scripts', array( $this, 'enqueueAdminSettingsPageStyles' ) );
103
+
104
+ add_action( 'admin_init', array( $this, 'registerSettings' ) );
105
+
106
+ $this->settingsPageTitle = $settingsPageTitle;
107
+ $this->settingsMenuTitle = $settingsMenuTitle;
108
+ $this->options = $options;
109
+
110
+ $this->settingsMenuSlug = sanitize_title( $settingsMenuTitle );
111
+
112
+ $actionName = $menuMethod . 'Action';
113
+ add_action( 'admin_menu', array( $this, $actionName ) );
114
+ }
115
+
116
+ /**
117
+ * enqueue admin settings page scripts
118
+ */
119
+ public function enqueueAdminSettingsPageScripts() {
120
+
121
+ wp_enqueue_script( 'jquery' );
122
+ wp_enqueue_script( 'wp-color-picker' );
123
+ }
124
+
125
+ /**
126
+ * enqueue admin settings page styles
127
+ */
128
+ public function enqueueAdminSettingsPageStyles() {
129
+
130
+ wp_enqueue_style( 'wp-color-picker' );
131
+ }
132
+
133
+ /**
134
+ * allows a user to call $this->addXxxxxPage( string $pageTitle, string $menuTitle, JmsUserOptionsCollection $options )
135
+ * internally handles calls like $this->addXxxxxPageAction() and adds the appropriate menu page
136
+ *
137
+ * @param string $method
138
+ * @param array $args
139
+ * @return boolean|void
140
+ */
141
+ public function __call( $method, $args ){
142
+
143
+ // first letters are 'add', last letters are 'Page'
144
+ if ( $this->_callMethodHasPrefixAndSuffix( $method, 'add', 'Page' ) ) {
145
+ // must be a valid menu type
146
+ $menuType = $this->_getCallMethodTypeFromCalledMethod( $method, 'add', 'Page' );
147
+ if ( !$this->_isValidMenuType( $menuType ) && !$this->_isValidSubMenuType( $menuType ) ) {
148
+
149
+ return false;
150
+ }
151
+
152
+ // must have correct arguments to initialize
153
+ if ( $this->_calledMethodWithCorrectArguments( $args ) ) {
154
+
155
+ $this->_initAdminSettingsPage( $args[0], $args[1], $args[2], $method );
156
+ }
157
+
158
+ return true;
159
+
160
+ // first letters are 'add', last letters are 'PageAction'
161
+ } elseif ( $this->_callMethodHasPrefixAndSuffix( $method, 'add', 'PageAction' ) ) {
162
+
163
+ // get method name
164
+ $menuType = $this->_getCallMethodTypeFromCalledMethod( $method, 'add', 'PageAction' );
165
+ if ( !$this->_isValidMenuType( $menuType ) && !$this->_isValidSubMenuType( $menuType ) ) {
166
+
167
+ return false;
168
+ }
169
+
170
+ $this->_callAddMenuPageMethod( $menuType );
171
+
172
+ return true;
173
+ }
174
+
175
+ // bad method call
176
+ return false;
177
+ }
178
+
179
+ /**
180
+ * __call method has a prefix and suffix
181
+ *
182
+ * @param string $method
183
+ * @param string $prefix
184
+ * @param string $suffix
185
+ * @return boolean
186
+ */
187
+ protected function _callMethodHasPrefixAndSuffix( $method, $prefix, $suffix ){
188
+
189
+ return substr( $method, 0, 3 ) == $prefix &&
190
+ substr( $method, ( strlen( $method ) - strlen( $suffix ) ), strlen( $method ) ) == $suffix;
191
+ }
192
+
193
+ /**
194
+ * __call'ed method with correct parameters
195
+ *
196
+ * @param array $args
197
+ * @return boolean
198
+ */
199
+ protected function _calledMethodWithCorrectArguments( $args ){
200
+
201
+ return isset( $args[0] ) &&
202
+ isset( $args[1] ) &&
203
+ isset( $args[2] ) &&
204
+ is_string( $args[0] ) &&
205
+ is_string( $args[1] ) &&
206
+ $args[2] instanceof JmsUserOptionsCollection;
207
+ }
208
+
209
+ /**
210
+ * get method type from the called method name
211
+ *
212
+ * @param string $method
213
+ * @param string $prefix
214
+ * @param string $suffix
215
+ * @return string
216
+ */
217
+ protected function _getCallMethodTypeFromCalledMethod( $method, $prefix, $suffix ){
218
+
219
+ $method = substr( $method, ( strlen( $prefix ) ), ( strlen( $method ) - strlen( $suffix ) - strlen( $prefix ) ) );
220
+ $method = strtolower( $method );
221
+
222
+ return $method;
223
+ }
224
+
225
+ /**
226
+ * is a valid menu type
227
+ *
228
+ * @param string $menuType
229
+ * @return bool
230
+ */
231
+ protected function _isValidMenuType( $menuType ){
232
+
233
+ $menuPageMethods = $this->_getMenuPageMethods();
234
+
235
+ return isset( $menuPageMethods[$menuType] );
236
+ }
237
+
238
+ /**
239
+ * is a valid sub menu type
240
+ *
241
+ * @param string $menuType
242
+ * @return bool
243
+ */
244
+ protected function _isValidSubMenuType( $menuType ) {
245
+
246
+ $subMenuPageMethods = $this->_getSubMenuPageMethods();
247
+
248
+ return isset($subMenuPageMethods[$menuType] );
249
+ }
250
+
251
+ /**
252
+ * get the correct add_xxxx_menu() menu page method
253
+ *
254
+ * @param string $menuType
255
+ * @return string|null
256
+ */
257
+ protected function _getAddMenuPageMethod( $menuType ){
258
+
259
+ $menuPageMethods = $this->_getMenuPageMethods();
260
+
261
+ return isset( $menuPageMethods[$menuType] ) ? $menuPageMethods[$menuType] : null;
262
+ }
263
+
264
+ /**
265
+ * get the correct add_xxxx_menu() submenu page method
266
+ *
267
+ * @param string $menuType
268
+ * @return string|null
269
+ */
270
+ protected function _getAddSubMenuPageMethod( $menuType ){
271
+
272
+ $subMenuPageMethods = $this->_getSubMenuPageMethods();
273
+
274
+ return isset( $subMenuPageMethods[$menuType] ) ? $subMenuPageMethods[$menuType] : null;
275
+ }
276
+
277
+ /**
278
+ * returns an array of menu page methods
279
+ *
280
+ * @return array
281
+ * @see http://codex.wordpress.org/Administration_Menus
282
+ */
283
+ protected function _getMenuPageMethods(){
284
+
285
+ // menu pages
286
+ return array(
287
+ 'menu' => 'add_menu_page',
288
+ 'object' => 'add_object_page',
289
+ 'utility' => 'add_utility_page',
290
+ );
291
+ }
292
+
293
+ /**
294
+ * returns an array of sub menu page methods
295
+ *
296
+ * @return array
297
+ * @see http://codex.wordpress.org/Administration_Menus
298
+ */
299
+ protected function _getSubMenuPageMethods(){
300
+
301
+ // submenu pages
302
+ return array(
303
+ 'dashboard' => 'add_dashboard_page',
304
+ 'posts' => 'add_posts_page',
305
+ 'media' => 'add_media_page',
306
+ 'links' => 'add_links_page',
307
+ 'pages' => 'add_pages_page',
308
+ 'comments' => 'add_comments_page',
309
+ 'theme' => 'add_theme_page',
310
+ 'plugins' => 'add_plugins_page',
311
+ 'users' => 'add_users_page',
312
+ 'management' => 'add_management_page',
313
+ 'options' => 'add_options_page',
314
+ );
315
+ }
316
+
317
+ /**
318
+ * calls the add menu/submenu page method with the appropriate arguments
319
+ *
320
+ * @param string $menuType
321
+ */
322
+ protected function _callAddMenuPageMethod( $menuType ){
323
+
324
+ // add menu page
325
+ if ( $this->_isValidMenuType( $menuType ) ) {
326
+
327
+ $method = $this->_getAddMenuPageMethod( $menuType );
328
+ $method(
329
+ __( $this->settingsPageTitle(), $this->textDomain() ),
330
+ __( $this->settingsMenuTitle(), $this->textDomain() ),
331
+ $this->manageSettingsCapability(),
332
+ $this->settingsMenuSlug(),
333
+ array( $this, 'renderAdminPage' )
334
+ );
335
+
336
+ // add admin submenu page
337
+ } else {
338
+
339
+ $method = $this->_getAddSubMenuPageMethod( $menuType );
340
+
341
+ // it's a pretty big pain to determine default menu positions, only add that param
342
+ // if we actually have a menu position set
343
+ if ( $this->menuPosition ) {
344
+
345
+ $method(
346
+ __( $this->settingsPageTitle(), $this->textDomain() ),
347
+ __( $this->settingsMenuTitle(), $this->textDomain() ),
348
+ $this->manageSettingsCapability(),
349
+ $this->settingsMenuSlug(),
350
+ array( $this, 'renderAdminPage' ),
351
+ $this->icon,
352
+ $this->menuPosition
353
+ );
354
+ } else {
355
+ $method(
356
+ __( $this->settingsPageTitle(), $this->textDomain() ),
357
+ __( $this->settingsMenuTitle(), $this->textDomain() ),
358
+ $this->manageSettingsCapability(),
359
+ $this->settingsMenuSlug(),
360
+ array( $this, 'renderAdminPage' ),
361
+ $this->icon
362
+ );
363
+ }
364
+ }
365
+ }
366
+
367
+ /**
368
+ * render admin page
369
+ */
370
+ public function renderAdminPage() {
371
+
372
+ if ( !current_user_can( $this->manageSettingsCapability() ) ) {
373
+ wp_die( __( 'You do not have sufficient permissions to access this page.', $this->textDomain() ) );
374
+ }
375
+
376
+ $args = array(
377
+ 'settings_page_slug' => $this->settingsMenuSlug(),
378
+ 'option_group' => $this->options->optionsGroup(),
379
+ 'option_key' => $this->options->optionsKey(),
380
+ );
381
+
382
+ $this->render( 'framework:admin:settings', $args );
383
+ }
384
+
385
+ /**
386
+ * admin settings init
387
+ */
388
+ public function registerSettings() {
389
+
390
+ $map = $this->options->optionMap();
391
+
392
+ register_setting(
393
+ $this->options->optionsGroup(),
394
+ $this->options->optionsKey(),
395
+ array( $this, 'validateFields' )
396
+ );
397
+
398
+ // map is broken up into sections, parse each one
399
+ foreach ( $map as $sectionKey => $sectionDetails ) {
400
+ $this->_addSettingsSection( $sectionKey, $sectionDetails );
401
+ }
402
+ }
403
+
404
+ /**
405
+ * add settings section
406
+ *
407
+ * @param string $sectionKey
408
+ * @param string $sectionDetails
409
+ * @return bool|void
410
+ */
411
+ protected function _addSettingsSection( $sectionKey, $sectionDetails ) {
412
+
413
+ if ( !isset( $sectionDetails['label'] ) || !isset( $sectionDetails['fields'] ) ) {
414
+ return false;
415
+ }
416
+
417
+ add_settings_section(
418
+ $sectionKey,
419
+ $sectionDetails['label'],
420
+ array( $this, 'renderSectionText' ),
421
+ $this->settingsMenuSlug()
422
+ );
423
+
424
+ foreach ( $sectionDetails['fields'] as $fieldKey => $fieldDetails ) {
425
+
426
+ $this->_addSettingsField( $fieldKey, $sectionKey );
427
+ }
428
+ }
429
+
430
+ /**
431
+ * add settings field
432
+ *
433
+ * @param string $fieldKey
434
+ * @param string $sectionKey
435
+ */
436
+ protected function _addSettingsField( $fieldKey, $sectionKey ) {
437
+
438
+ $fieldLabel = $this->options->fieldOption( $fieldKey, 'label' );
439
+ $fieldType = $this->options->fieldOption( $fieldKey, 'type' );
440
+ $required = $this->options->fieldOption( $fieldKey, 'required' );
441
+
442
+ if ( $required === true ) {
443
+ $fieldLabel .= $this->requiredIndicator();
444
+ }
445
+
446
+ $callback = $this->_getInputCallback( $fieldType );
447
+
448
+ add_settings_field(
449
+ $fieldKey,
450
+ apply_filters( 'jms_admin_settings_option_field_label', $fieldLabel ),
451
+ array( $this, $callback ),
452
+ $this->settingsMenuSlug(),
453
+ $sectionKey,
454
+ array(
455
+ 'field_key' => $fieldKey,
456
+ )
457
+ );
458
+ }
459
+
460
+ /**
461
+ * get input callback function
462
+ *
463
+ * @param string $type
464
+ * @return string
465
+ */
466
+ protected function _getInputCallback( $type ){
467
+
468
+ switch ($type) {
469
+ case 'radio':
470
+ return 'renderRadioInput';
471
+ case 'checkbox':
472
+ return 'renderCheckboxInput';
473
+ case 'textarea':
474
+ return 'renderTextareaInput';
475
+ case 'text':
476
+ default:
477
+ return 'renderTextInput';
478
+ }
479
+ }
480
+
481
+ /**
482
+ * render section text
483
+ *
484
+ * @param array $sectionDetails
485
+ */
486
+ public function renderSectionText( $sectionDetails ) {
487
+
488
+ $key = isset( $sectionDetails['id'] ) ? $sectionDetails['id'] : null;
489
+
490
+ if ( $key ) {
491
+ echo apply_filters( 'jms_admin_settings_section_text', $this->options->sectionOption( $key, 'description' ) );
492
+ }
493
+ }
494
+
495
+ /**
496
+ * render text input
497
+ *
498
+ * @param array $args
499
+ */
500
+ public function renderTextInput( $args ) {
501
+ $fieldKey = $args['field_key'];
502
+
503
+ $dataType = $this->options->fieldOption( $fieldKey, 'data_type' );
504
+
505
+ if ( $dataType == 'integer' || $dataType == 'float' ) {
506
+ $inputType = 'number';
507
+ } else {
508
+ $inputType = 'text';
509
+ }
510
+
511
+ $args = array(
512
+ 'plugin_option_name' => $this->options->optionsKey(),
513
+ 'field_key' => $fieldKey,
514
+ 'option_value' => $this->options->getOption( $fieldKey ),
515
+ 'input_type' => $inputType,
516
+ 'extra_attributes' => $this->_extraAtts( $fieldKey, $inputType ),
517
+ 'units' => $this->options->fieldOption( $fieldKey, 'units' ),
518
+ 'options' => $this->options->fieldOption( $fieldKey, 'options' ),
519
+ );
520
+
521
+ $this->render( apply_filters( 'jms_admin_settings_text_input_template', 'framework:admin:partials:text_input' ), $args );
522
+ }
523
+
524
+ /**
525
+ * render checkbox input
526
+ *
527
+ * @param array $args
528
+ */
529
+ public function renderCheckboxInput( $args ) {
530
+ $fieldKey = $args['field_key'];
531
+
532
+ $args = array(
533
+ 'plugin_option_name' => $this->options->optionsKey(),
534
+ 'field_key' => $fieldKey,
535
+ 'field_label' => $this->options->fieldOption( $fieldKey, 'label' ),
536
+ 'option_value' => $this->options->getOption( $fieldKey ),
537
+ 'extra_attributes' => $this->_extraAtts( $fieldKey, 'checkbox' ),
538
+ );
539
+
540
+ $this->render( apply_filters( 'jms_admin_settings_checkbox_input_template', 'framework:admin:partials:checkbox_input' ), $args );
541
+ }
542
+
543
+ /**
544
+ * render radio input
545
+ *
546
+ * @param array $args
547
+ */
548
+ public function renderRadioInput( $args ) {
549
+ $fieldKey = $args['field_key'];
550
+
551
+ $args = array(
552
+ 'plugin_option_name' => $this->options->optionsKey(),
553
+ 'field_key' => $fieldKey,
554
+ 'option_value' => $this->options->getOption( $fieldKey ),
555
+ 'extra_attributes' => $this->_extraAtts( $fieldKey, 'radio' ),
556
+ );
557
+
558
+ foreach ( $this->options->fieldOption( $fieldKey, 'choices' ) as $choiceKey => $choiceLabel ) {
559
+
560
+ $args['choice_key'] = $choiceKey;
561
+ $args['choice_label'] = $choiceLabel;
562
+
563
+ $this->render( apply_filters( 'jms_admin_settings_radio_input_template', 'framework:admin:partials:radio_input' ), $args );
564
+ }
565
+ }
566
+
567
+ /**
568
+ * render textarea input
569
+ *
570
+ * @param array $args
571
+ */
572
+ public function renderTextareaInput( $args ) {
573
+ $fieldKey = $args['field_key'];
574
+
575
+ $args = array(
576
+ 'plugin_option_name' => $this->options->optionsKey(),
577
+ 'field_key' => $fieldKey,
578
+ 'option_value' => $this->options->getOption( $fieldKey ),
579
+ 'extra_attributes' => $this->_extraAtts( $fieldKey, 'textarea' ),
580
+ );
581
+
582
+ $this->render( apply_filters( 'jms_admin_settings_textarea_input_template', 'framework:admin:partials:textarea_input' ), $args );
583
+ }
584
+
585
+ /**
586
+ * get extra html attributes
587
+ *
588
+ * @param string $fieldKey
589
+ * @param string $inputType
590
+ * @return string
591
+ */
592
+ protected function _extraAtts( $fieldKey, $inputType ){
593
+
594
+ $atts = array();
595
+
596
+ $dataType = $this->options->fieldOption( $fieldKey, 'data_type' );
597
+
598
+ switch ( $inputType ) {
599
+ case 'number':
600
+ if ( $dataType == 'integer' ) {
601
+ $atts[] = 'step="1"';
602
+ $atts[] = 'pattern="\d+"';
603
+ } elseif( $dataType == 'float') {
604
+ $atts[] = 'step="any"';
605
+ }
606
+
607
+ $min = $this->options->fieldOption( $fieldKey, 'min' );
608
+ $max = $this->options->fieldOption( $fieldKey, 'max' );
609
+
610
+ if ( is_int( $min ) ) {
611
+ $atts[] = 'min="' . $min . '"';
612
+ }
613
+ if ( is_int( $max ) ) {
614
+ $atts[] = 'max="' . $max . '"';
615
+ }
616
+ $atts = apply_filters( 'jms_admin_settings_number_input_field_extra_attributes', $atts );
617
+ break;
618
+ case 'textarea':
619
+ $columns = $this->options->fieldOption( $fieldKey, 'columns' );
620
+ $rows = $this->options->fieldOption( $fieldKey, 'rows' );
621
+
622
+ if ( is_int( $columns ) ) {
623
+ $atts[] = 'cols="' . $columns . '"';
624
+ }
625
+ if ( is_int( $rows ) ) {
626
+ $atts[] = 'rows="' . $rows . '"';
627
+ }
628
+ $atts = apply_filters( 'jms_admin_settings_textarea_input_field_extra_attributes', $atts );
629
+ break;
630
+ case 'text':
631
+ $atts = apply_filters( 'jms_admin_settings_text_input_field_extra_attributes', $atts );
632
+ break;
633
+ case 'radio':
634
+ $atts = apply_filters( 'jms_admin_settings_radio_input_field_extra_attributes', $atts );
635
+ break;
636
+ case 'checkbox':
637
+ $atts = apply_filters( 'jms_admin_settings_checkbox_input_field_extra_attributes', $atts );
638
+ break;
639
+ default:
640
+ break;
641
+ }
642
+
643
+ if ( $this->options->fieldOption( $fieldKey, 'required' ) === true ) {
644
+ $atts[] = 'required="required"';
645
+ }
646
+
647
+ return apply_filters( 'jms_admin_settings_input_field_extra_attributes', implode( ' ', $atts ) );
648
+ }
649
+
650
+ /**
651
+ * validate form fields
652
+ *
653
+ * @param array $fields
654
+ * @return array
655
+ */
656
+ public function validateFields( $fields ) {
657
+
658
+ // check for restore to defaults
659
+ if ( isset( $fields['restore'] ) ) {
660
+ return $this->options->defaultOptions();
661
+ }
662
+
663
+ $options = $this->options->fields();
664
+
665
+ // make sure no extra options were posted.
666
+ foreach ( $fields as $fieldKey => $fieldVal ) {
667
+ if ( !isset( $fieldKey, $fields ) ) {
668
+ add_settings_error(
669
+ $fieldKey,
670
+ 'error',
671
+ apply_filters( 'jms_admin_settings_error_invalid', __( $fieldKey . ' is not a valid option', $this->textDomain() ) ),
672
+ 'error'
673
+ );
674
+ }
675
+ }
676
+
677
+ // process each option in the options map since we may not have been posted every option.
678
+ foreach ( $options as $optionKey => $optionLabel ) {
679
+
680
+ $this->_validateField( $fields, $optionKey, $optionLabel );
681
+ }
682
+
683
+ return $fields;
684
+ }
685
+
686
+ /**
687
+ * validate field
688
+ *
689
+ * @param array $fields
690
+ * @param string $optionKey
691
+ * @param string $optionLabel
692
+ */
693
+ protected function _validateField( &$fields, $optionKey, $optionLabel ) {
694
+
695
+ $dataType = $this->options->fieldOption( $optionKey, 'data_type' );
696
+
697
+ // if the option wasn't posted it may be a boolean false, or may be a value the user wants to remove
698
+ if ( isset( $fields[$optionKey] ) ) {
699
+ if ( ( $dataType == 'integer' || $dataType == 'float' ) ) {
700
+ $this->_validateNumberField( $fields, $optionKey, $optionLabel );
701
+ } elseif( $dataType == 'string' ) {
702
+ $this->_validateStringField( $fields, $optionKey, $optionLabel );
703
+ } elseif ( $dataType == 'choice' ) {
704
+ $this->_validateChoiceField( $fields, $optionKey, $optionLabel );
705
+ } elseif ( $dataType == 'boolean' ) {
706
+ $this->_validateBooleanField( $fields, $optionKey, $optionLabel );
707
+ }
708
+ } elseif( $dataType == 'boolean' ) {
709
+ $fields[$optionKey] = 0;
710
+ }
711
+ }
712
+
713
+ /**
714
+ * validate numeric field
715
+ *
716
+ * @param array $fields
717
+ * @param string $optionKey
718
+ * @param string $optionLabel
719
+ */
720
+ protected function _validateNumberField( &$fields, $optionKey, $optionLabel ) {
721
+
722
+ if ( !is_numeric( $fields[$optionKey] ) ) {
723
+ $fields[$optionKey] = $this->options->getOption( $optionKey );
724
+ add_settings_error(
725
+ $optionKey,
726
+ 'error',
727
+ apply_filters( 'jms_admin_settings_error_invalid_number', __( $optionLabel . ' must be a numeric value', $this->textDomain() ) ),
728
+ 'error'
729
+ );
730
+ }
731
+
732
+ $min = $this->options->fieldOption( $optionKey, 'min' );
733
+ if ( $fields[$optionKey] < $min ) {
734
+ $fields[$optionKey] = $this->options->getOption( $optionKey );
735
+ add_settings_error(
736
+ $optionKey,
737
+ 'error',
738
+ apply_filters( 'jms_admin_settings_error_invalid_number', sprintf( __( $optionLabel . ' cannot be less than %s', $this->textDomain() ), $min ) ),
739
+ 'error'
740
+ );
741
+ }
742
+
743
+ $max = $this->options->fieldOption( $optionKey, 'max' );
744
+ if ( $fields[$optionKey] > $max ) {
745
+ $fields[$optionKey] = $this->options->getOption( $optionKey );
746
+ add_settings_error(
747
+ $optionKey,
748
+ 'error',
749
+ apply_filters( 'jms_admin_settings_error_invalid_number', sprintf( __( $optionLabel . ' cannot be greater than %s', $this->textDomain() ), $max ) ),
750
+ 'error'
751
+ );
752
+ }
753
+
754
+ $dataType = $this->options->fieldOption( $optionKey, 'data_type' );
755
+ if ( $dataType == 'integer' ) {
756
+ $fields[$optionKey] = (int)$fields[$optionKey];
757
+ }
758
+ if ( $dataType == 'float' ) {
759
+ $fields[$optionKey] = (float)$fields[$optionKey];
760
+ }
761
+ }
762
+
763
+ /**
764
+ * validate string field
765
+ *
766
+ * @param array $fields
767
+ * @param string $optionKey
768
+ * @param string $optionLabel
769
+ */
770
+ protected function _validateStringField( &$fields, $optionKey, $optionLabel ) {
771
+ // sanitize strings
772
+ $fields[$optionKey] = filter_var( $fields[$optionKey], FILTER_SANITIZE_STRING );
773
+
774
+ // check color
775
+ if ( $this->options->fieldOption( $optionKey, 'options' ) == 'color-picker' ) {
776
+ $this->_validateColorField( $fields, $optionKey, $optionLabel );
777
+ }
778
+ }
779
+
780
+ /**
781
+ * validate color field
782
+ *
783
+ * @param array $fields
784
+ * @param string $optionKey
785
+ * @param string $optionLabel
786
+ */
787
+ protected function _validateColorField( &$fields, $optionKey, $optionLabel ) {
788
+
789
+ $colorHex = $fields[$optionKey];
790
+ if ( substr( $colorHex, 0, 1 ) == '#' ) {
791
+ $colorHex = substr( $colorHex, 1 );
792
+ }
793
+
794
+ if ( !ctype_xdigit( $colorHex ) ) {
795
+ $fields[$optionKey] = $this->options->getOption( $optionKey );
796
+ add_settings_error(
797
+ $optionKey,
798
+ 'error',
799
+ apply_filters( 'jms_admin_settings_error_invalid_color', __( $optionLabel . ' must be a valid hexadecimal color value', $this->textDomain() ) ),
800
+ 'error'
801
+ );
802
+ }
803
+ }
804
+
805
+ /**
806
+ * validate choice field
807
+ *
808
+ * @param array $fields
809
+ * @param string $optionKey
810
+ * @param string $optionLabel
811
+ */
812
+ protected function _validateChoiceField( &$fields, $optionKey, $optionLabel ) {
813
+
814
+ $choices = $this->options->fieldOption( $optionKey, 'choices' );
815
+ if ( !isset( $choices[$fields[$optionKey]] ) ) {
816
+ $fields[$optionKey] = $this->options->getOption( $optionKey );
817
+ add_settings_error(
818
+ $optionKey,
819
+ 'error',
820
+ apply_filters( 'jms_admin_settings_error_invalid_choice', __( $optionLabel . ' is not a valid selection', $this->textDomain() ) ),
821
+ 'error'
822
+ );
823
+ }
824
+ }
825
+
826
+ /**
827
+ * validate boolean field
828
+ *
829
+ * @param array $fields
830
+ * @param string $optionKey
831
+ * @param string $optionLabel
832
+ */
833
+ protected function _validateBooleanField( &$fields, $optionKey, $optionLabel ) {
834
+ $fields[$optionKey] = (bool)$fields[$optionKey];
835
+ }
836
+
837
+ /**
838
+ * required indicator
839
+ *
840
+ * @return string
841
+ */
842
+ public function requiredIndicator(){
843
+
844
+ return $this->render( apply_filters( 'jms_admin_settings_required_indicator_template', 'framework:admin:partials:required_indicator' ), array(), false );
845
+ }
846
+
847
+ /**
848
+ * @param string $icon
849
+ */
850
+ public function setIcon( $icon )
851
+ {
852
+ $this->icon = $icon;
853
+ }
854
+
855
+ /**
856
+ * @return string
857
+ */
858
+ public function getIcon()
859
+ {
860
+ return $this->icon;
861
+ }
862
+
863
+ /**
864
+ * @param string $manageSettingsCapability
865
+ */
866
+ public function setManageSettingsCapability( $manageSettingsCapability )
867
+ {
868
+ $this->manageSettingsCapability = $manageSettingsCapability;
869
+ }
870
+
871
+ /**
872
+ * @return string
873
+ */
874
+ public function getManageSettingsCapability()
875
+ {
876
+ return $this->manageSettingsCapability;
877
+ }
878
+
879
+ /**
880
+ * @param string $menuPosition
881
+ */
882
+ public function setMenuPosition( $menuPosition )
883
+ {
884
+ $this->menuPosition = $menuPosition;
885
+ }
886
+
887
+ /**
888
+ * @return string
889
+ */
890
+ public function getMenuPosition()
891
+ {
892
+ return $this->menuPosition;
893
+ }
894
+
895
+ /**
896
+ * @param \JmsUserOptionsCollection $options
897
+ */
898
+ public function setOptions( $options )
899
+ {
900
+ $this->options = $options;
901
+ }
902
+
903
+ /**
904
+ * @return \JmsUserOptionsCollection
905
+ */
906
+ public function getOptions()
907
+ {
908
+ return $this->options;
909
+ }
910
+
911
+ /**
912
+ * @param string $settingsPageTitle
913
+ */
914
+ public function setSettingsPageTitle( $settingsPageTitle )
915
+ {
916
+ $this->settingsPageTitle = $settingsPageTitle;
917
+ }
918
+
919
+ /**
920
+ * @return string
921
+ */
922
+ public function getSettingsPageTitle()
923
+ {
924
+ return $this->settingsPageTitle;
925
+ }
926
+
927
+ /**
928
+ * @param string $settingsMenuSlug
929
+ */
930
+ public function setSettingsMenuSlug( $settingsMenuSlug )
931
+ {
932
+ $this->settingsMenuSlug = $settingsMenuSlug;
933
+ }
934
+
935
+ /**
936
+ * @return string
937
+ */
938
+ public function getSettingsMenuSlug()
939
+ {
940
+ return $this->settingsMenuSlug;
941
+ }
942
+
943
+ /**
944
+ * @param string $settingsMenuTitle
945
+ */
946
+ public function setSettingsMenuTitle( $settingsMenuTitle )
947
+ {
948
+ $this->settingsMenuTitle = $settingsMenuTitle;
949
+ }
950
+
951
+ /**
952
+ * @return string
953
+ */
954
+ public function getSettingsMenuTitle()
955
+ {
956
+ return $this->settingsMenuTitle;
957
+ }
958
+ }
959
+ }
framework/JmsBootstrap.php ADDED
@@ -0,0 +1,178 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Bootstrap
4
+ * This class autoloads all classes in the plugin directory
5
+ * This class will instantiate each controller class automatically
6
+ *
7
+ * @author Joe Sexton <joe@josephmsexton.com>
8
+ * @package WordPress
9
+ * @subpackage JMS Plugin Framework
10
+ * @version 1.2
11
+ */
12
+ if ( !class_exists( 'JmsBootstrap' ) ){
13
+ class JmsBootstrap {
14
+
15
+ /**
16
+ * @var string
17
+ */
18
+ protected $rootPath;
19
+
20
+ /**
21
+ * @var string
22
+ */
23
+ protected $fwPath;
24
+
25
+ /**
26
+ * @var string
27
+ */
28
+ protected $controllerPath;
29
+
30
+ /**
31
+ * @var string
32
+ */
33
+ protected $modelPath;
34
+
35
+ /**
36
+ * @var array
37
+ */
38
+ protected $objects = array();
39
+
40
+ /**
41
+ * @var string
42
+ */
43
+ protected $pluginName;
44
+
45
+ /**
46
+ * @var string
47
+ */
48
+ protected $pluginFile;
49
+
50
+ /**
51
+ * constructor
52
+ *
53
+ * @param string $pluginFile
54
+ * @param string $pluginName
55
+ */
56
+ public function __construct( $pluginFile, $pluginName = '' ) {
57
+
58
+ $rootPath = plugin_dir_path( $pluginFile );
59
+
60
+ if ( !$rootPath )
61
+ $rootPath = dirname( __FILE__ );
62
+ $this->rootPath = trailingslashit( $rootPath );
63
+
64
+ $this->fwPath = $this->rootPath . 'framework/';
65
+ $this->controllerPath = $this->rootPath . 'controller/';
66
+ $this->modelPath = $this->rootPath . 'model/';
67
+
68
+ $this->pluginFile = $pluginFile;
69
+ $this->pluginName = $pluginName;
70
+
71
+ spl_autoload_register( array( $this, '_autoload' ) );
72
+
73
+ $this->initControllers();
74
+ }
75
+
76
+ /**
77
+ * autoload
78
+ *
79
+ * @param $class
80
+ */
81
+ protected function _autoload( $class ){
82
+
83
+ $this->_loadClassFile( $class );
84
+ }
85
+
86
+ /**
87
+ * load class file
88
+ * recursively searches all directories/subdirectories for class
89
+ * if class file is found, include()
90
+ *
91
+ * @param string $class
92
+ * @param string $dir
93
+ * @return bool
94
+ */
95
+ protected function _loadClassFile( $class, $dir = null ) {
96
+
97
+ if ( is_null( $dir ) )
98
+ $dir = $this->rootPath;
99
+
100
+ foreach ( scandir( $dir ) as $file ) {
101
+
102
+ // directory?
103
+ if ( is_dir( $dir . $file ) && substr( $file, 0, 1 ) !== '.' )
104
+ $this->_loadClassFile( $class, $dir . $file . '/' );
105
+
106
+ // php file and filename matches class?
107
+ if (
108
+ substr( $file, 0, 1 ) !== '.' &&
109
+ preg_match( "/.php$/i" , $file ) &&
110
+ (str_replace( '.php', '', $file ) == $class || str_replace( '.class.php', '', $file ) == $class )
111
+ ) {
112
+ include $dir . $file;
113
+ }
114
+ }
115
+ }
116
+
117
+ /**
118
+ * init controllers
119
+ * recursively instantiates all controllers in the controllers directory/subdirectory
120
+ *
121
+ * @param string $dir
122
+ * @return boolean
123
+ */
124
+ public function initControllers( $dir = null ) {
125
+
126
+ if ( is_null( $dir ) )
127
+ $dir = $this->controllerPath;
128
+
129
+ if ( !is_dir( $dir ) )
130
+ return false;
131
+
132
+ foreach ( scandir( $dir ) as $file ) {
133
+
134
+ // directory?
135
+ if ( is_dir( $dir . $file ) && substr( $file, 0, 1 ) !== '.' )
136
+ $this->initControllers( $dir . $file . '/' );
137
+
138
+ // php file?
139
+ if( substr( $file, 0, 1 ) !== '.' && preg_match( "/.php$/i" , $file ) ) {
140
+
141
+ $class = str_replace( '.class.php', '', $file );
142
+ $class = str_replace( '.php', '', $class );
143
+ if ( class_exists( $class ) ) {
144
+ $this->objects[$class] = new $class( $this->pluginFile, $this->pluginName );
145
+ }
146
+ }
147
+ }
148
+
149
+ return true;
150
+ }
151
+
152
+ /**
153
+ * get objects
154
+ *
155
+ * @return array
156
+ */
157
+ public function getObjects() {
158
+
159
+ return $this->objects;
160
+ }
161
+
162
+ /**
163
+ * get object
164
+ *
165
+ * @param string $class
166
+ * @return object|null
167
+ */
168
+ public function getObject( $class ) {
169
+
170
+ if ( !empty( $this->objects[$class] ) ) {
171
+
172
+ return $this->objects[$class];
173
+ }
174
+
175
+ return null;
176
+ }
177
+ }
178
+ }
framework/JmsController.php ADDED
@@ -0,0 +1,420 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Controller
5
+ * This is an abstract base controller that adds some handy properties and methods
6
+ *
7
+ * @author Joe Sexton <joe@josephmsexton.com>
8
+ * @package WordPress
9
+ * @subpackage JMS Plugin Framework
10
+ * @version 1.2
11
+ */
12
+ if ( !class_exists( 'JmsController' ) ){
13
+ abstract class JmsController {
14
+
15
+ /**
16
+ * @var string
17
+ */
18
+ protected $rootPath;
19
+
20
+ /**
21
+ * @var string
22
+ */
23
+ protected $fwPath;
24
+
25
+ /**
26
+ * @var string
27
+ */
28
+ protected $controllerPath;
29
+
30
+ /**
31
+ * @var string
32
+ */
33
+ protected $modelPath;
34
+
35
+ /**
36
+ * @var string
37
+ */
38
+ protected $viewPath;
39
+
40
+ /**
41
+ * @var string
42
+ */
43
+ protected $assetPath;
44
+
45
+ /**
46
+ * @var string
47
+ */
48
+ protected $pluginName;
49
+
50
+ /**
51
+ * @var string
52
+ */
53
+ protected $pluginSlug;
54
+
55
+ /**
56
+ * @var string
57
+ */
58
+ protected $pluginFile;
59
+
60
+ /**
61
+ * constructor
62
+ *
63
+ * @param string $pluginFile
64
+ * @param string $pluginName
65
+ */
66
+ public function __construct( $pluginFile, $pluginName = '' ) {
67
+
68
+ $rootPath = plugin_dir_path( $pluginFile );
69
+ $rootUrl = plugin_dir_url( $pluginFile );
70
+
71
+ $this->rootPath = $rootPath;
72
+
73
+ $this->fwPath = $this->rootPath . 'framework/';
74
+ $this->controllerPath = $this->rootPath . 'controller/';
75
+ $this->modelPath = $this->rootPath . 'model/';
76
+ $this->viewPath = $this->rootPath . 'view/';
77
+ $this->assetPath = $rootUrl . 'assets/';
78
+
79
+ $this->pluginFile = $pluginFile;
80
+ $this->pluginName = $pluginName;
81
+
82
+ $pathParts = explode( '/', $pluginFile );
83
+ $filename = array_pop( $pathParts );
84
+ $filenameParts = explode( '.', $filename );
85
+ $this->pluginSlug = array_shift( $filenameParts );
86
+
87
+ add_action( 'wp_enqueue_scripts', array( $this, 'enqueueScripts' ) );
88
+ add_action( 'wp_enqueue_scripts', array( $this, 'enqueueStyles' ) );
89
+ add_action( 'admin_enqueue_scripts', array( $this, 'enqueueAdminScripts' ) );
90
+ add_action( 'admin_enqueue_scripts', array( $this, 'enqueueAdminStyles' ) );
91
+
92
+ register_activation_hook( $this->pluginFile, array( $this, 'onActivation' ) );
93
+ register_deactivation_hook( $this->pluginFile, array( $this, 'onDeactivation' ) );
94
+
95
+ $this->_init();
96
+ }
97
+
98
+ /**
99
+ * enqueue script
100
+ * enqueue script using : separators for dirs in assets directory
101
+ * ie. render('acme:test') will render /assets/js/acme/test.js
102
+ *
103
+ * @param string $handle
104
+ * @param string $script
105
+ * @param array $deps
106
+ * @param string $ver
107
+ * @param boolean $footer
108
+ * @param array $localizedVars
109
+ * @return boolean
110
+ */
111
+ public function enqueueScript(
112
+ $handle,
113
+ $script,
114
+ array $deps = array( 'jquery' ),
115
+ $ver = null,
116
+ $footer = true,
117
+ array $localizedVars = array()
118
+ ) {
119
+
120
+ $script = str_replace( ':', '/', $script );
121
+ $file = $this->assetPath . 'js/' . $script . '.js';
122
+
123
+ wp_register_script( $handle, $file, $deps, $ver, $footer );
124
+ wp_enqueue_script( $handle );
125
+
126
+ foreach ( $localizedVars as $name => $vars ) {
127
+
128
+ wp_localize_script( $handle, $name, $vars );
129
+ }
130
+
131
+ return true;
132
+ }
133
+
134
+ /**
135
+ * enqueue style
136
+ * enqueue style using : separators for dirs in assets directory
137
+ * ie. render('acme:test') will render /assets/css/acme/test.css
138
+ *
139
+ * @param string $handle
140
+ * @param string $style
141
+ * @param array $deps
142
+ * @param string $ver
143
+ * @param string $media
144
+ * @return boolean
145
+ */
146
+ public function enqueueStyle(
147
+ $handle,
148
+ $style,
149
+ array $deps = array(),
150
+ $ver = null,
151
+ $media = 'screen'
152
+ ) {
153
+
154
+ $style = str_replace( ':', '/', $style );
155
+ $file = $this->assetPath . 'css/' . $style . '.css';
156
+
157
+ wp_register_style( $handle, $file, $deps, $ver, $media );
158
+ wp_enqueue_style( $handle );
159
+
160
+ return true;
161
+ }
162
+
163
+ /**
164
+ * enqueue script
165
+ * enqueue script using a public web path
166
+ *
167
+ * @param string $handle
168
+ * @param string $path
169
+ * @param array $deps
170
+ * @param string $ver
171
+ * @param boolean $footer
172
+ * @param array $localizedVars
173
+ * @return boolean
174
+ */
175
+ public function enqueueCdnScript(
176
+ $handle,
177
+ $path,
178
+ array $deps = array( 'jquery' ),
179
+ $ver = null,
180
+ $footer = true,
181
+ array $localizedVars = array()
182
+ ) {
183
+ wp_register_script( $handle, $path, $deps, $ver, $footer );
184
+ wp_enqueue_script( $handle );
185
+
186
+ foreach ( $localizedVars as $name => $vars ) {
187
+
188
+ wp_localize_script( $handle, $name, $vars );
189
+ }
190
+
191
+ return true;
192
+ }
193
+
194
+ /**
195
+ * enqueue style
196
+ * enqueue style using a public web path
197
+ *
198
+ * @param string $handle
199
+ * @param string $path
200
+ * @param array $deps
201
+ * @param string $ver
202
+ * @param string $media
203
+ * @return boolean
204
+ */
205
+ public function enqueueCdnStyle(
206
+ $handle,
207
+ $path,
208
+ array $deps = array(),
209
+ $ver = null,
210
+ $media = 'screen'
211
+ ) {
212
+ wp_register_style( $handle, $path, $deps, $ver, $media );
213
+ wp_enqueue_style( $handle );
214
+
215
+ return true;
216
+ }
217
+
218
+ /**
219
+ * render view
220
+ * call view using : separators for dirs in view directory
221
+ * ie. render('acme:test') will render /view/acme/test.php
222
+ *
223
+ * @param string $view view template
224
+ * @param array $args arguments used in the view
225
+ * @param boolean $echo true=print false=return
226
+ * @return string|boolean
227
+ */
228
+ function render( $view, array $args = array(), $echo = true ){
229
+
230
+ $view = str_replace( ':', '/', $view );
231
+ $file = $this->viewPath . $view . '.php';
232
+ $assetPath = $this->assetPath;
233
+
234
+ if( !empty( $args ) )
235
+ extract( $args );
236
+
237
+ if ( !file_exists( $file ) )
238
+ return false;
239
+
240
+ if ( $echo ) {
241
+ include $file;
242
+
243
+ return true;
244
+
245
+ } else {
246
+ ob_start();
247
+ include $file;
248
+ $output = ob_get_contents();
249
+ ob_end_clean();
250
+
251
+ return $output;
252
+ }
253
+ }
254
+
255
+ /**
256
+ * render shortcode
257
+ * call view using : separators for dirs in view directory
258
+ * ie. renderShortcode('acme:test', $atts) will render /view/acme/test.php
259
+ *
260
+ * @param string $view view template
261
+ * @param array $atts attributes passed
262
+ * @param array $pairs supported/default attributes
263
+ * @param string $shortcode shortcode name
264
+ * @return string
265
+ */
266
+ public function renderShortcode( $view, $atts, array $pairs = array(), $shortcode = '' ) {
267
+
268
+ $view = str_replace( ':', '/', $view );
269
+ $file = $this->viewPath . $view . '.php';
270
+ $assetPath = $this->assetPath;
271
+
272
+ extract( shortcode_atts( $pairs, $atts, $shortcode ) );
273
+
274
+ if ( !file_exists( $file ) )
275
+ return false;
276
+
277
+ ob_start();
278
+ include $file;
279
+ $output = ob_get_contents();
280
+ ob_end_clean();
281
+
282
+ return $output;
283
+ }
284
+
285
+ /**
286
+ * add actions
287
+ */
288
+ protected function _init() {}
289
+
290
+ /**
291
+ * enqueue admin scripts
292
+ */
293
+ public function enqueueScripts() {}
294
+
295
+ /**
296
+ * enqueue admin styles
297
+ */
298
+ public function enqueueStyles() {}
299
+
300
+ /**
301
+ * enqueue admin scripts
302
+ */
303
+ public function enqueueAdminScripts() {}
304
+
305
+ /**
306
+ * enqueue admin styles
307
+ */
308
+ public function enqueueAdminStyles() {}
309
+
310
+ /**
311
+ * on activation
312
+ */
313
+ public function onActivation() {}
314
+
315
+ /**
316
+ * on deactivation
317
+ */
318
+ public function onDeactivation() {}
319
+
320
+ /**
321
+ * root path
322
+ *
323
+ * @return string
324
+ */
325
+ public function rootPath(){
326
+
327
+ return $this->rootPath;
328
+ }
329
+
330
+ /**
331
+ * fw path
332
+ *
333
+ * @return string
334
+ */
335
+ public function fwPath(){
336
+
337
+ return $this->fwPath;
338
+ }
339
+
340
+ /**
341
+ * controller path
342
+ *
343
+ * @return string
344
+ */
345
+ public function controllerPath(){
346
+
347
+ return $this->controllerPath;
348
+ }
349
+
350
+ /**
351
+ * model path
352
+ *
353
+ * @return string
354
+ */
355
+ public function modelPath(){
356
+
357
+ return $this->modelPath;
358
+ }
359
+
360
+ /**
361
+ * view path
362
+ *
363
+ * @return string
364
+ */
365
+ public function viewPath(){
366
+
367
+ return $this->viewPath;
368
+ }
369
+
370
+ /**
371
+ * asset path
372
+ *
373
+ * @return string
374
+ */
375
+ public function assetPath(){
376
+
377
+ return $this->assetPath;
378
+ }
379
+
380
+ /**
381
+ * plugin name
382
+ *
383
+ * @return string
384
+ */
385
+ public function pluginName(){
386
+
387
+ return $this->pluginName;
388
+ }
389
+
390
+ /**
391
+ * plugin slug
392
+ *
393
+ * @return string
394
+ */
395
+ public function pluginSlug(){
396
+
397
+ return $this->pluginSlug;
398
+ }
399
+
400
+ /**
401
+ * plugin file
402
+ *
403
+ * @return string
404
+ */
405
+ public function pluginFile(){
406
+
407
+ return $this->pluginFile;
408
+ }
409
+
410
+ /**
411
+ * text domain
412
+ *
413
+ * @return string
414
+ */
415
+ public function textDomain(){
416
+
417
+ return $this->pluginSlug;
418
+ }
419
+ }
420
+ }
framework/JmsUserOptionsCollection.php ADDED
@@ -0,0 +1,234 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * User Options Collection class
4
+ * This class manages plugin options that a user would change.
5
+ *
6
+ * @author Joe Sexton <joe@josephmsexton.com>
7
+ * @package WordPress
8
+ * @subpackage JMS Plugin Framework
9
+ * @version 1.2
10
+ */
11
+ if ( !class_exists( 'JmsPluginUserOptionsCollection' ) ){
12
+ class JmsUserOptionsCollection {
13
+
14
+ /**
15
+ * @var string
16
+ */
17
+ protected $optionsGroup = 'jms-framework-options';
18
+
19
+ /**
20
+ * @var string
21
+ */
22
+ protected $optionsKey = 'jms-framework';
23
+
24
+ /**
25
+ * @var array
26
+ */
27
+ protected $optionMap = array();
28
+
29
+ /**
30
+ * get options group
31
+ *
32
+ * @return string
33
+ */
34
+ public function optionsGroup(){
35
+
36
+ return $this->optionsGroup;
37
+ }
38
+
39
+ /**
40
+ * get options key
41
+ *
42
+ * @return string
43
+ */
44
+ public function optionsKey(){
45
+
46
+ return $this->optionsKey;
47
+ }
48
+
49
+ /**
50
+ * get option from array of options
51
+ *
52
+ * @param string $key
53
+ * @return string
54
+ */
55
+ public function getOption( $key ) {
56
+
57
+ $options = get_option( $this->optionsKey, array() );
58
+ $value = isset( $options[$key] ) ? $options[$key] : '';
59
+
60
+ return $value;
61
+ }
62
+
63
+ /**
64
+ * add/update option value
65
+ *
66
+ * @param string $key
67
+ * @param mixed $val
68
+ * @return bool
69
+ */
70
+ public function updateOption( $key, $val ) {
71
+
72
+ $options = get_option( $this->optionsKey, array() );
73
+ $options[$key] = $val;
74
+
75
+ return update_option( $this->optionsKey, $options );
76
+ }
77
+
78
+ /**
79
+ * option set yet?
80
+ *
81
+ * @param string $key
82
+ * @return boolean
83
+ */
84
+ public function hasOption( $key ){
85
+
86
+ $options = get_option( $this->optionsKey, array() );
87
+
88
+ return isset( $options[$key] );
89
+ }
90
+
91
+ /**
92
+ * options collection set yet?
93
+ *
94
+ * @return boolean
95
+ */
96
+ public function hasOptionCollection(){
97
+
98
+ $options = get_option( $this->optionsKey, array() );
99
+
100
+ return !empty( $options );
101
+ }
102
+
103
+ /**
104
+ * get section map
105
+ *
106
+ * @param string $sectionKey
107
+ * @return array
108
+ */
109
+ public function sectionMap( $sectionKey ) {
110
+
111
+ $map = $this->optionMap();
112
+
113
+ return isset( $map[$sectionKey] ) ? $map[$sectionKey] : array();
114
+ }
115
+
116
+ /**
117
+ * get section option setting
118
+ *
119
+ * @param string $sectionKey
120
+ * @param string $optionKey
121
+ * @return null
122
+ */
123
+ public function sectionOption( $sectionKey, $optionKey ) {
124
+
125
+ $map = $this->sectionMap( $sectionKey );
126
+
127
+ if ( isset( $map[$optionKey] ) ) {
128
+ return $map[$optionKey];
129
+ } else {
130
+ return NULL;
131
+ }
132
+ }
133
+
134
+ /**
135
+ * get all fields
136
+ *
137
+ * @return array
138
+ */
139
+ public function fields() {
140
+
141
+ $map = $this->optionMap();
142
+ $fields = array();
143
+
144
+ foreach ( $map as $sectionKey => $sectionDetails ) {
145
+
146
+ if ( isset( $sectionDetails['fields'] ) ) {
147
+ foreach ( $sectionDetails['fields'] as $fieldKey => $fieldDetails ) {
148
+
149
+ $fields[$fieldKey] = isset( $fieldDetails['label'] ) ? $fieldDetails['label'] : $fieldKey;
150
+ }
151
+ }
152
+ }
153
+
154
+ return $fields;
155
+ }
156
+
157
+ /**
158
+ * get field map
159
+ *
160
+ * @param string $fieldKey
161
+ * @return array
162
+ */
163
+ public function fieldMap( $fieldKey ) {
164
+
165
+ $map = $this->optionMap();
166
+
167
+ foreach ( $map as $sectionKey => $sectionDetails ) {
168
+
169
+ if ( isset( $sectionDetails['fields'][$fieldKey] ) ) {
170
+ return $sectionDetails['fields'][$fieldKey];
171
+ }
172
+ }
173
+
174
+ return array();
175
+ }
176
+
177
+ /**
178
+ * get field option setting
179
+ *
180
+ * @param string $fieldKey
181
+ * @param string $optionKey
182
+ * @return null
183
+ */
184
+ public function fieldOption( $fieldKey, $optionKey ) {
185
+
186
+ $map = $this->fieldMap( $fieldKey );
187
+
188
+ if ( isset( $map[$optionKey] ) ) {
189
+ return $map[$optionKey];
190
+ } else {
191
+ return NULL;
192
+ }
193
+ }
194
+
195
+ /**
196
+ * get default options
197
+ *
198
+ * @return array
199
+ */
200
+ public function defaultOptions() {
201
+
202
+ $defaults = array();
203
+
204
+ $fields = $this->fields();
205
+ foreach ( $fields as $fieldKey => $fieldLabel ) {
206
+
207
+ $defaults[$fieldKey] = $this->fieldOption( $fieldKey, 'default' );
208
+ }
209
+
210
+ return $defaults;
211
+ }
212
+
213
+ /**
214
+ * init plugin's options to default settings
215
+ *
216
+ * @return boolean
217
+ */
218
+ function initDefaultOptions(){
219
+
220
+ $defaults = $this->defaultOptions();
221
+ return update_option( $this->optionsKey, $defaults );
222
+ }
223
+
224
+ /**
225
+ * options mapping
226
+ *
227
+ * @return array
228
+ */
229
+ public function optionMap() {
230
+
231
+ return $this->optionMap;
232
+ }
233
+ }
234
+ }
framework/readme.md ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ v1.0 - Initial bootstrap class created, initial controller created
2
+ v1.1 - Updates to bootstrap, implement autoloading. Minor controller updates
3
+ v1.2 - Adds plugin name and text domain to bootstrap and controller. Minor controller updates. Adds basic plugin user options framework. Changes to parameters passed to bootstrap and controller, update all existing plugins.
model/SBTT_Options.php ADDED
@@ -0,0 +1,261 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * SBTT Options class
4
+ *
5
+ * @author Joe Sexton <joe@josephmsexton.com>
6
+ * @package WordPress
7
+ * @subpackage scroll-back-to-top
8
+ */
9
+ if ( !class_exists( 'SBTT_Options' ) ){
10
+ class SBTT_Options extends JmsUserOptionsCollection {
11
+
12
+ /**
13
+ * @var string
14
+ */
15
+ protected $optionsGroup = 'scroll-back-to-top-options';
16
+
17
+ /**
18
+ * @var string
19
+ */
20
+ protected $optionsKey = 'scroll-back-to-top';
21
+
22
+ /**
23
+ * configure options mapping
24
+ */
25
+ public function __construct() {
26
+
27
+ $this->optionMap['visibility'] = array(
28
+ 'label' => __( 'Visibility', 'scroll-back-to-top' ),
29
+ 'description' => __( 'Button visibility status options', 'scroll-back-to-top' ),
30
+ 'fields' => array(
31
+ 'enabled' => array(
32
+ 'label' => __( 'Status', 'scroll-back-to-top' ),
33
+ 'type' => 'radio',
34
+ 'default' => 'public',
35
+ 'data_type' => 'choice',
36
+ 'choices' => array(
37
+ 'public' => __( 'Publicly Visible', 'scroll-back-to-top' ),
38
+ 'preview' => __( 'Preview Mode', 'scroll-back-to-top' ),
39
+ 'disabled' => __( 'Disabled', 'scroll-back-to-top' ),
40
+ ),
41
+ 'required' => true,
42
+ ),
43
+ ),
44
+ );
45
+ $this->optionMap['appearance'] = array(
46
+ 'label' => __( 'Button Appearance', 'scroll-back-to-top' ),
47
+ 'description' => __( 'Change the look and feel of the scroll to top button', 'scroll-back-to-top' ),
48
+ 'fields' => array(
49
+ 'size_w' => array(
50
+ 'label' => __( 'Width', 'scroll-back-to-top' ),
51
+ 'type' => 'text',
52
+ 'default' => 50,
53
+ 'min' => 0,
54
+ 'max' => 2000,
55
+ 'units' => __( 'px', 'scroll-back-to-top' ),
56
+ 'data_type' => 'integer',
57
+ 'required' => true,
58
+ ),
59
+ 'size_h' => array(
60
+ 'label' => __( 'Height', 'scroll-back-to-top' ),
61
+ 'type' => 'text',
62
+ 'default' => 50,
63
+ 'min' => 0,
64
+ 'max' => 2000,
65
+ 'units' => __( 'px', 'scroll-back-to-top' ),
66
+ 'data_type' => 'integer',
67
+ 'required' => true,
68
+ ),
69
+ 'color_background' => array(
70
+ 'label' => __( 'Background Color', 'scroll-back-to-top' ),
71
+ 'type' => 'text',
72
+ 'default' => '#777777',
73
+ 'options' => 'color-picker',
74
+ 'data_type' => 'string',
75
+ 'required' => true,
76
+ ),
77
+ 'color_hover' => array(
78
+ 'label' => __( 'Hover Color', 'scroll-back-to-top' ),
79
+ 'type' => 'text',
80
+ 'default' => '#888888',
81
+ 'options' => 'color-picker',
82
+ 'data_type' => 'string',
83
+ 'required' => true,
84
+ ),
85
+ 'color_foreground' => array(
86
+ 'label' => __( 'Foreground Color', 'scroll-back-to-top' ),
87
+ 'type' => 'text',
88
+ 'default' => '#eeeeee',
89
+ 'options' => 'color-picker',
90
+ 'data_type' => 'string',
91
+ 'required' => true,
92
+ ),
93
+ 'opacity' => array(
94
+ 'label' => __( 'Opacity', 'scroll-back-to-top' ),
95
+ 'type' => 'text',
96
+ 'default' => 100,
97
+ 'min' => 0,
98
+ 'max' => 100,
99
+ 'units' => __( '%', 'scroll-back-to-top' ),
100
+ 'data_type' => 'integer',
101
+ 'required' => true,
102
+ ),
103
+ 'border_radius' => array(
104
+ 'label' => __( 'Border Radius', 'scroll-back-to-top' ),
105
+ 'type' => 'text',
106
+ 'default' => 10,
107
+ 'min' => 0,
108
+ 'max' => 100,
109
+ 'units' => __( 'px', 'scroll-back-to-top' ),
110
+ 'data_type' => 'integer',
111
+ 'required' => true,
112
+ ),
113
+ ),
114
+ );
115
+ $this->optionMap['location'] = array(
116
+ 'label' => __( 'Button Location', 'scroll-back-to-top' ),
117
+ 'description' => __( 'Change where the button is located on the page', 'scroll-back-to-top' ),
118
+ 'fields' => array(
119
+ 'align_x' => array(
120
+ 'label' => __( 'Horizontal Alignment', 'scroll-back-to-top' ),
121
+ 'type' => 'radio',
122
+ 'default' => 'right',
123
+ 'data_type' => 'choice',
124
+ 'choices' => array(
125
+ 'left' => __( 'Left', 'scroll-back-to-top' ),
126
+ 'center' => __( 'Center', 'scroll-back-to-top' ),
127
+ 'right' => __( 'Right', 'scroll-back-to-top' ),
128
+ ),
129
+ 'required' => true,
130
+ ),
131
+ 'align_y' => array(
132
+ 'label' => __( 'Vertical Alignment', 'scroll-back-to-top' ),
133
+ 'type' => 'radio',
134
+ 'default' => 'bottom',
135
+ 'data_type' => 'choice',
136
+ 'choices' => array(
137
+ 'top' => __( 'Top', 'scroll-back-to-top' ),
138
+ 'bottom' => __( 'Bottom', 'scroll-back-to-top' ),
139
+ ),
140
+ 'required' => true,
141
+ ),
142
+ 'margin_x' => array(
143
+ 'label' => __( 'Horizontal Distance from Edge', 'scroll-back-to-top' ),
144
+ 'type' => 'text',
145
+ 'default' => 30,
146
+ 'min' => 0,
147
+ 'max' => 2000,
148
+ 'units' => __( 'px margin', 'scroll-back-to-top' ),
149
+ 'data_type' => 'integer',
150
+ 'required' => true,
151
+ ),
152
+ 'margin_y' => array(
153
+ 'label' => __( 'Vertical Distance from Edge', 'scroll-back-to-top' ),
154
+ 'type' => 'text',
155
+ 'default' => 30,
156
+ 'min' => 0,
157
+ 'max' => 2000,
158
+ 'units' => __( 'px margin', 'scroll-back-to-top' ),
159
+ 'data_type' => 'integer',
160
+ 'required' => true,
161
+ ),
162
+ ),
163
+ );
164
+ $this->optionMap['label'] = array(
165
+ 'label' => __( 'Button Label', 'scroll-back-to-top' ),
166
+ 'description' => __( 'Change what appears on the button', 'scroll-back-to-top' ),
167
+ 'fields' => array(
168
+ 'label_type' => array(
169
+ 'label' => __( 'Label Type', 'scroll-back-to-top' ),
170
+ 'type' => 'radio',
171
+ 'default' => 'fa-arrow-circle-up',
172
+ 'data_type' => 'choice',
173
+ 'choices' => array(
174
+ 'fa-angle-up' => '<i class="fa fa-angle-up fa-lg"></i>',
175
+ 'fa-angle-double-up' => '<i class="fa fa-angle-double-up fa-lg"></i>',
176
+ 'fa-arrow-up' => '<i class="fa fa-arrow-up fa-lg"></i>',
177
+ 'fa-arrow-circle-o-up' => '<i class="fa fa-arrow-circle-o-up fa-lg"></i>',
178
+ 'fa-arrow-circle-up' => '<i class="fa fa-arrow-circle-up fa-lg"></i>',
179
+ 'fa-caret-up' => '<i class="fa fa-caret-up fa-lg"></i>',
180
+ 'fa-caret-square-o-up' => '<i class="fa fa-caret-square-o-up fa-lg"></i>',
181
+ 'fa-chevron-up' => '<i class="fa fa-chevron-up fa-lg"></i>',
182
+ 'fa-chevron-circle-up' => '<i class="fa fa-chevron-circle-up fa-lg"></i>',
183
+ 'fa-hand-o-up' => '<i class="fa fa-hand-o-up fa-lg"></i>',
184
+ 'fa-long-arrow-up' => '<i class="fa fa-long-arrow-up fa-lg"></i>',
185
+ 'text' => __( 'Custom Text', 'scroll-back-to-top' ),
186
+ ),
187
+ 'required' => true,
188
+ ),
189
+ 'icon_size' => array(
190
+ 'label' => __( 'Icon Size', 'scroll-back-to-top' ),
191
+ 'type' => 'radio',
192
+ 'default' => 'fa-2x',
193
+ 'data_type' => 'choice',
194
+ 'choices' => array(
195
+ 'fa-sm' => '1',
196
+ 'fa-lg' => '2',
197
+ 'fa-2x' => '3',
198
+ 'fa-3x' => '4',
199
+ 'fa-4x' => '5',
200
+ 'fa-5x' => '6',
201
+ ),
202
+ ),
203
+ 'label_text' => array(
204
+ 'label' => __( 'Custom Label Text', 'scroll-back-to-top' ),
205
+ 'type' => 'text',
206
+ 'default' => '',
207
+ 'data_type' => 'string',
208
+ ),
209
+ 'font_size' => array(
210
+ 'label' => __( 'Font Size', 'scroll-back-to-top' ),
211
+ 'type' => 'number',
212
+ 'default' => 12,
213
+ 'min' => 0,
214
+ 'max' => 100,
215
+ 'units' => __( 'px - Using 0px will auto-size text to fit the button', 'scroll-back-to-top' ),
216
+ 'data_type' => 'integer',
217
+ ),
218
+ ),
219
+ );
220
+ $this->optionMap['behavior'] = array(
221
+ 'label' => __( 'Animation Options', 'scroll-back-to-top' ),
222
+ 'description' => __( 'Change animation options', 'scroll-back-to-top' ),
223
+ 'fields' => array(
224
+ 'scroll_duration' => array(
225
+ 'label' => __( 'Scroll Duration', 'scroll-back-to-top' ),
226
+ 'type' => 'text',
227
+ 'default' => 500,
228
+ 'min' => 0,
229
+ 'max' => 5000,
230
+ 'units' => __( 'ms', 'scroll-back-to-top' ),
231
+ 'data_type' => 'integer',
232
+ 'required' => true,
233
+ ),
234
+ 'fade_duration' => array(
235
+ 'label' => __( 'Fade Duration', 'scroll-back-to-top' ),
236
+ 'type' => 'text',
237
+ 'default' => 500,
238
+ 'min' => 0,
239
+ 'max' => 5000,
240
+ 'units' => __( 'ms', 'scroll-back-to-top' ),
241
+ 'data_type' => 'integer',
242
+ 'required' => true,
243
+ ),
244
+ ),
245
+ );
246
+ $this->optionMap['advanced'] = array(
247
+ 'label' => __( 'Advanced Options', 'scroll-back-to-top' ),
248
+ 'description' => __( 'Advanced options, this requires some knowledge of css to use.', 'scroll-back-to-top' ),
249
+ 'fields' => array(
250
+ 'extra_css' => array(
251
+ 'label' => __( 'Extra CSS', 'scroll-back-to-top' ),
252
+ 'type' => 'textarea',
253
+ 'columns' => 50,
254
+ 'rows' => 10,
255
+ 'data_type' => 'string',
256
+ ),
257
+ ),
258
+ );
259
+ }
260
+ }
261
+ }
readme.txt ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === Scroll Back To Top ===
2
+ Contributors: joesexton00
3
+ Tags: back to top, jquery, scroll to top, button, scroll, scroll top, scroll back to top, scroll up, widget, icon, scroller, vertical scroller, arrow, link to top, back to top, smooth scroll, top, back
4
+ Requires at least: 3.0
5
+ Tested up to: 3.9
6
+ Stable tag: 1.0
7
+
8
+ This plugin will add a button that allows users to scroll smoothly to the top of the page.
9
+
10
+ == Description ==
11
+
12
+ Scroll Back to Top is a Wordpress plugin to add a button that appears only when users scroll down the page allowing them to scroll to the top of the page. The plugin comes pre-configured and is fully functional on activation. The plugin offers a number of webmaster-friendly features to completely customize the look, position, and animation. In addition, there is a setting to allow you to put the button in preview mode so it only appears when logged in, which is great for configuration, then fully enable it for everyone to see! This button is built on jQuery and is designed to be dead easy, without the need to modify any markup or the theme.
13
+
14
+ = Usage =
15
+ This was built for anyone to use, with no knowledge of HTML or CSS required!
16
+
17
+ * Install the plugin through the Plugins interface or by uploading the `scroll-back-to-top` directory to your `/wp-content/plugins/` directory.
18
+ * Activate the Scroll Back to Top plugin.
19
+ * You're done, the scroll back to top button should appear on all pages after you scroll down a little bit. If you'd like to customize the design you may continue.
20
+
21
+ Optional Customization Steps
22
+
23
+ * A new setting page will be located within Settings > Scroll Back to Top, navigate to that page to for customization options.
24
+ * Change enabled status, size, color, opacity, location, icon/text, or fades.
25
+
26
+ = More Support =
27
+ More support can be found at <a target="_blank" href="http://www.webtipblog.com/scroll-back-top-wordpress-plugin">our plugin support page</a>.
28
+ <br />
29
+ <br />This plugin is developed by <a target="_blank" href="http://www.josephmsexton.com">Joe Sexton</a>
30
+
31
+ == Installation ==
32
+
33
+ 1. Install the plugin through the Plugins interface or by uploading the `scroll-back-to-top` directory to your `/wp-content/plugins/` directory.
34
+ 2. Activate the Scroll Back to Top plugin.
35
+ 3. You're done, the scroll back to top button should appear on all pages after you scroll down a little bit. If you'd like to customize the design you may continue.
36
+
37
+ Optional Customization Steps
38
+
39
+ * A new setting page will be located within Settings > Scroll Back to Top, navigate to that page to for customization options.
40
+ * Change enabled status, size, color, opacity, location, icon/text, or fades.
41
+
42
+ == Screenshots ==
43
+
44
+ 1. This plugin offers a number of configuration options to easliy customize the look and feel of the scroll up button.
45
+ 2. This is the default button that comes pre-configured with the plugin.
46
+ 3. It is possible to add custom text, color, and change the position of the button.
47
+ 4. It's also possible to make the button a circle.
48
+ 5. Easily add icons or dock the button to the edge of the screen.
49
+
50
+ == Frequently Asked Questions ==
51
+
52
+ = Does this plugin require modification to the theme? =
53
+
54
+ Absolutely not. This plugin is added/configured entirely from the website's wp-admin section.
55
+
56
+ = Does this require any knowledge of HTML or CSS? =
57
+
58
+ Absolutely not. This plugin can be configured with no knowledge of HTML or CSS, using a simple Wordpress settings page.
59
+
60
+ = Do I need to configure this plugin? =
61
+
62
+ Absolutely not. This plugin is designed to work immediately upon activation, with a nicely designed scroll back to top button ready to go.
63
+
64
+ == Change Log ==
65
+
66
+ = 1.0 =
67
+ - Initial Release
68
+
69
+ == Upgrade Notice ==
70
+
71
+ Make sure you get the latest version.
72
+
73
+ == Localization ==
74
+
75
+ = Available in English =
76
+
77
+ Want to contribute with a translation to your language? Please contact me at joe@josephmsexton.com
scroll-back-to-top.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Plugin Name: Scroll Back to Top
4
+ Description: Adds a scroll to top button
5
+ Text Domain: scroll-back-to-top
6
+ Version: 1.0
7
+ Author: Joe Sexton
8
+ Author URI: http://www.josephmsexton.com
9
+ */
10
+
11
+ require_once 'framework/JmsBootstrap.php';
12
+ $wpClassLoader = new JmsBootstrap( __FILE__, __( 'Scroll Back to Top', 'scroll-back-to-top') );
view/dynamic-styles.php ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php $test = ''; ?>
2
+ <style>
3
+ .scroll-back-to-top-wrapper {
4
+ position: fixed;
5
+ opacity: 0;
6
+ visibility: hidden;
7
+ overflow: hidden;
8
+ text-align: center;
9
+ z-index: 99999999;
10
+ <?php if ( isset( $label_type ) && $label_type == 'text' && isset( $font_size ) && $font_size != '0px' ) : ?>
11
+ font-size: <?php echo $font_size; ?>;
12
+ <?php endif; ?>
13
+ <?php if ( isset( $color_background ) ) : ?>
14
+ background-color: <?php echo $color_background; ?>;
15
+ <?php endif; ?>
16
+ <?php if ( isset( $color_foreground ) ) : ?>
17
+ color: <?php echo $color_foreground; ?>;
18
+ <?php endif; ?>
19
+ <?php if ( isset( $size_w ) ) : ?>
20
+ width: <?php echo $size_w; ?>;
21
+ <?php endif; ?>
22
+ <?php if ( isset( $size_h ) ) : ?>
23
+ height: <?php echo $size_h; ?>;
24
+ line-height: <?php echo $size_h; ?>;
25
+ <?php endif; ?>
26
+ <?php if ( isset( $margin_top ) ) : ?>
27
+ margin-top: <?php echo $margin_top; ?>;
28
+ <?php endif; ?>
29
+ <?php if ( isset( $margin_right ) ) : ?>
30
+ margin-right: <?php echo $margin_right; ?>;
31
+ <?php endif; ?>
32
+ <?php if ( isset( $margin_bottom ) ) : ?>
33
+ margin-bottom: <?php echo $margin_bottom; ?>;
34
+ <?php endif; ?>
35
+ <?php if ( isset( $margin_left ) ) : ?>
36
+ margin-left: <?php echo $margin_left; ?>;
37
+ <?php endif; ?>
38
+ <?php if ( isset( $css_top ) ) : ?>
39
+ top: <?php echo $css_top; ?>;
40
+ <?php endif; ?>
41
+ <?php if ( isset( $css_right ) ) : ?>
42
+ right: <?php echo $css_right; ?>;
43
+ <?php endif; ?>
44
+ <?php if ( isset( $css_bottom ) ) : ?>
45
+ bottom: <?php echo $css_bottom; ?>;
46
+ <?php endif; ?>
47
+ <?php if ( isset( $css_left ) ) : ?>
48
+ left: <?php echo $css_left; ?>;
49
+ <?php endif; ?>
50
+ <?php if ( isset( $padding_top ) ) : ?>
51
+ padding-top: <?php echo $padding_top; ?>;
52
+ <?php endif; ?>
53
+ <?php if ( isset( $border_radius_top_left ) ) : ?>
54
+ border-top-left-radius: <?php echo $border_radius_top_left; ?>;
55
+ <?php endif; ?>
56
+ <?php if ( isset( $border_radius_top_right ) ) : ?>
57
+ border-top-right-radius: <?php echo $border_radius_top_right; ?>;
58
+ <?php endif; ?>
59
+ <?php if ( isset( $border_radius_bottom_right ) ) : ?>
60
+ border-bottom-right-radius: <?php echo $border_radius_bottom_right; ?>;
61
+ <?php endif; ?>
62
+ <?php if ( isset( $border_radius_bottom_left ) ) : ?>
63
+ border-bottom-left-radius: <?php echo $border_radius_bottom_left; ?>;
64
+ <?php endif; ?>
65
+ <?php if ( isset( $fade_duration ) ) : ?>
66
+ -webkit-transition: all <?php echo $fade_duration; ?>s ease-in-out;
67
+ -moz-transition: all <?php echo $fade_duration; ?>s ease-in-out;
68
+ -ms-transition: all <?php echo $fade_duration; ?>s ease-in-out;
69
+ -o-transition: all <?php echo $fade_duration; ?>s ease-in-out;
70
+ transition: all <?php echo $fade_duration; ?>s ease-in-out;
71
+ <?php endif; ?>
72
+ }
73
+ .scroll-back-to-top-wrapper:hover {
74
+ <?php if ( isset( $color_hover ) ) : ?>
75
+ background-color: <?php echo $color_hover; ?>;
76
+ <?php endif; ?>
77
+ }
78
+ .scroll-back-to-top-wrapper.show {
79
+ visibility:visible;
80
+ cursor:pointer;
81
+ <?php if ( isset( $opacity ) ) : ?>
82
+ opacity: <?php echo $opacity; ?>;
83
+ <?php endif; ?>
84
+ }
85
+ .scroll-back-to-top-wrapper i.fa {
86
+ line-height: inherit;
87
+ }
88
+ .scroll-back-to-top-wrapper .fa-lg {
89
+ vertical-align: 0;
90
+ }
91
+ <?php if ( isset( $extra_css ) ) : ?>
92
+ <?php echo $extra_css; ?>
93
+ <?php endif; ?>
94
+ </style>
view/framework/admin/partials/checkbox_input.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $plugin_option_name = isset( $plugin_option_name ) ? $plugin_option_name : '';
3
+ $field_key = isset( $field_key ) ? $field_key : '';
4
+ $field_label = isset( $field_label ) ? $field_label : '';
5
+ $option_value = isset( $option_value ) ? $option_value : '';
6
+ $extra_attributes = isset( $extra_attributes ) ? $extra_attributes : '';
7
+ ?>
8
+
9
+ <label
10
+ for="<?php echo $plugin_option_name; ?>[<?php echo $field_key; ?>]"
11
+ style="margin-right:15px;"
12
+ >
13
+ <input
14
+ class="<?php echo $plugin_option_name; ?> <?php echo $field_key; ?>"
15
+ type="checkbox"
16
+ id="<?php echo $plugin_option_name; ?>[<?php echo $field_key; ?>]"
17
+ name="<?php echo $plugin_option_name; ?>[<?php echo $field_key; ?>]"
18
+ value="1"
19
+ <?php checked( $option_value, 1 ); ?>
20
+ <?php echo $extra_attributes; ?>
21
+ ><?php echo $field_label; ?>
22
+ </label>
view/framework/admin/partials/radio_input.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $plugin_option_name = isset( $plugin_option_name ) ? $plugin_option_name : '';
3
+ $field_key = isset( $field_key ) ? $field_key : '';
4
+ $choice_key = isset( $choice_key ) ? $choice_key : '';
5
+ $choice_label = isset( $choice_label ) ? $choice_label : '';
6
+ $option_value = isset( $option_value ) ? $option_value : '';
7
+ $extra_attributes = isset( $extra_attributes ) ? $extra_attributes : '';
8
+ ?>
9
+
10
+ <label
11
+ for="<?php echo $plugin_option_name; ?>[<?php echo $field_key; ?>].<?php echo $choice_key; ?>"
12
+ style="margin-right:15px;"
13
+ >
14
+ <input
15
+ class="<?php echo $plugin_option_name; ?> <?php echo $field_key; ?>"
16
+ type="radio"
17
+ id="<?php echo $plugin_option_name; ?>[<?php echo $field_key; ?>].<?php echo $choice_key; ?>"
18
+ name="<?php echo $plugin_option_name; ?>[<?php echo $field_key; ?>]"
19
+ value="<?php echo $choice_key; ?>"
20
+ <?php checked( $option_value, $choice_key ); ?>
21
+ <?php echo $extra_attributes; ?>
22
+ ><?php echo $choice_label; ?>
23
+ </label>
view/framework/admin/partials/required_indicator.php ADDED
@@ -0,0 +1 @@
 
1
+ <span class="input-required">*</span>
view/framework/admin/partials/text_input.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $plugin_option_name = isset( $plugin_option_name ) ? $plugin_option_name : '';
3
+ $field_key = isset( $field_key ) ? $field_key : '';
4
+ $option_value = isset( $option_value ) ? $option_value : '';
5
+ $input_type = isset( $input_type ) ? $input_type : '';
6
+ $extra_attributes = isset( $extra_attributes ) ? $extra_attributes : '';
7
+ $units = isset( $units ) ? $units : '';
8
+ $options = isset( $options ) ? $options : '';
9
+ ?>
10
+
11
+ <input
12
+ class="<?php echo $plugin_option_name; ?> <?php echo $field_key; ?>"
13
+ type="<?php echo $input_type != '' ? $input_type : 'text'; ?>"
14
+ id="<?php echo $plugin_option_name; ?>[<?php echo $field_key; ?>]"
15
+ name="<?php echo $plugin_option_name; ?>[<?php echo $field_key; ?>]"
16
+ value="<?php echo $option_value; ?>"
17
+ <?php echo $extra_attributes; ?>
18
+ ><small class="units"><?php echo $units; ?></small>
19
+
20
+ <?php if ( $options == 'color-picker' ) : ?>
21
+ <script> jQuery(document).ready(function($){ $('.<?php echo $field_key; ?>').wpColorPicker(); }); </script>
22
+ <?php endif; ?>
view/framework/admin/partials/textarea_input.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $plugin_option_name = isset( $plugin_option_name ) ? $plugin_option_name : '';
3
+ $field_key = isset( $field_key ) ? $field_key : '';
4
+ $option_value = isset( $option_value ) ? $option_value : '';
5
+ $extra_attributes = isset( $extra_attributes ) ? $extra_attributes : '';
6
+ ?>
7
+
8
+ <textarea
9
+ class="<?php echo $plugin_option_name; ?> <?php echo $field_key; ?>"
10
+ id="<?php echo $plugin_option_name; ?>[<?php echo $field_key; ?>]"
11
+ name="<?php echo $plugin_option_name; ?>[<?php echo $field_key; ?>]"
12
+ <?php echo $extra_attributes; ?>
13
+ ><?php echo $option_value; ?></textarea>
view/framework/admin/settings.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Admin Settings Page
4
+ *
5
+ * @author Joe Sexton <joe@josephmsexton.com>
6
+ * @package WordPress
7
+ * @subpackage JMS Plugin Framework
8
+ * @version 1.2
9
+ */
10
+ ?>
11
+
12
+ <style type="text/css">
13
+ input:disabled { background:rgba(255, 13, 13, 0.23); }
14
+ </style>
15
+
16
+ <div class="wrap">
17
+
18
+ <?php screen_icon( 'plugins' ); ?>
19
+ <h2><?php echo esc_html( get_admin_page_title() ); ?></h2>
20
+
21
+ <?php if ( isset( $option_group ) && isset( $settings_page_slug ) && isset( $option_key ) ) : ?>
22
+ <form action="options.php" method="post" id="sbtt_options_form">
23
+ <?php settings_fields( $option_group ); ?>
24
+ <?php do_settings_sections( $settings_page_slug ); ?>
25
+ <div>
26
+ <?php submit_button( null, 'primary', 'submit', false ); ?>
27
+ <?php submit_button( 'Resore Default Settings', 'secondary', $option_key . '[restore]', false ); ?>
28
+
29
+ </div>
30
+ </form>
31
+
32
+ <script>
33
+ jQuery(document).ready(function($){
34
+ $('[name="<?php echo $option_key . '[restore]'; ?>"]').on('click', function(e){
35
+ if(!confirm("<?php _e('Are you sure you want to restore defualt settings? This will erase all current settings', 'scroll-back-to-top' ); ?>")) {
36
+ e.preventDefault();
37
+ }
38
+ });
39
+ });
40
+ </script>
41
+
42
+ <?php endif; ?>
43
+ </div>
44
+
45
+
view/scroll-button.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <div class="scroll-back-to-top-wrapper">
2
+ <span class="scroll-back-to-top-inner">
3
+ <?php if ( isset( $label_type ) && $label_type == 'text' && isset( $label_text ) ) : ?>
4
+ <?php echo $label_text; ?>
5
+ <?php elseif( isset( $label_type ) && isset( $icon_size )) : ?>
6
+ <i class="fa <?php echo $icon_size; ?> <?php echo $label_type; ?>"></i>
7
+ <?php endif; ?>
8
+ </span>
9
+ </div>