Version Description
- Add: Widget support
- Add: WordPress 3.3 support
- Add: Localization support
- Add: Option to group gallery links separately (supports WordPress & NextGen galleries)
- Add: Upgrade notice
- Optimize: WP 3.3 compatibility
- Optimize: Improved compatibility with URI case-sensitivity
- Optimize: Activation processing
- Optimize: Image grouping
- Optimize: Image metadata loading performance
- Optimize: File loading
- Optimize: Improved safeguards against interference by bugs in other plugins
- Optimize: Link processing performance
- Optimize: Lightbox styling isolated from site styles
- Optimize: Improved link processing performance
- Optimize: Improved image metadata support
- Optimize: Improved support for HTTP/HTTPS requests
- Fix: SLB is not defined in JS (Jezz Hands)
- Fix: Boolean case-sensitivity (78 Truths)
- Fix: YouTube embed using iFrame overlaps lightbox (Elena in Hiding)
- Fix: Issue when scanning links without valid URLs (McCloskey Iteration)
- Fix: Image activation is case-sensitive (Sensitive Tanya)
- Fix: Visible lightbox overlay edges when image larger than browser window (Chibi Overlay)
- Fix: Options availability for some users
- Fix: Inconsistent loading of image metadata
- Fix: Links not fully processed when group is set manually
Download this release
Release Info
Developer | Archetyped |
Plugin | Simple Lightbox |
Version | 1.6 |
Comparing to | |
See all releases |
Code changes from version 1.3 to 1.6
- css/admin.css +30 -0
- css/lb_black.css +43 -0
- css/lightbox.css +145 -79
- images/closelabel_black.gif +0 -0
- images/loading_black.gif +0 -0
- images/nextlabel_black.gif +0 -0
- images/prevlabel_black.gif +0 -0
- includes/class.base.php +174 -87
- includes/class.fields.php +2251 -0
- includes/class.options.php +517 -0
- includes/class.utilities.php +1126 -77
- js/dev/effects.js +0 -1094
- js/dev/lib.dev.js +1230 -0
- js/dev/lightbox.js +0 -719
- js/dev/prototype.js +0 -3271
- js/dev/scriptaculous.js +0 -58
- js/lib.js +1228 -207
- l10n/simple-lightbox.pot +161 -0
- main.php +9 -5
- model.php +1241 -253
- readme.txt +165 -29
- templates/default/layout.html +31 -0
css/admin.css
CHANGED
@@ -1,3 +1,33 @@
|
|
1 |
.subhead {
|
2 |
margin-bottom: .2em;
|
3 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
.subhead {
|
2 |
margin-bottom: .2em;
|
3 |
}
|
4 |
+
|
5 |
+
#slb_settings {
|
6 |
+
display: block;
|
7 |
+
padding: 2em 0 0;
|
8 |
+
}
|
9 |
+
|
10 |
+
.slb_option_item .block {
|
11 |
+
display: inline-block;
|
12 |
+
}
|
13 |
+
|
14 |
+
.slb_option_item label.title {
|
15 |
+
width: 200px;
|
16 |
+
padding: 10px;
|
17 |
+
}
|
18 |
+
|
19 |
+
.slb_option_item .input {
|
20 |
+
font-size: 11px;
|
21 |
+
line-height: 20px;
|
22 |
+
margin-bottom: 9px;
|
23 |
+
padding: 8px 10px;
|
24 |
+
}
|
25 |
+
|
26 |
+
.slb_option_item .input select {
|
27 |
+
min-width: 12em;
|
28 |
+
}
|
29 |
+
|
30 |
+
.slb_notice {
|
31 |
+
color: #f00;
|
32 |
+
font-weight: bold;
|
33 |
+
}
|
css/lb_black.css
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
@import url('lightbox.css');
|
2 |
+
|
3 |
+
/* General */
|
4 |
+
|
5 |
+
#slb_viewer {
|
6 |
+
color:#fff;
|
7 |
+
}
|
8 |
+
|
9 |
+
#slb_viewer a,
|
10 |
+
#slb_viewer a:hover {
|
11 |
+
color:#fff;
|
12 |
+
}
|
13 |
+
|
14 |
+
#slb_container {
|
15 |
+
background-color: #000;
|
16 |
+
}
|
17 |
+
|
18 |
+
#slb_slbLoading {
|
19 |
+
background-image: url("../images/loading_black.gif");
|
20 |
+
}
|
21 |
+
|
22 |
+
/* Navigation */
|
23 |
+
|
24 |
+
#slb_nav_hover .slb_navPrev:hover,
|
25 |
+
#slb_nav_hover .slb_navPrev:visited:hover {
|
26 |
+
background-image: url("../images/prevlabel_black.gif");
|
27 |
+
}
|
28 |
+
|
29 |
+
#slb_nav_hover .slb_navNext:hover,
|
30 |
+
#slb_nav_hover .slb_navNext:visited:hover {
|
31 |
+
background-image: url("../images/nextlabel_black.gif");
|
32 |
+
}
|
33 |
+
|
34 |
+
#slb_close .slb_slbClose {
|
35 |
+
background-image: url("../images/closelabel_black.gif");
|
36 |
+
}
|
37 |
+
|
38 |
+
/* Content */
|
39 |
+
|
40 |
+
#slb_details {
|
41 |
+
background-color: #000;
|
42 |
+
}
|
43 |
+
|
css/lightbox.css
CHANGED
@@ -1,35 +1,61 @@
|
|
1 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
position: absolute;
|
3 |
top: 20px;
|
4 |
left: 0;
|
5 |
width: 100%;
|
6 |
-
z-index:
|
7 |
text-align: center;
|
8 |
line-height: 0;
|
9 |
color:#151410;
|
10 |
-
|
11 |
|
12 |
-
#
|
|
|
13 |
border-bottom:none;
|
14 |
color:#151410;
|
15 |
text-decoration:underline;
|
16 |
}
|
17 |
|
18 |
-
#
|
|
|
|
|
19 |
|
20 |
-
#
|
21 |
position: relative;
|
22 |
background-color: #fff;
|
23 |
width: 250px;
|
24 |
height: 250px;
|
25 |
margin: 0 auto;
|
26 |
-
|
27 |
|
28 |
-
#
|
29 |
padding: 10px;
|
30 |
-
|
31 |
|
32 |
-
#
|
33 |
position: absolute;
|
34 |
top: 40%;
|
35 |
left: 0%;
|
@@ -37,8 +63,9 @@
|
|
37 |
width: 100%;
|
38 |
text-align: center;
|
39 |
line-height: 0;
|
40 |
-
|
41 |
-
|
|
|
42 |
display:block;
|
43 |
margin:0 auto;
|
44 |
padding:0;
|
@@ -47,89 +74,128 @@
|
|
47 |
background:url("../images/loading.gif") center center no-repeat;
|
48 |
text-indent:-9999px;
|
49 |
}
|
50 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
position: absolute;
|
52 |
top: 0;
|
53 |
left: 0;
|
54 |
height: 100%;
|
55 |
width: 100%;
|
56 |
z-index: 10;
|
57 |
-
|
58 |
-
|
59 |
-
|
|
|
|
|
|
|
60 |
|
61 |
-
#
|
62 |
-
width:
|
63 |
-
|
|
|
64 |
background: transparent url("../images/blank.gif") no-repeat; /* Trick IE into showing hover */
|
65 |
display: block;
|
66 |
-
text-indent
|
67 |
-
|
68 |
-
#prevLinkImg { left: 0; float: left;}
|
69 |
-
#nextLinkImg { right: 0; float: right;}
|
70 |
-
#prevLinkImg:hover, #prevLinkImg:visited:hover { background: url("../images/prevlabel.gif") left 15% no-repeat; }
|
71 |
-
#nextLinkImg:hover, #nextLinkImg:visited:hover { background: url("../images/nextlabel.gif") right 15% no-repeat; }
|
72 |
|
|
|
|
|
|
|
73 |
|
74 |
-
#
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
#
|
85 |
-
#
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
#closeLink {
|
91 |
display:block;
|
92 |
margin:0;
|
93 |
padding:0 0 10px 0;
|
94 |
text-decoration:none;
|
95 |
-
float:right;
|
96 |
-
width:66px;
|
97 |
-
height:28px;
|
98 |
-
background:url("../images/closelabel.gif") no-repeat;
|
99 |
text-indent:-9999px;
|
100 |
overflow:hidden;
|
101 |
-
}
|
102 |
-
|
103 |
-
#overlay{
|
104 |
-
position: absolute;
|
105 |
-
top: 0;
|
106 |
-
left: 0;
|
107 |
-
z-index: 3090;
|
108 |
-
width: 100%;
|
109 |
-
height: 500px;
|
110 |
-
background-color: #151410;
|
111 |
-
filter:alpha(opacity=60);
|
112 |
-
-moz-opacity: 0.6;
|
113 |
-
opacity: 0.6;
|
114 |
-
}
|
115 |
-
|
116 |
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
height: 0;
|
121 |
-
clear: both;
|
122 |
-
visibility: hidden;
|
123 |
-
}
|
124 |
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* Reset */
|
2 |
+
#slb_viewer * {
|
3 |
+
visibility: visible;
|
4 |
+
margin: 0;
|
5 |
+
padding: 0;
|
6 |
+
line-height: 1.4em;
|
7 |
+
text-align: left;
|
8 |
+
vertical-align: baseline;
|
9 |
+
white-space: normal;
|
10 |
+
outline: none;
|
11 |
+
border: 0px;
|
12 |
+
background: none;
|
13 |
+
opacity: 1;
|
14 |
+
width: auto;
|
15 |
+
height: auto;
|
16 |
+
position: static;
|
17 |
+
float: none;
|
18 |
+
clear: none;
|
19 |
+
font-family: Verdana, Helvetica, sans-serif;
|
20 |
+
}
|
21 |
+
|
22 |
+
/* General */
|
23 |
+
|
24 |
+
#slb_viewer {
|
25 |
position: absolute;
|
26 |
top: 20px;
|
27 |
left: 0;
|
28 |
width: 100%;
|
29 |
+
z-index: 999999;
|
30 |
text-align: center;
|
31 |
line-height: 0;
|
32 |
color:#151410;
|
33 |
+
}
|
34 |
|
35 |
+
#slb_viewer a,
|
36 |
+
#slb_viewer a:hover {
|
37 |
border-bottom:none;
|
38 |
color:#151410;
|
39 |
text-decoration:underline;
|
40 |
}
|
41 |
|
42 |
+
#slb_viewer a img {
|
43 |
+
border: none;
|
44 |
+
}
|
45 |
|
46 |
+
#slb_container {
|
47 |
position: relative;
|
48 |
background-color: #fff;
|
49 |
width: 250px;
|
50 |
height: 250px;
|
51 |
margin: 0 auto;
|
52 |
+
}
|
53 |
|
54 |
+
#slb_content {
|
55 |
padding: 10px;
|
56 |
+
}
|
57 |
|
58 |
+
#slb_loading {
|
59 |
position: absolute;
|
60 |
top: 40%;
|
61 |
left: 0%;
|
63 |
width: 100%;
|
64 |
text-align: center;
|
65 |
line-height: 0;
|
66 |
+
}
|
67 |
+
|
68 |
+
#slb_slbLoading {
|
69 |
display:block;
|
70 |
margin:0 auto;
|
71 |
padding:0;
|
74 |
background:url("../images/loading.gif") center center no-repeat;
|
75 |
text-indent:-9999px;
|
76 |
}
|
77 |
+
|
78 |
+
#slb_overlay {
|
79 |
+
position: fixed;
|
80 |
+
top: 0;
|
81 |
+
left: 0;
|
82 |
+
z-index: 99999;
|
83 |
+
width: 100%;
|
84 |
+
height: 500px;
|
85 |
+
background-color: #151410;
|
86 |
+
filter:alpha(opacity=60);
|
87 |
+
-moz-opacity: 0.6;
|
88 |
+
opacity: 0.6;
|
89 |
+
}
|
90 |
+
|
91 |
+
/* Navigation */
|
92 |
+
|
93 |
+
#slb_nav .slb_navPrev,
|
94 |
+
#slb_nav .slb_navNext {
|
95 |
+
margin:0 8px 0 0;
|
96 |
+
}
|
97 |
+
|
98 |
+
#slb_nav {
|
99 |
+
display: block;
|
100 |
+
clear: left;
|
101 |
+
padding:0 0 10px 0;
|
102 |
+
}
|
103 |
+
|
104 |
+
#slb_nav_hover {
|
105 |
position: absolute;
|
106 |
top: 0;
|
107 |
left: 0;
|
108 |
height: 100%;
|
109 |
width: 100%;
|
110 |
z-index: 10;
|
111 |
+
left: 0;
|
112 |
+
}
|
113 |
+
|
114 |
+
#slb_nav_hover a {
|
115 |
+
outline: none;
|
116 |
+
}
|
117 |
|
118 |
+
#slb_nav_hover .slb_nav {
|
119 |
+
min-width: 65px;
|
120 |
+
width: 46%;
|
121 |
+
height: 98%;
|
122 |
background: transparent url("../images/blank.gif") no-repeat; /* Trick IE into showing hover */
|
123 |
display: block;
|
124 |
+
text-indent: -9999px;
|
125 |
+
}
|
|
|
|
|
|
|
|
|
126 |
|
127 |
+
#slb_nav_hover .slb_navPrev {
|
128 |
+
left: 0; float: left;
|
129 |
+
}
|
130 |
|
131 |
+
#slb_nav_hover .slb_navNext {
|
132 |
+
right: 0; float: right;
|
133 |
+
margin: 0;
|
134 |
+
}
|
135 |
+
|
136 |
+
#slb_nav_hover .slb_navPrev:hover,
|
137 |
+
#slb_nav_hover .slb_navPrev:visited:hover {
|
138 |
+
background: url("../images/prevlabel.gif") left 15% no-repeat;
|
139 |
+
}
|
140 |
+
|
141 |
+
#slb_nav_hover .slb_navNext:hover,
|
142 |
+
#slb_nav_hover .slb_navNext:visited:hover {
|
143 |
+
background: url("../images/nextlabel.gif") right 15% no-repeat;
|
144 |
+
}
|
145 |
+
|
146 |
+
.slb_slbClose {
|
|
|
147 |
display:block;
|
148 |
margin:0;
|
149 |
padding:0 0 10px 0;
|
150 |
text-decoration:none;
|
|
|
|
|
|
|
|
|
151 |
text-indent:-9999px;
|
152 |
overflow:hidden;
|
153 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
154 |
|
155 |
+
#slb_close {
|
156 |
+
float: right;
|
157 |
+
}
|
|
|
|
|
|
|
|
|
158 |
|
159 |
+
#slb_close,
|
160 |
+
#slb_close .slb_slbClose {
|
161 |
+
height:28px;
|
162 |
+
width:66px;
|
163 |
+
}
|
164 |
+
|
165 |
+
#slb_close .slb_slbClose {
|
166 |
+
background:url("../images/closelabel.gif") no-repeat;
|
167 |
+
}
|
168 |
+
|
169 |
+
/* Content */
|
170 |
+
|
171 |
+
#slb_data {
|
172 |
+
padding: 0 10px;
|
173 |
+
}
|
174 |
+
|
175 |
+
#slb_data_content {
|
176 |
+
width: 70%;
|
177 |
+
float: left;
|
178 |
+
}
|
179 |
+
|
180 |
+
.slb_dataCaption {
|
181 |
+
font-weight: bold;
|
182 |
+
}
|
183 |
+
|
184 |
+
#slb_data_desc .slb_dataDescription {
|
185 |
+
display: block;
|
186 |
+
padding: .5em 0;
|
187 |
+
}
|
188 |
+
|
189 |
+
.slb_dataNumber {
|
190 |
+
display: block;
|
191 |
+
clear: left;
|
192 |
+
}
|
193 |
+
|
194 |
+
#slb_details {
|
195 |
+
font: 10px Verdana, Helvetica, sans-serif;
|
196 |
+
background-color: #fff;
|
197 |
+
margin: 0 auto;
|
198 |
+
line-height: 1.4em;
|
199 |
+
text-align: left;
|
200 |
+
overflow: hidden;
|
201 |
+
}
|
images/closelabel_black.gif
ADDED
Binary file
|
images/loading_black.gif
ADDED
Binary file
|
images/nextlabel_black.gif
ADDED
Binary file
|
images/prevlabel_black.gif
ADDED
Binary file
|
includes/class.base.php
CHANGED
@@ -11,10 +11,37 @@ require_once 'class.utilities.php';
|
|
11 |
class SLB_Base {
|
12 |
|
13 |
/**
|
14 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
* @var string
|
16 |
*/
|
17 |
var $prefix = 'slb';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
|
19 |
/**
|
20 |
* Utilities
|
@@ -33,140 +60,200 @@ class SLB_Base {
|
|
33 |
* Constructor
|
34 |
*/
|
35 |
function __construct() {
|
36 |
-
$this->util
|
37 |
}
|
38 |
|
|
|
|
|
39 |
/**
|
40 |
* Default initialization method
|
41 |
-
* To be
|
42 |
*/
|
43 |
-
function init() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
|
|
|
|
52 |
}
|
53 |
|
54 |
/**
|
55 |
-
*
|
56 |
-
*
|
57 |
-
* @
|
58 |
-
* @param int $post_id Post ID
|
59 |
-
* @param string $key Name of metadata to retrieve
|
60 |
-
* @param boolean $single Whether or not to retrieve single value or not
|
61 |
-
* @return mixed Retrieved post metadata
|
62 |
*/
|
63 |
-
function
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
68 |
}
|
69 |
|
70 |
/**
|
71 |
-
*
|
72 |
-
*
|
73 |
-
* @return
|
74 |
*/
|
75 |
-
function
|
76 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
77 |
}
|
78 |
|
79 |
/**
|
80 |
-
*
|
81 |
-
* For internal methods
|
82 |
-
* @see add_post_meta
|
83 |
-
* @param $post_id
|
84 |
-
* @param $meta_key
|
85 |
-
* @param $meta_value
|
86 |
-
* @param $unique
|
87 |
-
* @return boolean Result of operation
|
88 |
*/
|
89 |
-
function
|
90 |
-
$
|
91 |
-
|
|
|
|
|
92 |
}
|
93 |
|
|
|
|
|
94 |
/**
|
95 |
-
*
|
96 |
-
* @
|
97 |
-
* @param $post_id
|
98 |
-
* @param $meta_key
|
99 |
-
* @param $meta_value
|
100 |
-
* @param $prev_value
|
101 |
-
* @return boolean Result of operation
|
102 |
*/
|
103 |
-
function
|
104 |
-
$
|
105 |
-
|
|
|
|
|
106 |
}
|
107 |
|
|
|
|
|
108 |
/**
|
109 |
-
*
|
110 |
-
* @param string $
|
111 |
-
* @return
|
112 |
*/
|
113 |
-
function
|
114 |
-
$
|
115 |
-
if ( strpos($key, $sep . $this->prefix) !== 0 ) {
|
116 |
-
$key_base = func_get_args();
|
117 |
-
if ( !empty($key_base) ) {
|
118 |
-
$key = array_merge((array)$this->prefix, $key_base);
|
119 |
-
return $sep . implode($sep, $key);
|
120 |
-
}
|
121 |
-
}
|
122 |
-
|
123 |
-
return $key;
|
124 |
}
|
125 |
|
|
|
|
|
126 |
/**
|
127 |
* Retrieve class prefix (with separator if set)
|
128 |
* @param bool|string $sep Separator to append to class prefix (Default: no separator)
|
129 |
* @return string Class prefix
|
130 |
*/
|
131 |
-
function get_prefix($sep =
|
132 |
-
$
|
133 |
-
|
134 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
135 |
}
|
136 |
|
137 |
/**
|
138 |
* Prepend plugin prefix to some text
|
139 |
* @param string $text Text to add to prefix
|
140 |
-
* @param string $sep Text used to separate prefix and text
|
|
|
141 |
* @return string Text with prefix prepended
|
142 |
*/
|
143 |
-
function add_prefix($text =
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
function remove_prefix($text = '', $sep = '_') {
|
148 |
-
if ( !empty($text) && strpos($text, ( $p = $this->get_prefix($sep) )) === 0 )
|
149 |
-
$text = substr($text, strlen($p));
|
150 |
-
return $text;
|
151 |
}
|
152 |
|
153 |
/**
|
154 |
-
*
|
155 |
-
*
|
156 |
-
* @
|
157 |
-
* @
|
|
|
|
|
|
|
158 |
*/
|
159 |
-
function
|
160 |
-
|
|
|
|
|
161 |
}
|
162 |
|
163 |
/**
|
164 |
-
*
|
165 |
-
* @
|
|
|
166 |
*/
|
167 |
-
function
|
168 |
-
|
169 |
-
return $
|
170 |
}
|
171 |
}
|
172 |
|
11 |
class SLB_Base {
|
12 |
|
13 |
/**
|
14 |
+
* Variable name of base object in global scope
|
15 |
+
* @var string
|
16 |
+
*/
|
17 |
+
var $base = 'slb';
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Prefix for plugin-related data (attributes, DB tables, etc.)
|
21 |
* @var string
|
22 |
*/
|
23 |
var $prefix = 'slb';
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Client files
|
27 |
+
* @var array
|
28 |
+
* Structure
|
29 |
+
* > Key: unique file ID
|
30 |
+
* > Properties
|
31 |
+
* > file (string) File path (Relative to plugin base)
|
32 |
+
* > deps (array) Script dependencies
|
33 |
+
* > Internal dependencies are wrapped in square brackets ([])
|
34 |
+
* > context (string|array)
|
35 |
+
* > Context in which the script should be included
|
36 |
+
* > in_footer (bool) optional [Default: FALSE]
|
37 |
+
* > If TRUE, file will be included in footer of page, otherwise it will be included in the header
|
38 |
+
*
|
39 |
+
* Array is processed and converted to an object on init
|
40 |
+
*/
|
41 |
+
var $client_files = array(
|
42 |
+
'scripts' => array(),
|
43 |
+
'styles' => array()
|
44 |
+
);
|
45 |
|
46 |
/**
|
47 |
* Utilities
|
60 |
* Constructor
|
61 |
*/
|
62 |
function __construct() {
|
63 |
+
$this->util = new SLB_Utilities($this);
|
64 |
}
|
65 |
|
66 |
+
/*-** Init **-*/
|
67 |
+
|
68 |
/**
|
69 |
* Default initialization method
|
70 |
+
* To be overridden by child classes
|
71 |
*/
|
72 |
+
function init() {
|
73 |
+
if ( !isset($this) )
|
74 |
+
return false;
|
75 |
+
|
76 |
+
/* Client files */
|
77 |
+
$this->init_client_files();
|
78 |
+
|
79 |
+
/* Hook */
|
80 |
+
$this->register_hooks();
|
81 |
+
|
82 |
+
/* Environment */
|
83 |
+
add_action('init', $this->m('init_env'), 1);
|
84 |
+
}
|
85 |
|
86 |
+
function register_hooks() {
|
87 |
+
//Activation
|
88 |
+
$func_activate = 'activate';
|
89 |
+
if ( method_exists($this, $func_activate) )
|
90 |
+
register_activation_hook($this->util->get_plugin_base_file(), $this->m($func_activate));
|
91 |
+
//Deactivation
|
92 |
+
$func_deactivate = 'deactivate';
|
93 |
+
if ( method_exists($this, $func_deactivate) )
|
94 |
+
register_deactivation_hook($this->util->get_plugin_base_file(), $this->m($func_deactivate));
|
95 |
}
|
96 |
|
97 |
/**
|
98 |
+
* Initialize environment (Localization, etc.)
|
99 |
+
* To be overriden by child class
|
100 |
+
* @uses `init` Action hook as trigger
|
|
|
|
|
|
|
|
|
101 |
*/
|
102 |
+
function init_env() {}
|
103 |
+
|
104 |
+
function init_client_files() {
|
105 |
+
foreach ( $this->client_files as $key => $val ) {
|
106 |
+
if ( empty($val) && isset($this->{$key}) )
|
107 |
+
$this->client_files[$key] =& $this->{$key};
|
108 |
+
$g =& $this->client_files[$key];
|
109 |
+
if ( is_array($g) && !empty($g) ) {
|
110 |
+
$g = $this->util->parse_client_files($g, $key);
|
111 |
+
}
|
112 |
+
}
|
113 |
+
|
114 |
+
//Register
|
115 |
+
add_action('init', $this->m('register_client_files'));
|
116 |
+
|
117 |
+
//Enqueue
|
118 |
+
$hook_enqueue = ( ( is_admin() ) ? 'admin' : 'wp' ) . '_enqueue_scripts' ;
|
119 |
+
add_action($hook_enqueue, $this->m('enqueue_client_files'));
|
120 |
+
}
|
121 |
+
|
122 |
+
function register_client_files() {
|
123 |
+
//Scripts
|
124 |
+
foreach ( $this->client_files as $type => $files ) {
|
125 |
+
if ( !empty($files) ) {
|
126 |
+
$func = $this->get_client_files_handler($type, 'register');
|
127 |
+
if ( !$func )
|
128 |
+
continue;
|
129 |
+
foreach ( $files as $f ) {
|
130 |
+
$params = array($f->id, $this->util->get_file_url($f->file), $f->deps, $this->util->get_plugin_version());
|
131 |
+
switch ( $type ) {
|
132 |
+
case 'scripts':
|
133 |
+
$params[] = $f->in_footer;
|
134 |
+
break;
|
135 |
+
case 'styles':
|
136 |
+
$params[] = $f->media;
|
137 |
+
break;
|
138 |
+
}
|
139 |
+
call_user_func_array($func, $params);
|
140 |
+
}
|
141 |
+
}
|
142 |
+
}
|
143 |
}
|
144 |
|
145 |
/**
|
146 |
+
* Enqueues files for client output (scripts/styles)
|
147 |
+
* Called by appropriate `enqueue_scripts` hook depending on context (admin or frontend)
|
148 |
+
* @return void
|
149 |
*/
|
150 |
+
function enqueue_client_files() {
|
151 |
+
//Enqueue files
|
152 |
+
foreach ( $this->client_files as $type => $files ) {
|
153 |
+
if ( !empty($files) ) {
|
154 |
+
$func = $this->get_client_files_handler($type, 'enqueue');
|
155 |
+
if ( !$func )
|
156 |
+
continue;
|
157 |
+
foreach ( $files as $f ) {
|
158 |
+
if ( empty($f->context) || $this->util->is_context($f->context) ) {
|
159 |
+
$func($f->id);
|
160 |
+
}
|
161 |
+
}
|
162 |
+
}
|
163 |
+
}
|
164 |
}
|
165 |
|
166 |
/**
|
167 |
+
* Build function name for handling client operations
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
168 |
*/
|
169 |
+
function get_client_files_handler($type, $action) {
|
170 |
+
$func = 'wp_' . $action . '_' . substr($type, 0, -1);
|
171 |
+
if ( !function_exists($func) )
|
172 |
+
$func = false;
|
173 |
+
return $func;
|
174 |
}
|
175 |
|
176 |
+
/*-** Reflection **-*/
|
177 |
+
|
178 |
/**
|
179 |
+
* Retrieve base object
|
180 |
+
* @return object|bool Base object (FALSE if object does not exist)
|
|
|
|
|
|
|
|
|
|
|
181 |
*/
|
182 |
+
function &get_base() {
|
183 |
+
$base = false;
|
184 |
+
if ( isset($GLOBALS[$this->base]) )
|
185 |
+
$base =& $GLOBALS[$this->base];
|
186 |
+
return $base;
|
187 |
}
|
188 |
|
189 |
+
/*-** Method/Function calling **-*/
|
190 |
+
|
191 |
/**
|
192 |
+
* Returns callback to instance method
|
193 |
+
* @param string $method Method name
|
194 |
+
* @return array Callback array
|
195 |
*/
|
196 |
+
function &m($method) {
|
197 |
+
return $this->util->m($this, $method);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
198 |
}
|
199 |
|
200 |
+
/*-** Prefix **-*/
|
201 |
+
|
202 |
/**
|
203 |
* Retrieve class prefix (with separator if set)
|
204 |
* @param bool|string $sep Separator to append to class prefix (Default: no separator)
|
205 |
* @return string Class prefix
|
206 |
*/
|
207 |
+
function get_prefix($sep = null) {
|
208 |
+
$args = func_get_args();
|
209 |
+
return call_user_func_array($this->util->m($this->util, 'get_prefix'), $args);
|
210 |
+
}
|
211 |
+
|
212 |
+
/**
|
213 |
+
* Check if a string is prefixed
|
214 |
+
* @param string $text Text to check for prefix
|
215 |
+
* @param string $sep (optional) Separator used
|
216 |
+
*/
|
217 |
+
function has_prefix($text, $sep = null) {
|
218 |
+
$args = func_get_args();
|
219 |
+
return call_user_func_array($this->util->m($this->util, 'has_prefix'), $args);
|
220 |
}
|
221 |
|
222 |
/**
|
223 |
* Prepend plugin prefix to some text
|
224 |
* @param string $text Text to add to prefix
|
225 |
+
* @param string $sep (optional) Text used to separate prefix and text
|
226 |
+
* @param bool $once (optional) Whether to add prefix to text that already contains a prefix or not
|
227 |
* @return string Text with prefix prepended
|
228 |
*/
|
229 |
+
function add_prefix($text, $sep = null, $once = true) {
|
230 |
+
$args = func_get_args();
|
231 |
+
return call_user_func_array($this->util->m($this->util, 'add_prefix'), $args);
|
|
|
|
|
|
|
|
|
|
|
232 |
}
|
233 |
|
234 |
/**
|
235 |
+
* Add prefix to variable reference
|
236 |
+
* Updates actual variable rather than return value
|
237 |
+
* @uses SLB_Utilities::add_prefix_ref();
|
238 |
+
* @param string $var Variable to add prefix to
|
239 |
+
* @param string $sep (optional) Separator text
|
240 |
+
* @param bool $once (optional) Add prefix only once
|
241 |
+
* @return void
|
242 |
*/
|
243 |
+
function add_prefix_ref(&$var, $sep = null, $once = true) {
|
244 |
+
$args = func_get_args();
|
245 |
+
$args[0] =& $var;
|
246 |
+
call_user_func_array($this->util->m($this->util, 'add_prefix_ref'), $args);
|
247 |
}
|
248 |
|
249 |
/**
|
250 |
+
* Remove prefix from specified string
|
251 |
+
* @param string $text String to remove prefix from
|
252 |
+
* @param string $sep (optional) Separator used with prefix
|
253 |
*/
|
254 |
+
function remove_prefix($text, $sep = null) {
|
255 |
+
$args = func_get_args();
|
256 |
+
return call_user_func_array($this->util->m($this->util, 'remove_prefix'), $args);
|
257 |
}
|
258 |
}
|
259 |
|
includes/class.fields.php
ADDED
@@ -0,0 +1,2251 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once 'class.base.php';
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Fields - Base class
|
7 |
+
* Core properties/methods for Content Type derivative classes
|
8 |
+
* @package Simple Lightbox
|
9 |
+
* @subpackage Fields
|
10 |
+
* @author SM
|
11 |
+
*/
|
12 |
+
class SLB_Field_Base extends SLB_Base {
|
13 |
+
/**
|
14 |
+
* @var string Unique name
|
15 |
+
*/
|
16 |
+
var $id = '';
|
17 |
+
|
18 |
+
/**
|
19 |
+
* ID formatting options
|
20 |
+
* Merged with defaults during initialization
|
21 |
+
* @see $id_formats_default
|
22 |
+
* @var array
|
23 |
+
*/
|
24 |
+
var $id_formats = null;
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Default ID Formatting options
|
28 |
+
* Structure:
|
29 |
+
* > Key (string): Format name
|
30 |
+
* > Val (array): Options
|
31 |
+
* @var array
|
32 |
+
*/
|
33 |
+
var $id_formats_default = array(
|
34 |
+
'attr_id' => array(
|
35 |
+
'wrap' => array('open' => '_', 'segment_open' => '_'),
|
36 |
+
'prefix' => array('get_container', 'get_id', 'add_prefix'),
|
37 |
+
'recursive' => true
|
38 |
+
),
|
39 |
+
'attr_name' => array(
|
40 |
+
'wrap' => array('open' => '[', 'close' => ']', 'segment_open' => '[', 'segment_close' => ']'),
|
41 |
+
'recursive' => true,
|
42 |
+
'prefix' => array('get_container', 'get_id', 'add_prefix')
|
43 |
+
)
|
44 |
+
);
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Reference to parent object that current instance inherits from
|
48 |
+
* @var object
|
49 |
+
*/
|
50 |
+
var $parent = null;
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Title
|
54 |
+
* @var string
|
55 |
+
*/
|
56 |
+
var $title = '';
|
57 |
+
|
58 |
+
/**
|
59 |
+
* @var string Short description
|
60 |
+
*/
|
61 |
+
var $description = '';
|
62 |
+
|
63 |
+
/**
|
64 |
+
* @var array Object Properties
|
65 |
+
*/
|
66 |
+
var $properties = array();
|
67 |
+
|
68 |
+
/**
|
69 |
+
* Initialization properties
|
70 |
+
* @var array
|
71 |
+
*/
|
72 |
+
var $properties_init = null;
|
73 |
+
|
74 |
+
/**
|
75 |
+
* Structure: Property names stored as keys in group
|
76 |
+
* Root
|
77 |
+
* -> Group Name
|
78 |
+
* -> Property Name => Null
|
79 |
+
* Reason: Faster searching over large arrays
|
80 |
+
* @var array Groupings of Properties
|
81 |
+
*/
|
82 |
+
var $property_groups = array();
|
83 |
+
|
84 |
+
/**
|
85 |
+
* Keys to filter out of properties array before setting properties
|
86 |
+
* @var array
|
87 |
+
*/
|
88 |
+
var $property_filter = array('group');
|
89 |
+
|
90 |
+
/**
|
91 |
+
* Data for object
|
92 |
+
* May also contain data for nested objects
|
93 |
+
* @var mixed
|
94 |
+
*/
|
95 |
+
var $data = null;
|
96 |
+
|
97 |
+
/**
|
98 |
+
* Whether data has been fetched or not
|
99 |
+
* @var bool
|
100 |
+
*/
|
101 |
+
var $data_fetched = false;
|
102 |
+
|
103 |
+
/**
|
104 |
+
* @var array Script resources to include for object
|
105 |
+
*/
|
106 |
+
var $scripts = array();
|
107 |
+
|
108 |
+
/**
|
109 |
+
* @var array CSS style resources to include for object
|
110 |
+
*/
|
111 |
+
var $styles = array();
|
112 |
+
|
113 |
+
/**
|
114 |
+
* Hooks (Filters/Actions) for object
|
115 |
+
* @var array
|
116 |
+
*/
|
117 |
+
var $hooks = array();
|
118 |
+
|
119 |
+
/**
|
120 |
+
* Mapping of child properties to parent members
|
121 |
+
* Allows more flexibility when creating new instances of child objects using property arrays
|
122 |
+
* Associative array structure:
|
123 |
+
* > Key: Child property to map FROM
|
124 |
+
* > Val: Parent property to map TO
|
125 |
+
* @var array
|
126 |
+
*/
|
127 |
+
var $map = null;
|
128 |
+
|
129 |
+
/**
|
130 |
+
* Legacy Constructor
|
131 |
+
*/
|
132 |
+
function SLB_Field_Base($id = '', $parent = null) {
|
133 |
+
$args = func_get_args();
|
134 |
+
call_user_func_array(array(&$this, '__construct'), $args);
|
135 |
+
}
|
136 |
+
|
137 |
+
/**
|
138 |
+
* Constructor
|
139 |
+
*/
|
140 |
+
function __construct($id = '', $parent = null) {
|
141 |
+
parent::__construct();
|
142 |
+
//Normalize Properties
|
143 |
+
$args = func_get_args();
|
144 |
+
if ( func_num_args() > 1 && empty($parent) ) {
|
145 |
+
unset($args[1]);
|
146 |
+
$args = array_values($args);
|
147 |
+
}
|
148 |
+
$properties = $this->make_properties($this->util->func_get_options($args), array('id' => $id, 'parent' => $parent));
|
149 |
+
//Remove empty variables
|
150 |
+
if ( empty($properties['parent']) )
|
151 |
+
unset($properties['parent']);
|
152 |
+
//Save init properties
|
153 |
+
$this->properties_init = $properties;
|
154 |
+
//Set Properties
|
155 |
+
$this->set_properties($properties);
|
156 |
+
}
|
157 |
+
|
158 |
+
/* Getters/Setters */
|
159 |
+
|
160 |
+
/**
|
161 |
+
* Checks if the specified path exists in the object
|
162 |
+
* @param array $path Path to check for
|
163 |
+
* @return bool TRUE if path exists in object, FALSE otherwise
|
164 |
+
*/
|
165 |
+
function path_isset($path = '') {
|
166 |
+
//Stop execution if no path is supplied
|
167 |
+
if ( empty($path) )
|
168 |
+
return false;
|
169 |
+
$args = func_get_args();
|
170 |
+
$path = $this->util->build_path($args);
|
171 |
+
$item =& $this;
|
172 |
+
//Iterate over path and check if each level exists before moving on to the next
|
173 |
+
for ($x = 0; $x < count($path); $x++) {
|
174 |
+
if ( $this->util->property_exists($item, $path[$x]) ) {
|
175 |
+
//Set $item as reference to next level in path for next iteration
|
176 |
+
$item =& $this->util->get_property($item, $path[$x]);
|
177 |
+
//$item =& $item[ $path[$x] ];
|
178 |
+
} else {
|
179 |
+
return false;
|
180 |
+
}
|
181 |
+
}
|
182 |
+
return true;
|
183 |
+
}
|
184 |
+
|
185 |
+
/**
|
186 |
+
* Retrieves a value from object using a specified path
|
187 |
+
* Checks to make sure path exists in object before retrieving value
|
188 |
+
* @param array $path Path to retrieve value from. Each item in array is a deeper dimension
|
189 |
+
* @return mixed Value at specified path
|
190 |
+
*/
|
191 |
+
function &get_path_value($path = '') {
|
192 |
+
$ret = '';
|
193 |
+
$path = $this->util->build_path(func_get_args());
|
194 |
+
if ( $this->path_isset($path) ) {
|
195 |
+
$ret =& $this;
|
196 |
+
for ($x = 0; $x < count($path); $x++) {
|
197 |
+
if ( 0 == $x )
|
198 |
+
$ret =& $ret->{ $path[$x] };
|
199 |
+
else
|
200 |
+
$ret =& $ret[ $path[$x] ];
|
201 |
+
}
|
202 |
+
}
|
203 |
+
return $ret;
|
204 |
+
}
|
205 |
+
|
206 |
+
/**
|
207 |
+
* Search for specified member value in field type ancestors
|
208 |
+
* @param string $member Name of object member to search (e.g. properties, layout, etc.)
|
209 |
+
* @param string $name Value to retrieve from member
|
210 |
+
* @return mixed Member value if found (Default: empty string)
|
211 |
+
*/
|
212 |
+
function get_parent_value($member, $name = '', $default = '') {
|
213 |
+
$parent =& $this->get_parent();
|
214 |
+
return $this->get_object_value($parent, $member, $name, $default, 'parent');
|
215 |
+
}
|
216 |
+
|
217 |
+
/**
|
218 |
+
* Retrieves specified member value
|
219 |
+
* Handles inherited values
|
220 |
+
* Merging corresponding parents if value is an array (e.g. for property groups)
|
221 |
+
* @param string|array $member Member to search. May also contain a path to the desired member
|
222 |
+
* @param string $name Value to retrieve from member
|
223 |
+
* @param mixed $default Default value if no value found (Default: empty string)
|
224 |
+
* @param string $dir Direction to move through hierarchy to find value
|
225 |
+
* Possible Values:
|
226 |
+
* parent (default) - Search through field parents
|
227 |
+
* current - Do not search through connected objects
|
228 |
+
* container - Search through field containers
|
229 |
+
* caller - Search through field callers
|
230 |
+
* @return mixed Specified member value
|
231 |
+
* @todo Return reference
|
232 |
+
*/
|
233 |
+
function &get_member_value($member, $name = '', $default = '', $dir = 'parent') {
|
234 |
+
//Check if path to member is supplied
|
235 |
+
$path = array();
|
236 |
+
if ( is_array($member) && isset($member['tag']) ) {
|
237 |
+
if ( isset($member['attributes']['ref_base']) ) {
|
238 |
+
if ( 'root' != $member['attributes']['ref_base'] )
|
239 |
+
$path[] = $member['attributes']['ref_base'];
|
240 |
+
} else {
|
241 |
+
$path[] = 'properties';
|
242 |
+
}
|
243 |
+
|
244 |
+
$path[] = $member['tag'];
|
245 |
+
} else {
|
246 |
+
$path = $member;
|
247 |
+
}
|
248 |
+
|
249 |
+
$path = $this->util->build_path($path, $name);
|
250 |
+
//Set defaults and prepare data
|
251 |
+
$val = $default;
|
252 |
+
$inherit = false;
|
253 |
+
$inherit_tag = '{inherit}';
|
254 |
+
|
255 |
+
/* Determine whether the value must be retrieved from a parent/container object
|
256 |
+
* Conditions:
|
257 |
+
* > Path does not exist in current field
|
258 |
+
* > Path exists and is not an object, but at least one of the following is true:
|
259 |
+
* > Value at path is an array (e.g. properties, elements, etc. array)
|
260 |
+
* > Parent/container values should be merged with retrieved array
|
261 |
+
* > Value at path is a string that inherits from another field
|
262 |
+
* > Value from other field will be retrieved and will replace inheritance placeholder in retrieved value
|
263 |
+
*/
|
264 |
+
|
265 |
+
$deeper = false;
|
266 |
+
|
267 |
+
if ( !$this->path_isset($path) )
|
268 |
+
$deeper = true;
|
269 |
+
else {
|
270 |
+
$val = $this->get_path_value($path);
|
271 |
+
if ( !is_object($val) && ( is_array($val) || ($inherit = strpos($val, $inherit_tag)) !== false ) )
|
272 |
+
$deeper = true;
|
273 |
+
else
|
274 |
+
$deeper = false;
|
275 |
+
}
|
276 |
+
if ( $deeper && 'current' != $dir ) {
|
277 |
+
//Get Parent value (recursive)
|
278 |
+
$ex_val = ( 'parent' != $dir ) ? $this->get_container_value($member, $name, $default) : $this->get_parent_value($member, $name, $default);
|
279 |
+
//Handle inheritance
|
280 |
+
if ( is_array($val) ) {
|
281 |
+
//Combine Arrays
|
282 |
+
if ( is_array($ex_val) )
|
283 |
+
$val = array_merge($ex_val, $val);
|
284 |
+
} elseif ( $inherit !== false ) {
|
285 |
+
//Replace placeholder with inherited string
|
286 |
+
$val = str_replace($inherit_tag, $ex_val, $val);
|
287 |
+
} else {
|
288 |
+
//Default: Set parent value as value
|
289 |
+
$val = $ex_val;
|
290 |
+
}
|
291 |
+
}
|
292 |
+
|
293 |
+
return $val;
|
294 |
+
}
|
295 |
+
|
296 |
+
/**
|
297 |
+
* Search for specified member value in an object
|
298 |
+
* @param object $object Reference to object to retrieve value from
|
299 |
+
* @param string $member Name of object member to search (e.g. properties, layout, etc.)
|
300 |
+
* @param string $name (optional) Value to retrieve from member
|
301 |
+
* @param mixed $default (optional) Default value to use if no value found (Default: empty string)
|
302 |
+
* @param string $dir Direction to move through hierarchy to find value @see SLB_Field_Type::get_member_value() for possible values
|
303 |
+
* @return mixed Member value if found (Default: $default)
|
304 |
+
*/
|
305 |
+
function get_object_value(&$object, $member, $name = '', $default = '', $dir = 'parent') {
|
306 |
+
$ret = $default;
|
307 |
+
if ( is_object($object) && method_exists($object, 'get_member_value') )
|
308 |
+
$ret = $object->get_member_value($member, $name, $default, $dir);
|
309 |
+
return $ret;
|
310 |
+
}
|
311 |
+
|
312 |
+
/**
|
313 |
+
* Set item ID
|
314 |
+
* @param string $id Unique item ID
|
315 |
+
*/
|
316 |
+
function set_id($id) {
|
317 |
+
if ( empty($id) || !is_string($id) )
|
318 |
+
return false;
|
319 |
+
$this->id = trim($id);
|
320 |
+
}
|
321 |
+
|
322 |
+
/**
|
323 |
+
* Retrieves field ID
|
324 |
+
* @param array|string $options (optional) Options or ID of format to use
|
325 |
+
* @return string item ID
|
326 |
+
*/
|
327 |
+
function get_id($options = array()) {
|
328 |
+
$item_id = trim($this->id);
|
329 |
+
|
330 |
+
$formats = $this->get_id_formats();
|
331 |
+
|
332 |
+
//Setup options
|
333 |
+
$wrap_default = array('open' => '', 'close' => '', 'segment_open' => '', 'segment_close' => '');
|
334 |
+
|
335 |
+
$options_default = array(
|
336 |
+
'format' => null,
|
337 |
+
'wrap' => array(),
|
338 |
+
'segments_pre' => null,
|
339 |
+
'prefix' => '',
|
340 |
+
'recursive' => false
|
341 |
+
);
|
342 |
+
|
343 |
+
//Load options based on format
|
344 |
+
if ( !is_array($options) )
|
345 |
+
$options = array('format' => $options);
|
346 |
+
if ( isset($options['format']) && is_string($options['format']) && isset($formats[$options['format']]) )
|
347 |
+
$options_default = wp_parse_args($formats[$options['format']], $options_default);
|
348 |
+
else
|
349 |
+
unset($options['format']);
|
350 |
+
$options = wp_parse_args($options, $options_default);
|
351 |
+
//Import options into function
|
352 |
+
extract($options);
|
353 |
+
|
354 |
+
//Validate options
|
355 |
+
$wrap = wp_parse_args($wrap, $wrap_default);
|
356 |
+
|
357 |
+
if ( !is_array($segments_pre) )
|
358 |
+
$segments_pre = array($segments_pre);
|
359 |
+
$segments_pre = array_reverse($segments_pre);
|
360 |
+
|
361 |
+
//Format ID based on options
|
362 |
+
|
363 |
+
$item_id = array($item_id);
|
364 |
+
|
365 |
+
//Add parent objects to ID
|
366 |
+
if ( !!$recursive ) {
|
367 |
+
//Create array of ID components
|
368 |
+
$c = $this->get_caller();
|
369 |
+
while ( !!$c ) {
|
370 |
+
//Add ID of current caller to array
|
371 |
+
if ( method_exists($c, 'get_id') && ( $itemp = $c->get_id() ) && !empty($itemp) )
|
372 |
+
$item_id = $itemp;
|
373 |
+
//Get parent object
|
374 |
+
$c = ( method_exists($c, 'get_caller') ) ? $c->get_caller() : null;
|
375 |
+
$itemp = '';
|
376 |
+
}
|
377 |
+
unset($c);
|
378 |
+
}
|
379 |
+
|
380 |
+
//Additional segments (Pre)
|
381 |
+
foreach ( $segments_pre as $seg ) {
|
382 |
+
if ( is_null($seg) )
|
383 |
+
continue;
|
384 |
+
if ( is_object($seg) )
|
385 |
+
$seg = (array)$seg;
|
386 |
+
if ( is_array($seg) )
|
387 |
+
$item_id = array_merge($item_id, array_reverse($seg));
|
388 |
+
elseif ( '' != strval($seg) )
|
389 |
+
$item_id[] = strval($seg);
|
390 |
+
}
|
391 |
+
|
392 |
+
//Prefix
|
393 |
+
if ( is_array($prefix) ) {
|
394 |
+
//Array is sequence of instance methods to call on object
|
395 |
+
//Last array member can be an array of parameters to pass to methods
|
396 |
+
$count = count($prefix);
|
397 |
+
$args = ( $count > 1 && is_array($prefix[$count - 1]) ) ? array_pop($prefix) : array();
|
398 |
+
$p = $this;
|
399 |
+
$val = '';
|
400 |
+
//Iterate through methods
|
401 |
+
foreach ( $prefix as $m ) {
|
402 |
+
//Build callback
|
403 |
+
$m = $this->util->m($p, $m);
|
404 |
+
//Call callback
|
405 |
+
if ( is_callable($m) )
|
406 |
+
$val = call_user_func_array($m, $args);
|
407 |
+
//Process returned value
|
408 |
+
if ( is_object($val) )
|
409 |
+
$p = $val; //Use returned object in next round
|
410 |
+
else
|
411 |
+
array_unshift($args, $val); //Pass returned value as parameter to next method on using current object
|
412 |
+
}
|
413 |
+
$prefix = $val;
|
414 |
+
unset($p, $val);
|
415 |
+
}
|
416 |
+
if ( is_numeric($prefix) )
|
417 |
+
$prefix = strval($prefix);
|
418 |
+
if ( empty($prefix) || !is_string($prefix) )
|
419 |
+
$prefix = '';
|
420 |
+
|
421 |
+
//Convert array to string
|
422 |
+
$item_id = $prefix . $wrap['open'] . implode($wrap['segment_close'] . $wrap['segment_open'], array_reverse($item_id)) . $wrap['close'];
|
423 |
+
return $item_id;
|
424 |
+
}
|
425 |
+
|
426 |
+
/**
|
427 |
+
* Retrieve ID formatting options for class
|
428 |
+
* Format options arrays are merged together and saved to $id_formats
|
429 |
+
* @uses $id_formats
|
430 |
+
* @uses $id_formats_default
|
431 |
+
* @return array ID Formatting options
|
432 |
+
*/
|
433 |
+
function &get_id_formats() {
|
434 |
+
if ( is_null($this->id_formats) ) {
|
435 |
+
$this->id_formats = wp_parse_args($this->id_formats, $this->id_formats_default);
|
436 |
+
}
|
437 |
+
return $this->id_formats;
|
438 |
+
}
|
439 |
+
|
440 |
+
/**
|
441 |
+
* Retrieve value from data member
|
442 |
+
* @param string $context Context to format data for
|
443 |
+
* @param bool $top (optional) Whether to traverse through the field hierarchy to get data for field (Default: TRUE)
|
444 |
+
* @return mixed Value at specified path
|
445 |
+
*/
|
446 |
+
function get_data($context = '', $top = true) {
|
447 |
+
$opt_d = array('context' => '', 'top' => true);
|
448 |
+
$args = func_get_args();
|
449 |
+
$a = false;
|
450 |
+
if ( count($args) == 1 && is_array($args[0]) && !empty($args[0]) ) {
|
451 |
+
$a = true;
|
452 |
+
$args = wp_parse_args($args[0], $opt_d);
|
453 |
+
extract($args);
|
454 |
+
}
|
455 |
+
|
456 |
+
if ( is_string($top) ) {
|
457 |
+
if ( 'false' == $top )
|
458 |
+
$top = false;
|
459 |
+
elseif ( 'true' == $top )
|
460 |
+
$top = true;
|
461 |
+
elseif ( is_numeric($top) )
|
462 |
+
$top = intval($top);
|
463 |
+
}
|
464 |
+
$top = !!$top;
|
465 |
+
$obj =& $this;
|
466 |
+
$obj_path = array(&$this);
|
467 |
+
$path = array();
|
468 |
+
if ( $top ) {
|
469 |
+
//Iterate through hiearchy to get top-most object
|
470 |
+
while ( !empty($obj) ) {
|
471 |
+
$new = null;
|
472 |
+
//Try to get caller first
|
473 |
+
if ( method_exists($obj, 'get_caller') ) {
|
474 |
+
$checked = true;
|
475 |
+
$new =& $obj->get_caller();
|
476 |
+
}
|
477 |
+
//Try to get container if no caller found
|
478 |
+
if ( empty($new) && method_exists($obj, 'get_container') ) {
|
479 |
+
$checked = true;
|
480 |
+
$new =& $obj->get_container();
|
481 |
+
//Load data
|
482 |
+
if ( method_exists($new, 'load_data') ) {
|
483 |
+
$new->load_data();
|
484 |
+
}
|
485 |
+
}
|
486 |
+
|
487 |
+
$obj =& $new;
|
488 |
+
unset($new);
|
489 |
+
//Stop iteration
|
490 |
+
if ( !empty($obj) ) {
|
491 |
+
//Add object to path if it is valid
|
492 |
+
$obj_path[] =& $obj;
|
493 |
+
}
|
494 |
+
}
|
495 |
+
unset($obj);
|
496 |
+
}
|
497 |
+
|
498 |
+
//Check each object (starting with top-most) for matching data for current field
|
499 |
+
|
500 |
+
//Reverse array
|
501 |
+
$obj_path = array_reverse($obj_path);
|
502 |
+
//Build path for data location
|
503 |
+
foreach ( $obj_path as $obj ) {
|
504 |
+
if ( method_exists($obj, 'get_id') )
|
505 |
+
$path[] = $obj->get_id();
|
506 |
+
}
|
507 |
+
//Iterate through objects
|
508 |
+
while ( !empty($obj_path) ) {
|
509 |
+
//Get next object
|
510 |
+
$obj =& array_shift($obj_path);
|
511 |
+
//Shorten path
|
512 |
+
array_shift($path);
|
513 |
+
//Check for value in object and stop iteration if matching data found
|
514 |
+
$val = $this->get_object_value($obj, 'data', $path, null, 'current');
|
515 |
+
if ( !is_null($val) ) {
|
516 |
+
break;
|
517 |
+
}
|
518 |
+
}
|
519 |
+
return $this->format($val, $context);
|
520 |
+
}
|
521 |
+
|
522 |
+
/**
|
523 |
+
* Sets value in data member
|
524 |
+
* Sets value to data member itself by default
|
525 |
+
* @param mixed $value Value to set
|
526 |
+
* @param string|array $name Name of value to set (Can also be path to value)
|
527 |
+
*/
|
528 |
+
function set_data($value, $name = '') {
|
529 |
+
$ref =& $this->get_path_value('data', $name);
|
530 |
+
$ref = $value;
|
531 |
+
}
|
532 |
+
|
533 |
+
/**
|
534 |
+
* Sets parent object of current instance
|
535 |
+
* Parent objects must be the same object type as current instance
|
536 |
+
* @uses SLB to get field type definition
|
537 |
+
* @uses SLB_Fields::has() to check if field type exists
|
538 |
+
* @uses SLB_Fields::get() to retrieve field type object reference
|
539 |
+
* @param string|object $parent Parent ID or reference
|
540 |
+
*/
|
541 |
+
function set_parent($parent = null) {
|
542 |
+
//Stop processing if parent empty
|
543 |
+
if ( empty($parent) && !is_string($this->parent) )
|
544 |
+
return false;
|
545 |
+
//Parent passed as object reference wrapped in array
|
546 |
+
if ( is_array($parent) && isset($parent[0]) && is_object($parent[0]) )
|
547 |
+
$parent =& $parent[0];
|
548 |
+
|
549 |
+
//No parent set but parent ID (previously) set in object
|
550 |
+
if ( empty($parent) && is_string($this->parent) )
|
551 |
+
$parent = $this->parent;
|
552 |
+
|
553 |
+
//Retrieve reference object if ID was supplied
|
554 |
+
if ( is_string($parent) ) {
|
555 |
+
$parent = trim($parent);
|
556 |
+
//Get parent object reference
|
557 |
+
/**
|
558 |
+
* @var SLB
|
559 |
+
*/
|
560 |
+
$b =& $this->get_base();
|
561 |
+
if ( $b && isset($b->fields) && $b->fields->has($parent) ) {
|
562 |
+
$parent =& $b->fields->get($parent);
|
563 |
+
}
|
564 |
+
}
|
565 |
+
|
566 |
+
//Set parent value on object
|
567 |
+
if ( is_string($parent) || is_object($parent) )
|
568 |
+
$this->parent =& $parent;
|
569 |
+
}
|
570 |
+
|
571 |
+
/**
|
572 |
+
* Retrieve field type parent
|
573 |
+
* @return SLB_Field_Type Reference to parent field
|
574 |
+
*/
|
575 |
+
function &get_parent() {
|
576 |
+
return $this->parent;
|
577 |
+
}
|
578 |
+
|
579 |
+
/**
|
580 |
+
* Set object title
|
581 |
+
* @param string $title Title for object
|
582 |
+
* @param string $plural Plural form of title
|
583 |
+
*/
|
584 |
+
function set_title($title = '') {
|
585 |
+
$this->title = strip_tags(trim($title));
|
586 |
+
}
|
587 |
+
|
588 |
+
/**
|
589 |
+
* Retrieve object title
|
590 |
+
*/
|
591 |
+
function get_title() {
|
592 |
+
return $this->get_member_value('title', '','', 'current');
|
593 |
+
}
|
594 |
+
|
595 |
+
/**
|
596 |
+
* Set object description
|
597 |
+
* @param string $description Description for object
|
598 |
+
*/
|
599 |
+
function set_description($description = '') {
|
600 |
+
$this->description = strip_tags(trim($description));
|
601 |
+
}
|
602 |
+
|
603 |
+
/**
|
604 |
+
* Retrieve object description
|
605 |
+
* @return string Object description
|
606 |
+
*/
|
607 |
+
function get_description() {
|
608 |
+
$dir = 'current';
|
609 |
+
return $this->get_member_value('description', '','', $dir);
|
610 |
+
return $desc;
|
611 |
+
}
|
612 |
+
|
613 |
+
/**
|
614 |
+
* Sets multiple properties on field type at once
|
615 |
+
* @param array $properties Properties. Each element is an array containing the arguments to set a new property
|
616 |
+
* @return boolean TRUE if successful, FALSE otherwise
|
617 |
+
*/
|
618 |
+
function set_properties($properties) {
|
619 |
+
if ( !is_array($properties) )
|
620 |
+
return false;
|
621 |
+
|
622 |
+
//Set Member properties
|
623 |
+
foreach ( $properties as $prop => $val ) {
|
624 |
+
if ( ( $m = 'set_' . $prop ) && method_exists($this, $m) ) {
|
625 |
+
$this->{$m}($val);
|
626 |
+
//Remove member property from array
|
627 |
+
unset($properties[$prop]);
|
628 |
+
}
|
629 |
+
}
|
630 |
+
|
631 |
+
//Filter properties
|
632 |
+
$properties = $this->filter_properties($properties);
|
633 |
+
|
634 |
+
//Set additional instance properties
|
635 |
+
foreach ( $properties as $name => $val) {
|
636 |
+
$this->set_property($name, $val);
|
637 |
+
}
|
638 |
+
}
|
639 |
+
|
640 |
+
/**
|
641 |
+
* Remap properties based on $map
|
642 |
+
* @uses $map For determine how child properties should map to parent properties
|
643 |
+
* @uses SLB_Utlities::array_remap() to perform array remapping
|
644 |
+
* @param array $properties Associative array of properties
|
645 |
+
* @return array Remapped properties
|
646 |
+
*/
|
647 |
+
function remap_properties($properties) {
|
648 |
+
//Return remapped properties
|
649 |
+
return $this->util->array_remap($properties, $this->map);
|
650 |
+
}
|
651 |
+
|
652 |
+
/**
|
653 |
+
* Build properties array
|
654 |
+
* Accepts a variable number of additional arrays of default properties
|
655 |
+
* that will be merged in order from last to first
|
656 |
+
* (e.g. first array overwrites duplicate members in last)
|
657 |
+
* @uses SLB_Field_Base::remap_properties() to remap properties members if necessary
|
658 |
+
* @param array $props Instance properties
|
659 |
+
* @param array $defaults Default properties
|
660 |
+
* @return array Normalized properties
|
661 |
+
*/
|
662 |
+
function make_properties($props, $defaults = array()) {
|
663 |
+
$args = func_get_args();
|
664 |
+
$args = array_reverse($args);
|
665 |
+
$props = array();
|
666 |
+
foreach ( $args as $arg ) {
|
667 |
+
$props = wp_parse_args($arg, $props);
|
668 |
+
}
|
669 |
+
return $this->remap_properties($props);
|
670 |
+
}
|
671 |
+
|
672 |
+
/**
|
673 |
+
* Filter property members
|
674 |
+
* @uses $property_filter to remove define members to remove from $properties
|
675 |
+
* @param array $props Properties
|
676 |
+
* @return array Filtered properties
|
677 |
+
*/
|
678 |
+
function filter_properties($props = array()) {
|
679 |
+
return $this->util->array_filter_keys($props, $this->property_filter);
|
680 |
+
}
|
681 |
+
|
682 |
+
/**
|
683 |
+
* Add/Set a property on the field definition
|
684 |
+
* @param string $name Name of property
|
685 |
+
* @param mixed $value Default value for property
|
686 |
+
* @param string|array $group Group(s) property belongs to
|
687 |
+
* @return boolean TRUE if property is successfully added to field type, FALSE otherwise
|
688 |
+
*/
|
689 |
+
function set_property($name, $value = '', $group = null) {
|
690 |
+
//Do not add if property name is not a string
|
691 |
+
if ( !is_string($name) )
|
692 |
+
return false;
|
693 |
+
//Create property array
|
694 |
+
$prop_arr = array();
|
695 |
+
$prop_arr['value'] = $value;
|
696 |
+
//Add to properties array
|
697 |
+
$this->properties[$name] = $value;
|
698 |
+
//Add property to specified groups
|
699 |
+
if ( !empty($group) ) {
|
700 |
+
$this->set_group_property($group, $name);
|
701 |
+
}
|
702 |
+
return true;
|
703 |
+
}
|
704 |
+
|
705 |
+
/**
|
706 |
+
* Retreives property from field type
|
707 |
+
* @param string $name Name of property to retrieve
|
708 |
+
* @return mixed Specified Property if exists (Default: Empty string)
|
709 |
+
*/
|
710 |
+
function get_property($name) {
|
711 |
+
$val = $this->get_member_value('properties', $name);
|
712 |
+
return $val;
|
713 |
+
}
|
714 |
+
|
715 |
+
/**
|
716 |
+
* Removes a property from item
|
717 |
+
* @param string $name Property ID
|
718 |
+
*/
|
719 |
+
function remove_property($name) {
|
720 |
+
//Remove property
|
721 |
+
if ( isset($this->properties[$name]) )
|
722 |
+
unset($this->properties[$name]);
|
723 |
+
//Remove from group
|
724 |
+
foreach ( array_keys($this->property_groups) as $g ) {
|
725 |
+
if ( isset($this->property_groups[$g][$name]) ) {
|
726 |
+
unset($this->property_groups[$g][$name]);
|
727 |
+
break;
|
728 |
+
}
|
729 |
+
}
|
730 |
+
}
|
731 |
+
|
732 |
+
/**
|
733 |
+
* Adds Specified Property to a Group
|
734 |
+
* @param string|array $group Group(s) to add property to
|
735 |
+
* @param string $property Property to add to group
|
736 |
+
*/
|
737 |
+
function set_group_property($group, $property) {
|
738 |
+
if ( is_string($group) && isset($this->property_groups[$group][$property]) )
|
739 |
+
return;
|
740 |
+
if ( !is_array($group) ) {
|
741 |
+
$group = array($group);
|
742 |
+
}
|
743 |
+
|
744 |
+
foreach ($group as $g) {
|
745 |
+
$g = trim($g);
|
746 |
+
//Initialize group if it doesn't already exist
|
747 |
+
if ( !isset($this->property_groups[$g]) )
|
748 |
+
$this->property_groups[$g] = array();
|
749 |
+
|
750 |
+
//Add property to group
|
751 |
+
$this->property_groups[$g][$property] = null;
|
752 |
+
}
|
753 |
+
}
|
754 |
+
|
755 |
+
/**
|
756 |
+
* Retrieve property group
|
757 |
+
* @param string $group Group to retrieve
|
758 |
+
* @return array Array of properties in specified group
|
759 |
+
*/
|
760 |
+
function get_group($group) {
|
761 |
+
return $this->get_member_value('property_groups', $group, array());
|
762 |
+
}
|
763 |
+
|
764 |
+
/**
|
765 |
+
* Save field data
|
766 |
+
* Child classes will define their own
|
767 |
+
* functionality for this method
|
768 |
+
* @return bool TRUE if save was successful (FALSE otherwise)
|
769 |
+
*/
|
770 |
+
function save() {
|
771 |
+
return true;
|
772 |
+
}
|
773 |
+
|
774 |
+
/*-** Hooks **-*/
|
775 |
+
|
776 |
+
/**
|
777 |
+
* Retrieve hooks added to object
|
778 |
+
* @return array Hooks
|
779 |
+
*/
|
780 |
+
function get_hooks() {
|
781 |
+
return $this->get_member_value('hooks', '', array());
|
782 |
+
}
|
783 |
+
|
784 |
+
/**
|
785 |
+
* Add hook for object
|
786 |
+
* @see add_filter() for parameter defaults
|
787 |
+
* @param $tag
|
788 |
+
* @param $function_to_add
|
789 |
+
* @param $priority
|
790 |
+
* @param $accepted_args
|
791 |
+
*/
|
792 |
+
function add_hook($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
|
793 |
+
//Create new array for tag (if not already set)
|
794 |
+
if ( !isset($this->hooks[$tag]) )
|
795 |
+
$this->hooks[$tag] = array();
|
796 |
+
//Build Unique ID
|
797 |
+
if ( is_string($function_to_add) )
|
798 |
+
$id = $function_to_add;
|
799 |
+
elseif ( is_array($function_to_add) && !empty($function_to_add) )
|
800 |
+
$id = strval($function_to_add[count($function_to_add) - 1]);
|
801 |
+
else
|
802 |
+
$id = 'function_' . ( count($this->hooks[$tag]) + 1 );
|
803 |
+
//Add hook
|
804 |
+
$this->hooks[$tag][$id] = func_get_args();
|
805 |
+
}
|
806 |
+
|
807 |
+
/**
|
808 |
+
* Convenience method for adding an action for object
|
809 |
+
* @see add_filter() for parameter defaults
|
810 |
+
* @param $tag
|
811 |
+
* @param $function_to_add
|
812 |
+
* @param $priority
|
813 |
+
* @param $accepted_args
|
814 |
+
*/
|
815 |
+
function add_action($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
|
816 |
+
$this->add_hook($tag, $function_to_add, $priority, $accepted_args);
|
817 |
+
}
|
818 |
+
|
819 |
+
/**
|
820 |
+
* Convenience method for adding a filter for object
|
821 |
+
* @see add_filter() for parameter defaults
|
822 |
+
* @param $tag
|
823 |
+
* @param $function_to_add
|
824 |
+
* @param $priority
|
825 |
+
* @param $accepted_args
|
826 |
+
*/
|
827 |
+
function add_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
|
828 |
+
$this->add_hook($tag, $function_to_add, $priority, $accepted_args);
|
829 |
+
}
|
830 |
+
|
831 |
+
/*-** Dependencies **-*/
|
832 |
+
|
833 |
+
/**
|
834 |
+
* Adds dependency to object
|
835 |
+
* @param string $type Type of dependency to add (script, style)
|
836 |
+
* @param array|string $context When dependency will be added (@see SLB_Utilities::get_action() for possible contexts)
|
837 |
+
* @see wp_enqueue_script for the following of the parameters
|
838 |
+
* @param $handle
|
839 |
+
* @param $src
|
840 |
+
* @param $deps
|
841 |
+
* @param $ver
|
842 |
+
* @param $ex
|
843 |
+
*/
|
844 |
+
function add_dependency($type, $context, $handle, $src = false, $deps = array(), $ver = false, $ex = false) {
|
845 |
+
$args = func_get_args();
|
846 |
+
//Remove type/context from arguments
|
847 |
+
$args = array_slice($args, 2);
|
848 |
+
|
849 |
+
//Set context
|
850 |
+
if ( !is_array($context) ) {
|
851 |
+
//Wrap single contexts in an array
|
852 |
+
if ( is_string($context) )
|
853 |
+
$context = array($context);
|
854 |
+
else
|
855 |
+
$context = array();
|
856 |
+
}
|
857 |
+
//Add file to instance property
|
858 |
+
if ( isset($this->{$type}) && is_array($this->{$type}) )
|
859 |
+
$this->{$type}[$handle] = array('context' => $context, 'params' => $args);
|
860 |
+
}
|
861 |
+
|
862 |
+
/**
|
863 |
+
* Add script to object to be added in specified contexts
|
864 |
+
* @param array|string $context Array of contexts to add script to page
|
865 |
+
* @see wp_enqueue_script for the following of the parameters
|
866 |
+
* @param $handle
|
867 |
+
* @param $src
|
868 |
+
* @param $deps
|
869 |
+
* @param $ver
|
870 |
+
* @param $in_footer
|
871 |
+
*/
|
872 |
+
function add_script( $context, $handle, $src = false, $deps = array(), $ver = false, $in_footer = false ) {
|
873 |
+
$args = func_get_args();
|
874 |
+
//Add file type to front of arguments array
|
875 |
+
array_unshift($args, 'scripts');
|
876 |
+
call_user_func_array($this->m('add_dependency'), $args);
|
877 |
+
}
|
878 |
+
|
879 |
+
/**
|
880 |
+
* Retrieve script dependencies for object
|
881 |
+
* @return array Script dependencies
|
882 |
+
*/
|
883 |
+
function get_scripts() {
|
884 |
+
return $this->get_member_value('scripts', '', array());
|
885 |
+
}
|
886 |
+
|
887 |
+
/**
|
888 |
+
* Add style to object to be added in specified contexts
|
889 |
+
* @param array|string $context Array of contexts to add style to page
|
890 |
+
* @see wp_enqueue_style for the following of the parameters
|
891 |
+
* @param $handle
|
892 |
+
* @param $src
|
893 |
+
* @param $deps
|
894 |
+
* @param $ver
|
895 |
+
* @param $in_footer
|
896 |
+
*/
|
897 |
+
function add_style( $handle, $src = false, $deps = array(), $ver = false, $media = false ) {
|
898 |
+
$args = func_get_args();
|
899 |
+
array_unshift($args, 'styles');
|
900 |
+
call_user_func_array($this->m('add_dependency'), $args);
|
901 |
+
}
|
902 |
+
|
903 |
+
/**
|
904 |
+
* Retrieve Style dependencies for object
|
905 |
+
* @return array Style dependencies
|
906 |
+
*/
|
907 |
+
function get_styles() {
|
908 |
+
return $this->get_member_value('styles', '', array());
|
909 |
+
}
|
910 |
+
|
911 |
+
/* Helpers */
|
912 |
+
|
913 |
+
/**
|
914 |
+
* Format value based on specified context
|
915 |
+
* @param mixed $value Value to format
|
916 |
+
* @param string $context Current context
|
917 |
+
* @return mixed Formatted value
|
918 |
+
*/
|
919 |
+
function format($value, $context = '') {
|
920 |
+
$handler = 'format_' . trim(strval($context));
|
921 |
+
//Only process if context is valid and has a handler
|
922 |
+
if ( !empty($context) && method_exists($this, $handler) ) {
|
923 |
+
//Pass value to handler
|
924 |
+
$value = $this->{$handler}($value, $context);
|
925 |
+
}
|
926 |
+
//Return formatted value
|
927 |
+
return $value;
|
928 |
+
}
|
929 |
+
|
930 |
+
/**
|
931 |
+
* Format value for output in form field
|
932 |
+
* @param mixed $value Value to format
|
933 |
+
* @return mixed Formatted value
|
934 |
+
*/
|
935 |
+
function format_form($value) {
|
936 |
+
if ( is_string($value) )
|
937 |
+
$value = htmlspecialchars($value);
|
938 |
+
return $value;
|
939 |
+
}
|
940 |
+
}
|
941 |
+
|
942 |
+
/**
|
943 |
+
* Field Types
|
944 |
+
* Stores properties for a specific field
|
945 |
+
* @package Simple Lightbox
|
946 |
+
* @subpackage Fields
|
947 |
+
* @author SM
|
948 |
+
*/
|
949 |
+
class SLB_Field_Type extends SLB_Field_Base {
|
950 |
+
/* Properties */
|
951 |
+
|
952 |
+
/**
|
953 |
+
* @var array Array of Field types that make up current Field type
|
954 |
+
*/
|
955 |
+
var $elements = array();
|
956 |
+
|
957 |
+
/**
|
958 |
+
* @var array Field type layouts
|
959 |
+
*/
|
960 |
+
var $layout = array();
|
961 |
+
|
962 |
+
/**
|
963 |
+
* @var SLB_Field_Type Parent field type (reference)
|
964 |
+
*/
|
965 |
+
var $parent = null;
|
966 |
+
|
967 |
+
/**
|
968 |
+
* Object that field is in
|
969 |
+
* @var SLB_Field|SLB_Field_Type|SLB_Field_Collection
|
970 |
+
*/
|
971 |
+
var $container = null;
|
972 |
+
|
973 |
+
/**
|
974 |
+
* Object that called field
|
975 |
+
* Used to determine field hierarchy/nesting
|
976 |
+
* @var SLB_Field|SLB_Field_Type|SLB_Field_Collection
|
977 |
+
*/
|
978 |
+
var $caller = null;
|
979 |
+
|
980 |
+
/**
|
981 |
+
* Legacy Constructor
|
982 |
+
*/
|
983 |
+
function SLB_Field_Type($id = '', $parent = null) {
|
984 |
+
$args = func_get_args();
|
985 |
+
call_user_func_array(array(&$this, '__construct'), $args);
|
986 |
+
}
|
987 |
+
|
988 |
+
function __construct($id = '', $parent = null) {
|
989 |
+
parent::__construct($id, $parent);
|
990 |
+
}
|
991 |
+
|
992 |
+
/* Getters/Setters */
|
993 |
+
|
994 |
+
/**
|
995 |
+
* Search for specified member value in field's container object (if exists)
|
996 |
+
* @param string $member Name of object member to search (e.g. properties, layout, etc.)
|
997 |
+
* @param string $name Value to retrieve from member
|
998 |
+
* @return mixed Member value if found (Default: empty string)
|
999 |
+
*/
|
1000 |
+
function get_container_value($member, $name = '', $default = '') {
|
1001 |
+
$container =& $this->get_container();
|
1002 |
+
return $this->get_object_value($container, $member, $name, $default, 'container');
|
1003 |
+
}
|
1004 |
+
|
1005 |
+
/**
|
1006 |
+
* Search for specified member value in field's container object (if exists)
|
1007 |
+
* @param string $member Name of object member to search (e.g. properties, layout, etc.)
|
1008 |
+
* @param string $name Value to retrieve from member
|
1009 |
+
* @return mixed Member value if found (Default: empty string)
|
1010 |
+
*/
|
1011 |
+
function get_caller_value($member, $name = '', $default = '') {
|
1012 |
+
$caller =& $this->get_caller();
|
1013 |
+
return $this->get_object_value($caller, $member, $name, $default, 'caller');
|
1014 |
+
}
|
1015 |
+
|
1016 |
+
/**
|
1017 |
+
* Sets reference to container object of current field
|
1018 |
+
* Reference is cleared if no valid object is passed to method
|
1019 |
+
* @param object $container
|
1020 |
+
*/
|
1021 |
+
function set_container(&$container) {
|
1022 |
+
if ( !empty($container) && is_object($container) ) {
|
1023 |
+
//Set as param as container for current field
|
1024 |
+
$this->container =& $container;
|
1025 |
+
} else {
|
1026 |
+
//Clear container member if argument is invalid
|
1027 |
+
$this->clear_container();
|
1028 |
+
}
|
1029 |
+
}
|
1030 |
+
|
1031 |
+
/**
|
1032 |
+
* Clears reference to container object of current field
|
1033 |
+
*/
|
1034 |
+
function clear_container() {
|
1035 |
+
$this->container = null;
|
1036 |
+
}
|
1037 |
+
|
1038 |
+
/**
|
1039 |
+
* Retrieves reference to container object of current field
|
1040 |
+
* @return object Reference to container object
|
1041 |
+
*/
|
1042 |
+
function &get_container() {
|
1043 |
+
$ret = null;
|
1044 |
+
if ( $this->has_container() )
|
1045 |
+
$ret =& $this->container;
|
1046 |
+
return $ret;
|
1047 |
+
}
|
1048 |
+
|
1049 |
+
/**
|
1050 |
+
* Checks if field has a container reference
|
1051 |
+
* @return bool TRUE if field is contained, FALSE otherwise
|
1052 |
+
*/
|
1053 |
+
function has_container() {
|
1054 |
+
return !empty($this->container);
|
1055 |
+
}
|
1056 |
+
|
1057 |
+
/**
|
1058 |
+
* Sets reference to calling object of current field
|
1059 |
+
* Any existing reference is cleared if no valid object is passed to method
|
1060 |
+
* @param object $caller Calling object
|
1061 |
+
*/
|
1062 |
+
function set_caller(&$caller) {
|
1063 |
+
if ( !empty($caller) && is_object($caller) )
|
1064 |
+
$this->caller =& $caller;
|
1065 |
+
else
|
1066 |
+
$this->clear_caller();
|
1067 |
+
}
|
1068 |
+
|
1069 |
+
/**
|
1070 |
+
* Clears reference to calling object of current field
|
1071 |
+
*/
|
1072 |
+
function clear_caller() {
|
1073 |
+
unset($this->caller);
|
1074 |
+
}
|
1075 |
+
|
1076 |
+
/**
|
1077 |
+
* Retrieves reference to caller object of current field
|
1078 |
+
* @return object Reference to caller object
|
1079 |
+
*/
|
1080 |
+
function &get_caller() {
|
1081 |
+
$ret = null;
|
1082 |
+
if ( $this->has_caller() )
|
1083 |
+
$ret =& $this->caller;
|
1084 |
+
return $ret;
|
1085 |
+
}
|
1086 |
+
|
1087 |
+
/**
|
1088 |
+
* Checks if field has a caller reference
|
1089 |
+
* @return bool TRUE if field is called by another field, FALSE otherwise
|
1090 |
+
*/
|
1091 |
+
function has_caller() {
|
1092 |
+
return !empty($this->caller);
|
1093 |
+
}
|
1094 |
+
|
1095 |
+
|
1096 |
+
|
1097 |
+
/**
|
1098 |
+
* Sets an element for the field type
|
1099 |
+
* @param string $name Name of element
|
1100 |
+
* @param SLB_Field_Type $type Reference of field type to use for element
|
1101 |
+
* @param array $properties Properties for element (passed as keyed associative array)
|
1102 |
+
* @param string $id_prop Name of property to set $name to (e.g. ID, etc.)
|
1103 |
+
*/
|
1104 |
+
function set_element($name, $type, $properties = array(), $id_prop = 'id') {
|
1105 |
+
$name = trim(strval($name));
|
1106 |
+
if ( empty($name) )
|
1107 |
+
return false;
|
1108 |
+
//Create new field for element
|
1109 |
+
$el = new SLB_Field($name, $type);
|
1110 |
+
//Set container to current field instance
|
1111 |
+
$el->set_container($this);
|
1112 |
+
//Add properties to element
|
1113 |
+
$el->set_properties($properties);
|
1114 |
+
//Save element to current instance
|
1115 |
+
$this->elements[$name] =& $el;
|
1116 |
+
}
|
1117 |
+
|
1118 |
+
/**
|
1119 |
+
* Add a layout to the field
|
1120 |
+
* @param string $name Name of layout
|
1121 |
+
* @param string $value Layout text
|
1122 |
+
*/
|
1123 |
+
function set_layout($name, $value = '') {
|
1124 |
+
if ( !is_string($name) )
|
1125 |
+
return false;
|
1126 |
+
$name = trim($name);
|
1127 |
+
$this->layout[$name] = $value;
|
1128 |
+
return true;
|
1129 |
+
}
|
1130 |
+
|
1131 |
+
/**
|
1132 |
+
* Retrieve specified layout
|
1133 |
+
* @param string $name Layout name
|
1134 |
+
* @param bool $parse_nested (optional) Whether nested layouts should be expanded in retreived layout or not (Default: TRUE)
|
1135 |
+
* @return string Specified layout text
|
1136 |
+
*/
|
1137 |
+
function get_layout($name = 'form', $parse_nested = true) {
|
1138 |
+
//Retrieve specified layout (use $name value if no layout by that name exists)
|
1139 |
+
$layout = $this->get_member_value('layout', $name, $name);
|
1140 |
+
|
1141 |
+
//Find all nested layouts in current layout
|
1142 |
+
if ( !empty($layout) && !!$parse_nested ) {
|
1143 |
+
$ph = $this->get_placeholder_defaults();
|
1144 |
+
|
1145 |
+
while ($ph->match = $this->parse_layout($layout, $ph->pattern_layout)) {
|
1146 |
+
//Iterate through the different types of layout placeholders
|
1147 |
+
foreach ($ph->match as $tag => $instances) {
|
1148 |
+
//Iterate through instances of a specific type of layout placeholder
|
1149 |
+
foreach ($instances as $instance) {
|
1150 |
+
//Get nested layout
|
1151 |
+
$nested_layout = $this->get_member_value($instance);
|
1152 |
+
|
1153 |
+
//Replace layout placeholder with retrieved item data
|
1154 |
+
if ( !empty($nested_layout) )
|
1155 |
+
$layout = str_replace($ph->start . $instance['match'] . $ph->end, $nested_layout, $layout);
|
1156 |
+
}
|
1157 |
+
}
|
1158 |
+
}
|
1159 |
+
}
|
1160 |
+
|
1161 |
+
return $layout;
|
1162 |
+
}
|
1163 |
+
|
1164 |
+
/**
|
1165 |
+
* Checks if specified layout exists
|
1166 |
+
* Finds layout if it exists in current object or any of its parents
|
1167 |
+
* @param string $layout Name of layout to check for
|
1168 |
+
* @return bool TRUE if layout exists, FALSE otherwise
|
1169 |
+
*/
|
1170 |
+
function has_layout($layout) {
|
1171 |
+
$ret = false;
|
1172 |
+
if ( is_string($layout) && ($layout = trim($layout)) && !empty($layout) ) {
|
1173 |
+
$layout = $this->get_member_value('layout', $layout, false);
|
1174 |
+
if ( $layout !== false )
|
1175 |
+
$ret = true;
|
1176 |
+
}
|
1177 |
+
|
1178 |
+
return $ret;
|
1179 |
+
}
|
1180 |
+
|
1181 |
+
/**
|
1182 |
+
* Checks if layout content is valid
|
1183 |
+
* Layouts need to have placeholders to be valid
|
1184 |
+
* @param string $layout_content Layout content (markup)
|
1185 |
+
* @return bool TRUE if layout is valid, FALSE otherwise
|
1186 |
+
*/
|
1187 |
+
function is_valid_layout($layout_content) {
|
1188 |
+
$ph = $this->get_placeholder_defaults();
|
1189 |
+
return preg_match($ph->pattern_general, $layout_content);
|
1190 |
+
}
|
1191 |
+
|
1192 |
+
/**
|
1193 |
+
* Parse field layout with a regular expression
|
1194 |
+
* @param string $layout Layout data
|
1195 |
+
* @param string $search Regular expression pattern to search layout for
|
1196 |
+
* @return array Associative array containing all of the regular expression matches in the layout data
|
1197 |
+
* Array Structure:
|
1198 |
+
* root => placeholder tags
|
1199 |
+
* => Tag instances (array)
|
1200 |
+
* 'tag' => (string) tag name
|
1201 |
+
* 'match' => (string) placeholder match
|
1202 |
+
* 'attributes' => (array) attributes
|
1203 |
+
*/
|
1204 |
+
function parse_layout($layout, $search) {
|
1205 |
+
$ph_xml = '';
|
1206 |
+
$parse_match = '';
|
1207 |
+
$ph_root_tag = 'ph_root_element';
|
1208 |
+
$ph_start_xml = '<';
|
1209 |
+
$ph_end_xml = ' />';
|
1210 |
+
$ph_wrap_start = '<' . $ph_root_tag . '>';
|
1211 |
+
$ph_wrap_end = '</' . $ph_root_tag . '>';
|
1212 |
+
$parse_result = false;
|
1213 |
+
|
1214 |
+
//Find all nested layouts in layout
|
1215 |
+
$match_value = preg_match_all($search, $layout, $parse_match, PREG_PATTERN_ORDER);
|
1216 |
+
|
1217 |
+
if ($match_value !== false && $match_value > 0) {
|
1218 |
+
$parse_result = array();
|
1219 |
+
//Get all matched elements
|
1220 |
+
$parse_match = $parse_match[1];
|
1221 |
+
|
1222 |
+
//Build XML string from placeholders
|
1223 |
+
foreach ($parse_match as $ph) {
|
1224 |
+
$ph_xml .= $ph_start_xml . $ph . $ph_end_xml . ' ';
|
1225 |
+
}
|
1226 |
+
$ph_xml = $ph_wrap_start . $ph_xml . $ph_wrap_end;
|
1227 |
+
//Parse XML data
|
1228 |
+
$ph_prs = xml_parser_create();
|
1229 |
+
xml_parser_set_option($ph_prs, XML_OPTION_SKIP_WHITE, 1);
|
1230 |
+
xml_parser_set_option($ph_prs, XML_OPTION_CASE_FOLDING, 0);
|
1231 |
+
$ret = xml_parse_into_struct($ph_prs, $ph_xml, $parse_result['values'], $parse_result['index']);
|
1232 |
+
xml_parser_free($ph_prs);
|
1233 |
+
|
1234 |
+
//Build structured array with all parsed data
|
1235 |
+
|
1236 |
+
unset($parse_result['index'][$ph_root_tag]);
|
1237 |
+
|
1238 |
+
//Build structured array
|
1239 |
+
$result = array();
|
1240 |
+
foreach ($parse_result['index'] as $tag => $instances) {
|
1241 |
+
$result[$tag] = array();
|
1242 |
+
//Instances
|
1243 |
+
foreach ($instances as $instance) {
|
1244 |
+
//Skip instance if it doesn't exist in parse results
|
1245 |
+
if (!isset($parse_result['values'][$instance]))
|
1246 |
+
continue;
|
1247 |
+
|
1248 |
+
//Stop processing instance if a previously-saved instance with the same options already exists
|
1249 |
+
foreach ($result[$tag] as $tag_match) {
|
1250 |
+
if ($tag_match['match'] == $parse_match[$instance - 1])
|
1251 |
+
continue 2;
|
1252 |
+
}
|
1253 |
+
|
1254 |
+
//Init instance data array
|
1255 |
+
$inst_data = array();
|
1256 |
+
|
1257 |
+
//Add Tag to array
|
1258 |
+
$inst_data['tag'] = $parse_result['values'][$instance]['tag'];
|
1259 |
+
|
1260 |
+
//Add instance data to array
|
1261 |
+
$inst_data['attributes'] = (isset($parse_result['values'][$instance]['attributes'])) ? $inst_data['attributes'] = $parse_result['values'][$instance]['attributes'] : '';
|
1262 |
+
|
1263 |
+
//Add match to array
|
1264 |
+
$inst_data['match'] = $parse_match[$instance - 1];
|
1265 |
+
|
1266 |
+
//Add to result array
|
1267 |
+
$result[$tag][] = $inst_data;
|
1268 |
+
}
|
1269 |
+
}
|
1270 |
+
$parse_result = $result;
|
1271 |
+
}
|
1272 |
+
|
1273 |
+
return $parse_result;
|
1274 |
+
}
|
1275 |
+
|
1276 |
+
/**
|
1277 |
+
* Retrieves default properties to use when evaluating layout placeholders
|
1278 |
+
* @return object Object with properties for evaluating layout placeholders
|
1279 |
+
*/
|
1280 |
+
function get_placeholder_defaults() {
|
1281 |
+
$ph = new stdClass();
|
1282 |
+
$ph->start = '{';
|
1283 |
+
$ph->end = '}';
|
1284 |
+
$ph->reserved = array('ref' => 'ref_base');
|
1285 |
+
$ph->pattern_general = '/' . $ph->start . '([a-zA-Z0-9_].*?)' . $ph->end . '/i';
|
1286 |
+
$ph->pattern_layout = '/' . $ph->start . '([a-zA-Z0-9].*?\s+' . $ph->reserved['ref'] . '="layout.*?".*?)' . $ph->end . '/i';
|
1287 |
+
return $ph;
|
1288 |
+
}
|
1289 |
+
|
1290 |
+
/**
|
1291 |
+
* Build item output
|
1292 |
+
* @param string $layout (optional) Layout to build
|
1293 |
+
* @param string $data Data to pass to layout
|
1294 |
+
* @return string Generated output
|
1295 |
+
*/
|
1296 |
+
function build($layout = 'form', $data = null) {
|
1297 |
+
$out = array(
|
1298 |
+
$this->build_pre($layout, $data),
|
1299 |
+
$this->build_layout($layout,$data),
|
1300 |
+
$this->build_post($layout, $data)
|
1301 |
+
);
|
1302 |
+
return implode('', $out);
|
1303 |
+
}
|
1304 |
+
|
1305 |
+
/**
|
1306 |
+
* Content to add before layout output
|
1307 |
+
* @return string
|
1308 |
+
*/
|
1309 |
+
function build_pre($layout = 'form', $data = null) {
|
1310 |
+
return '';
|
1311 |
+
}
|
1312 |
+
|
1313 |
+
/**
|
1314 |
+
* Content to add after layout output
|
1315 |
+
* @return string
|
1316 |
+
*/
|
1317 |
+
function build_post($layout = 'form', $data = null) {
|
1318 |
+
return '';
|
1319 |
+
}
|
1320 |
+
|
1321 |
+
/**
|
1322 |
+
* Builds HTML for a field based on its properties
|
1323 |
+
* @param string $layout (optional) Name of layout to build
|
1324 |
+
* @param array $data Additional data for current item
|
1325 |
+
*/
|
1326 |
+
function build_layout($layout = 'form', $data = null) {
|
1327 |
+
$out_default = '';
|
1328 |
+
//Get base layout
|
1329 |
+
$out = $this->get_layout($layout);
|
1330 |
+
//Only parse valid layouts
|
1331 |
+
if ( $this->is_valid_layout($out) ) {
|
1332 |
+
//Parse Layout
|
1333 |
+
$ph = $this->get_placeholder_defaults();
|
1334 |
+
|
1335 |
+
//Search layout for placeholders
|
1336 |
+
while ( $ph->match = $this->parse_layout($out, $ph->pattern_general) ) {
|
1337 |
+
//Iterate through placeholders (tag, id, etc.)
|
1338 |
+
foreach ( $ph->match as $tag => $instances ) {
|
1339 |
+
//Iterate through instances of current placeholder
|
1340 |
+
foreach ( $instances as $instance ) {
|
1341 |
+
//Process value based on placeholder name
|
1342 |
+
$target_property = apply_filters($this->add_prefix('process_placeholder_' . $tag), '', $this, $instance, $layout, $data);
|
1343 |
+
//Process value using default processors (if necessary)
|
1344 |
+
if ( '' == $target_property ) {
|
1345 |
+
$target_property = apply_filters($this->add_prefix('process_placeholder'), $target_property, $this, $instance, $layout, $data);
|
1346 |
+
}
|
1347 |
+
|
1348 |
+
//Clear value if value not a string
|
1349 |
+
if ( !is_scalar($target_property) ) {
|
1350 |
+
$target_property = '';
|
1351 |
+
}
|
1352 |
+
//Replace layout placeholder with retrieved item data
|
1353 |
+
$out = str_replace($ph->start . $instance['match'] . $ph->end, $target_property, $out);
|
1354 |
+
}
|
1355 |
+
}
|
1356 |
+
}
|
1357 |
+
} else {
|
1358 |
+
$out = $out_default;
|
1359 |
+
}
|
1360 |
+
/* Return generated value */
|
1361 |
+
return $out;
|
1362 |
+
}
|
1363 |
+
}
|
1364 |
+
|
1365 |
+
class SLB_Field extends SLB_Field_Type {}
|
1366 |
+
|
1367 |
+
/**
|
1368 |
+
* Managed collection of fields
|
1369 |
+
* @package Simple Lightbox
|
1370 |
+
* @subpackage Fields
|
1371 |
+
* @author SM
|
1372 |
+
*/
|
1373 |
+
class SLB_Field_Collection extends SLB_Field_Base {
|
1374 |
+
|
1375 |
+
/**
|
1376 |
+
* Indexed array of items in collection
|
1377 |
+
* @var array
|
1378 |
+
*/
|
1379 |
+
var $items = array();
|
1380 |
+
|
1381 |
+
/**
|
1382 |
+
* Associative array of groups in content type
|
1383 |
+
* Key: Group name
|
1384 |
+
* Value: object of group properties
|
1385 |
+
* > title
|
1386 |
+
* > description string Group description
|
1387 |
+
* > items array Items in group
|
1388 |
+
* @var array
|
1389 |
+
*/
|
1390 |
+
var $groups = array();
|
1391 |
+
|
1392 |
+
/**
|
1393 |
+
* Item type
|
1394 |
+
* @var string
|
1395 |
+
*/
|
1396 |
+
var $item_type = 'SLB_Field';
|
1397 |
+
|
1398 |
+
/* Constructors */
|
1399 |
+
|
1400 |
+
/**
|
1401 |
+
* Legacy constructor
|
1402 |
+
* @uses __construct() to init instance
|
1403 |
+
* @param string $id Content type ID
|
1404 |
+
*/
|
1405 |
+
function SLB_Field_Collection($id, $title = '', $properties = null) {
|
1406 |
+
$args = func_get_args();
|
1407 |
+
call_user_func_array(array(&$this, '__construct'), $args);
|
1408 |
+
}
|
1409 |
+
|
1410 |
+
/**
|
1411 |
+
* Class constructor
|
1412 |
+
* @param string $id Content type ID
|
1413 |
+
* @param array $properties (optional) Properties to set for content type (Default: none)
|
1414 |
+
*/
|
1415 |
+
function __construct($id, $properties = null) {
|
1416 |
+
//Parent constructor
|
1417 |
+
parent::__construct($id, $properties);
|
1418 |
+
|
1419 |
+
//Init
|
1420 |
+
$this->init();
|
1421 |
+
|
1422 |
+
//Setup object based on properties
|
1423 |
+
if ( is_array($properties) && !empty($properties) ) {
|
1424 |
+
//Groups
|
1425 |
+
if ( isset($properties['groups']) )
|
1426 |
+
$this->add_groups($properties['groups']);
|
1427 |
+
//Items
|
1428 |
+
if ( isset($properties['items']) )
|
1429 |
+
$this->add_items($properties['items']);
|
1430 |
+
}
|
1431 |
+
}
|
1432 |
+
|
1433 |
+
/*-** Getters/Setters **-*/
|
1434 |
+
|
1435 |
+
/* Data */
|
1436 |
+
|
1437 |
+
/**
|
1438 |
+
* Retrieve external data for items in collection
|
1439 |
+
* Retrieved data is saved to the collection's $data property
|
1440 |
+
* Uses class properties to determine how data is retrieved
|
1441 |
+
* Examples:
|
1442 |
+
* > DB
|
1443 |
+
* > XML
|
1444 |
+
* > JSON
|
1445 |
+
* @return void
|
1446 |
+
*/
|
1447 |
+
function load_data() {
|
1448 |
+
$this->data_fetched = true;
|
1449 |
+
}
|
1450 |
+
|
1451 |
+
/**
|
1452 |
+
* Set data for an item
|
1453 |
+
* @param string|object $item Reference or ID of Field to set data for
|
1454 |
+
* @param mixed $value Data to set
|
1455 |
+
*/
|
1456 |
+
function set_data($item, $value = '', $save = true) {
|
1457 |
+
//Set data for entire collection
|
1458 |
+
if ( 1 == func_num_args() && is_array($item) )
|
1459 |
+
$this->data = wp_parse_args($item, $this->data);
|
1460 |
+
//Get $item's ID
|
1461 |
+
elseif ( is_object($item) && method_exists($item, 'get_id') )
|
1462 |
+
$item = $item->get_id();
|
1463 |
+
//Set data
|
1464 |
+
if ( is_string($item) && !empty($item) && isset($this->items[$item]) )
|
1465 |
+
$this->data[$item] = $value;
|
1466 |
+
if ( $save )
|
1467 |
+
$this->save();
|
1468 |
+
}
|
1469 |
+
|
1470 |
+
/* Item */
|
1471 |
+
|
1472 |
+
/**
|
1473 |
+
* Adds item to collection
|
1474 |
+
* @param string $id Unique name for item
|
1475 |
+
* @param object|string $parent Field type that this item is based on
|
1476 |
+
* @param array $properties (optional) Item properties
|
1477 |
+
* @param string $group (optional) Group ID to add item to
|
1478 |
+
* @return object Reference to new item
|
1479 |
+
*/
|
1480 |
+
function &add($id, $parent = null, $properties = array(), $group = null) {
|
1481 |
+
$args = func_get_args();
|
1482 |
+
$properties = $this->make_properties($this->util->func_get_options($args), $properties, array('group' => $group));
|
1483 |
+
$it = ( is_object($id) ) ? 'O:' . $id->get_id() . '(' . get_class($id) . ')' : $id;
|
1484 |
+
//Check if previously created item is being added
|
1485 |
+
if ( is_object($id) && strtolower(get_class($id)) == strtolower($this->item_type) ) {
|
1486 |
+
$item =& $id;
|
1487 |
+
} else {
|
1488 |
+
//Create item
|
1489 |
+
if ( !class_exists($this->item_type) )
|
1490 |
+
return false;
|
1491 |
+
$type = $this->item_type;
|
1492 |
+
/**
|
1493 |
+
* @var SLB_Field
|
1494 |
+
*/
|
1495 |
+
$item = new $type($id, $properties);
|
1496 |
+
}
|
1497 |
+
if ( strlen($item->get_id()) == 0 ) {
|
1498 |
+
return false;
|
1499 |
+
}
|
1500 |
+
|
1501 |
+
$item->set_container($this);
|
1502 |
+
|
1503 |
+
//Add item to collection
|
1504 |
+
$this->items[$item->get_id()] =& $item;
|
1505 |
+
|
1506 |
+
//Add item to group
|
1507 |
+
if ( empty($group) ) {
|
1508 |
+
//Check properties array for group
|
1509 |
+
if ( isset($properties['group']) ) {
|
1510 |
+
$group = $properties['group'];
|
1511 |
+
//Remove group property from array
|
1512 |
+
unset($properties['group']);
|
1513 |
+
}
|
1514 |
+
}
|
1515 |
+
$this->add_to_group($group, $item->id);
|
1516 |
+
return $item;
|
1517 |
+
}
|
1518 |
+
|
1519 |
+
/**
|
1520 |
+
* Removes item from collection
|
1521 |
+
* @param string|object $item Object or item ID to remove
|
1522 |
+
*/
|
1523 |
+
function remove($item) {
|
1524 |
+
if ( $this->has($item) ) {
|
1525 |
+
$item = $this->get($item);
|
1526 |
+
$item = $item->get_id();
|
1527 |
+
//Remove from items array
|
1528 |
+
unset($this->items[$item]);
|
1529 |
+
//Remove item from groups
|
1530 |
+
$this->remove_from_group($item);
|
1531 |
+
}
|
1532 |
+
}
|
1533 |
+
|
1534 |
+
/**
|
1535 |
+
* Checks if item exists in the collection
|
1536 |
+
* @param string $item Item ID
|
1537 |
+
* @return bool TRUE if item exists, FALSE otherwise
|
1538 |
+
*/
|
1539 |
+
function has($item) {
|
1540 |
+
return ( !is_string($item) || empty($item) || is_null($this->get_member_value('items', $item, null)) ) ? false : true;
|
1541 |
+
}
|
1542 |
+
|
1543 |
+
/**
|
1544 |
+
* Retrieve specified item in collection
|
1545 |
+
* @param string|object $item Item object or ID to retrieve
|
1546 |
+
* @return object Specified item
|
1547 |
+
*/
|
1548 |
+
function &get($item) {
|
1549 |
+
if ( $this->has($item) ) {
|
1550 |
+
if ( !is_object($item) || !is_a($item, $this->item_type) ) {
|
1551 |
+
if ( is_string($item) ) {
|
1552 |
+
$item = trim($item);
|
1553 |
+
$item =& $this->items[$item];
|
1554 |
+
}
|
1555 |
+
else {
|
1556 |
+
$item = false;
|
1557 |
+
}
|
1558 |
+
}
|
1559 |
+
}
|
1560 |
+
|
1561 |
+
if ( empty($item) ) {
|
1562 |
+
//Return empty item if no item exists
|
1563 |
+
$item = new $this->item_type;
|
1564 |
+
}
|
1565 |
+
return $item;
|
1566 |
+
}
|
1567 |
+
|
1568 |
+
/**
|
1569 |
+
* Retrieve item data
|
1570 |
+
* @param $item
|
1571 |
+
* @param $context
|
1572 |
+
* @param $top
|
1573 |
+
*/
|
1574 |
+
function get_data($item = null, $context = '', $top = true) {
|
1575 |
+
$this->load_data();
|
1576 |
+
$ret = null;
|
1577 |
+
if ( $this->has($item) ) {
|
1578 |
+
$item =& $this->get($item);
|
1579 |
+
$ret = $item->get_data($context, $top);
|
1580 |
+
} elseif ( is_null($item) ) {
|
1581 |
+
$ret = parent::get_data($context, $top);
|
1582 |
+
}
|
1583 |
+
return $ret;
|
1584 |
+
}
|
1585 |
+
|
1586 |
+
/* Items (Collection) */
|
1587 |
+
|
1588 |
+
/**
|
1589 |
+
* Add multiple items to collection
|
1590 |
+
* @param array $items Items to add to collection
|
1591 |
+
* Array Structure:
|
1592 |
+
* > Key (string): Item ID
|
1593 |
+
* > Val (array): Item properties
|
1594 |
+
* @return void
|
1595 |
+
*/
|
1596 |
+
function add_items($items = array()) {
|
1597 |
+
//Validate
|
1598 |
+
if ( !is_array($items) || empty($items) )
|
1599 |
+
return false;
|
1600 |
+
//Iterate
|
1601 |
+
foreach ( $items as $id => $props ) {
|
1602 |
+
$this->add($id, $props);
|
1603 |
+
}
|
1604 |
+
}
|
1605 |
+
|
1606 |
+
/**
|
1607 |
+
* Retrieve reference to items in collection
|
1608 |
+
* @return array Collection items (reference)
|
1609 |
+
*/
|
1610 |
+
function &get_items($group = null) {
|
1611 |
+
if ( $this->group_exists($group) ) {
|
1612 |
+
return $this->get_group_items($group);
|
1613 |
+
}
|
1614 |
+
return $this->items;
|
1615 |
+
}
|
1616 |
+
|
1617 |
+
/**
|
1618 |
+
* Default bulk item building method
|
1619 |
+
* Children classes should implement their own functionality
|
1620 |
+
* If no group specified, all items in collection are built
|
1621 |
+
* @param string|object $group (optional) Group to build items for (ID or instance object)
|
1622 |
+
* @return void
|
1623 |
+
*/
|
1624 |
+
function build_items($group = null) {
|
1625 |
+
$items =& $this->get_items($group);
|
1626 |
+
$out = array();
|
1627 |
+
foreach ( $items as $item ) {
|
1628 |
+
$out[] = $item->build();
|
1629 |
+
}
|
1630 |
+
return implode('', $out);
|
1631 |
+
}
|
1632 |
+
|
1633 |
+
/* Group */
|
1634 |
+
|
1635 |
+
/**
|
1636 |
+
* Add groups to collection
|
1637 |
+
* @param array $groups Associative array of group properties
|
1638 |
+
* Array structure:
|
1639 |
+
* > Key (string): group ID
|
1640 |
+
* > Val (string): Group Title
|
1641 |
+
*/
|
1642 |
+
function add_groups($groups = array()) {
|
1643 |
+
//Validate
|
1644 |
+
if ( !is_array($groups) || empty($groups) )
|
1645 |
+
return false;
|
1646 |
+
//Iterate
|
1647 |
+
foreach ( $groups as $id => $props ) {
|
1648 |
+
$this->add_group($id, $props);
|
1649 |
+
}
|
1650 |
+
}
|
1651 |
+
|
1652 |
+
/**
|
1653 |
+
* Adds group to content type
|
1654 |
+
* Groups are used to display related items in the UI
|
1655 |
+
* @param string $id Unique name for group
|
1656 |
+
* @param string $title Group title
|
1657 |
+
* @param string $description Short description of group's purpose
|
1658 |
+
* @param array $items (optional) ID's of existing items to add to group
|
1659 |
+
* @return object Group object
|
1660 |
+
*/
|
1661 |
+
function &add_group($id, $title = '', $description = '', $items = array()) {
|
1662 |
+
//Create new group and set properties
|
1663 |
+
$id = trim($id);
|
1664 |
+
$this->groups[$id] =& $this->create_group($title, $description);
|
1665 |
+
//Add items to group (if supplied)
|
1666 |
+
if ( !empty($items) && is_array($items) )
|
1667 |
+
$this->add_to_group($id, $items);
|
1668 |
+
return $this->groups[$id];
|
1669 |
+
}
|
1670 |
+
|
1671 |
+
/**
|
1672 |
+
* Remove specified group from content type
|
1673 |
+
* @param string $id Group ID to remove
|
1674 |
+
*/
|
1675 |
+
function remove_group($id) {
|
1676 |
+
$id = trim($id);
|
1677 |
+
if ( $this->group_exists($id) ) {
|
1678 |
+
unset($this->groups[$id]);
|
1679 |
+
}
|
1680 |
+
}
|
1681 |
+
|
1682 |
+
/**
|
1683 |
+
* Standardized method to create a new item group
|
1684 |
+
* @param string $title Group title (used in meta boxes, etc.)
|
1685 |
+
* @param string $description Short description of group's purpose
|
1686 |
+
* @return object Group object
|
1687 |
+
*/
|
1688 |
+
function &create_group($title = '', $description = '') {
|
1689 |
+
//Create new group object
|
1690 |
+
$group = new stdClass();
|
1691 |
+
/* Set group properties */
|
1692 |
+
|
1693 |
+
//Set Title
|
1694 |
+
$title = ( is_scalar($title) ) ? trim($title) : '';
|
1695 |
+
$group->title = $title;
|
1696 |
+
//Set Description
|
1697 |
+
$description = ( is_scalar($description) ) ? trim($description) : '';
|
1698 |
+
$group->description = $description;
|
1699 |
+
//Create array to hold items
|
1700 |
+
$group->items = array();
|
1701 |
+
return $group;
|
1702 |
+
}
|
1703 |
+
|
1704 |
+
/**
|
1705 |
+
* Checks if group exists in collection
|
1706 |
+
* @param string $id Group name
|
1707 |
+
* @return bool TRUE if group exists, FALSE otherwise
|
1708 |
+
*/
|
1709 |
+
function group_exists($group) {
|
1710 |
+
$ret = false;
|
1711 |
+
if ( is_object($group) )
|
1712 |
+
$ret = true;
|
1713 |
+
elseif ( is_string($group) && ($group = trim($group)) && strlen($group) > 0 ) {
|
1714 |
+
$group = trim($group);
|
1715 |
+
//Check if group exists
|
1716 |
+
$ret = !is_null($this->get_member_value('groups', $group, null));
|
1717 |
+
}
|
1718 |
+
return $ret;
|
1719 |
+
}
|
1720 |
+
|
1721 |
+
/**
|
1722 |
+
* Adds item to a group in the collection
|
1723 |
+
* Group is created if it does not already exist
|
1724 |
+
* @param string|array $group ID of group (or group parameters if new group) to add item to
|
1725 |
+
* @param string|array $items Name or array of item(s) to add to group
|
1726 |
+
*/
|
1727 |
+
function add_to_group($group, $items) {
|
1728 |
+
//Validate parameters
|
1729 |
+
$group_id = '';
|
1730 |
+
if ( !empty($group) ) {
|
1731 |
+
if ( !is_array($group) ) {
|
1732 |
+
$group = array($group, $group);
|
1733 |
+
}
|
1734 |
+
|
1735 |
+
$group[0] = $group_id = trim(sanitize_title_with_dashes($group[0]));
|
1736 |
+
}
|
1737 |
+
if ( empty($group_id) || empty($items) )
|
1738 |
+
return false;
|
1739 |
+
//Create group if it doesn't exist
|
1740 |
+
if ( !$this->group_exists($group_id) ) {
|
1741 |
+
call_user_func_array($this->m('add_group'), $group);
|
1742 |
+
}
|
1743 |
+
if ( ! is_array($items) )
|
1744 |
+
$items = array($items);
|
1745 |
+
foreach ( $items as $item ) {
|
1746 |
+
if ( ! $this->has($item) )
|
1747 |
+
continue;
|
1748 |
+
$iref =& $this->get($item);
|
1749 |
+
//Remove item from any other group it's in (items can only be in one group)
|
1750 |
+
foreach ( array_keys($this->groups) as $group_name ) {
|
1751 |
+
if ( isset($this->groups[$group_name]->items[$iref->id]) )
|
1752 |
+
unset($this->groups[$group_name]->items[$iref->id]);
|
1753 |
+
}
|
1754 |
+
//Add reference to item in group
|
1755 |
+
$this->groups[$group_id]->items[$iref->id] =& $iref;
|
1756 |
+
unset($iref);
|
1757 |
+
}
|
1758 |
+
}
|
1759 |
+
|
1760 |
+
/**
|
1761 |
+
* Remove item from a group
|
1762 |
+
* If no group is specified, then item is removed from all groups
|
1763 |
+
* @param string|object $item Object or ID of item to remove from group
|
1764 |
+
* @param string $group (optional) Group ID to remove item from
|
1765 |
+
*/
|
1766 |
+
function remove_from_group($item, $group = '') {
|
1767 |
+
//Get ID of item to remove or stop execution if item invalid
|
1768 |
+
$item = $this->get($item);
|
1769 |
+
$item = $item->get_id();
|
1770 |
+
if ( !$item )
|
1771 |
+
return false;
|
1772 |
+
|
1773 |
+
//Remove item from group
|
1774 |
+
if ( !empty($group) ) {
|
1775 |
+
//Remove item from single group
|
1776 |
+
if ( ($group =& $this->get_group($group)) && isset($group->items[$item]) ) {
|
1777 |
+
unset($group->items[$item]);
|
1778 |
+
}
|
1779 |
+
} else {
|
1780 |
+
//Remove item from all groups
|
1781 |
+
foreach ( array_keys($this->groups) as $group ) {
|
1782 |
+
if ( ($group =& $this->get_group($group)) && isset($group->items[$item]) ) {
|
1783 |
+
unset($group->items[$item]);
|
1784 |
+
}
|
1785 |
+
}
|
1786 |
+
}
|
1787 |
+
}
|
1788 |
+
|
1789 |
+
/**
|
1790 |
+
* Retrieve specified group
|
1791 |
+
* @param string $group ID of group to retrieve
|
1792 |
+
* @return object Reference to specified group
|
1793 |
+
*/
|
1794 |
+
function &get_group($group) {
|
1795 |
+
if ( is_object($group) )
|
1796 |
+
return $group;
|
1797 |
+
if ( is_string($group) )
|
1798 |
+
$group = trim($group);
|
1799 |
+
//Create group if it doesn't already exist
|
1800 |
+
if ( ! $this->group_exists($group) )
|
1801 |
+
$this->add_group($group);
|
1802 |
+
return $this->get_member_value('groups', $group);
|
1803 |
+
}
|
1804 |
+
|
1805 |
+
/**
|
1806 |
+
* Retrieve a group's items
|
1807 |
+
* @uses SLB_Field_Collection::get_group() to retrieve group object
|
1808 |
+
* @param object|string $group Group object or group ID
|
1809 |
+
* @return array Group's items
|
1810 |
+
*/
|
1811 |
+
function &get_group_items($group) {
|
1812 |
+
$group =& $this->get_group($group);
|
1813 |
+
return $group->items;
|
1814 |
+
}
|
1815 |
+
|
1816 |
+
/**
|
1817 |
+
* Retrieve all groups in content type
|
1818 |
+
* @return array Reference to group objects
|
1819 |
+
*/
|
1820 |
+
function &get_groups() {
|
1821 |
+
return $this->get_member_value('groups');
|
1822 |
+
}
|
1823 |
+
|
1824 |
+
/**
|
1825 |
+
* Output items in a group
|
1826 |
+
* @param string $group ID of Group to output
|
1827 |
+
* @return string Group output
|
1828 |
+
* @todo Refactor to be general builder
|
1829 |
+
*/
|
1830 |
+
function build_group($group) {
|
1831 |
+
$out = array();
|
1832 |
+
$classnames = (object) array(
|
1833 |
+
'multi' => 'multi_field',
|
1834 |
+
'single' => 'single_field',
|
1835 |
+
'elements' => 'has_elements'
|
1836 |
+
);
|
1837 |
+
|
1838 |
+
//Stop execution if group does not exist
|
1839 |
+
if ( $this->group_exists($group) && $group =& $this->get_group($group) ) {
|
1840 |
+
$group_items = ( count($group->items) > 1 ) ? $classnames->multi : $classnames->single . ( ( ( $fs = array_keys($group->items) ) && ( $f =& $group->items[$fs[0]] ) && ( $els = $f->get_member_value('elements', '', null) ) && !empty($els) ) ? '_' . $classnames->elements : '' );
|
1841 |
+
$classname = array($this->add_prefix('attributes_wrap'), $group_items);
|
1842 |
+
$out[] = '<div class="' . implode(' ', $classname) . '">'; //Wrap all items in group
|
1843 |
+
|
1844 |
+
//Build layout for each item in group
|
1845 |
+
foreach ( array_keys($group->items) as $item_id ) {
|
1846 |
+
$item =& $group->items[$item_id];
|
1847 |
+
$item->set_caller($this);
|
1848 |
+
//Start item output
|
1849 |
+
$id = $this->add_prefix('field_' . $item->get_id());
|
1850 |
+
$out[] = '<div id="' . $id . '_wrap" class=' . $this->add_prefix('attribute_wrap') . '>';
|
1851 |
+
//Build item layout
|
1852 |
+
$out[] = $item->build_layout();
|
1853 |
+
//end item output
|
1854 |
+
$out[] = '</div>';
|
1855 |
+
$item->clear_caller();
|
1856 |
+
}
|
1857 |
+
$out[] = '</div>'; //Close items container
|
1858 |
+
//Add description if exists
|
1859 |
+
if ( !empty($group->description) )
|
1860 |
+
$out[] = '<p class=' . $this->add_prefix('group_description') . '>' . $group->description . '</p>';
|
1861 |
+
}
|
1862 |
+
|
1863 |
+
//Return group output
|
1864 |
+
return implode($out);
|
1865 |
+
}
|
1866 |
+
|
1867 |
+
/* Collection */
|
1868 |
+
|
1869 |
+
/**
|
1870 |
+
* Build entire collection of items
|
1871 |
+
*/
|
1872 |
+
function build() {
|
1873 |
+
//Get Groups
|
1874 |
+
$groups = array_keys($this->get_groups());
|
1875 |
+
//Build groups
|
1876 |
+
foreach ( $groups as $group ) {
|
1877 |
+
$this->build_group($group);
|
1878 |
+
}
|
1879 |
+
}
|
1880 |
+
}
|
1881 |
+
|
1882 |
+
/**
|
1883 |
+
* Collection of default system-wide fields
|
1884 |
+
* @package Simple Lightbox
|
1885 |
+
* @subpackage Fields
|
1886 |
+
* @author SM
|
1887 |
+
*
|
1888 |
+
*/
|
1889 |
+
class SLB_Fields extends SLB_Field_Collection {
|
1890 |
+
|
1891 |
+
var $item_type = 'SLB_Field_Type';
|
1892 |
+
|
1893 |
+
/**
|
1894 |
+
* Placeholder handlers
|
1895 |
+
* @var array
|
1896 |
+
*/
|
1897 |
+
var $placholders = null;
|
1898 |
+
|
1899 |
+
/* Constructor */
|
1900 |
+
|
1901 |
+
function SLB_Fields() {
|
1902 |
+
$this->__construct();
|
1903 |
+
}
|
1904 |
+
|
1905 |
+
function __construct() {
|
1906 |
+
parent::__construct('fields');
|
1907 |
+
}
|
1908 |
+
|
1909 |
+
function register_hooks() {
|
1910 |
+
parent::register_hooks();
|
1911 |
+
|
1912 |
+
//Init fields
|
1913 |
+
add_action('init', $this->m('register_types'));
|
1914 |
+
//Init placeholders
|
1915 |
+
add_action('init', $this->m('register_placeholders'));
|
1916 |
+
}
|
1917 |
+
|
1918 |
+
/* Field Types */
|
1919 |
+
|
1920 |
+
/**
|
1921 |
+
* Initialize fields and content types
|
1922 |
+
*/
|
1923 |
+
function register_types() {
|
1924 |
+
/* Field Types */
|
1925 |
+
|
1926 |
+
//Base
|
1927 |
+
$base = new SLB_Field_Type('base');
|
1928 |
+
$base->set_description('Default Element');
|
1929 |
+
$base->set_property('tag', 'span');
|
1930 |
+
$base->set_property('class', '', 'attr');
|
1931 |
+
$base->set_layout('form_attr', '{tag} name="{field_name}" id="{field_id}" {properties ref_base="root" group="attr"}');
|
1932 |
+
$base->set_layout('form', '<{form_attr ref_base="layout"} />');
|
1933 |
+
$base->set_layout('label', '<label for="{field_id}">{label}</label>');
|
1934 |
+
$base->set_layout('display', '{data context="display"}');
|
1935 |
+
$this->add($base);
|
1936 |
+
|
1937 |
+
//Base closed
|
1938 |
+
$base_closed = new SLB_Field_Type('base_closed');
|
1939 |
+
$base_closed->set_parent('base');
|
1940 |
+
$base_closed->set_description('Default Element (Closed Tag)');
|
1941 |
+
$base_closed->set_layout('form_start', '<{tag} id="{field_id}" name="{field_name}" {properties ref_base="root" group="attr"}>');
|
1942 |
+
$base_closed->set_layout('form_end', '</{tag}>');
|
1943 |
+
$base_closed->set_layout('form', '{form_start ref_base="layout"}{data}{form_end ref_base="layout"}');
|
1944 |
+
$this->add($base_closed);
|
1945 |
+
|
1946 |
+
//Input
|
1947 |
+
$input = new SLB_Field_Type('input', 'base');
|
1948 |
+
$input->set_description('Default Input Element');
|
1949 |
+
$input->set_property('tag', 'input');
|
1950 |
+
$input->set_property('type', 'text', 'attr');
|
1951 |
+
$input->set_property('value', '{data}', 'attr');
|
1952 |
+
$this->add($input);
|
1953 |
+
|
1954 |
+
//Text input
|
1955 |
+
$text = new SLB_Field_Type('text', 'input');
|
1956 |
+
$text->set_description('Text Box');
|
1957 |
+
$text->set_property('size', 15, 'attr');
|
1958 |
+
$text->set_property('label');
|
1959 |
+
$text->set_layout('form', '{label ref_base="layout"} {inherit}');
|
1960 |
+
$this->add($text);
|
1961 |
+
|
1962 |
+
//Checkbox
|
1963 |
+
$cb = new SLB_Field_Type('checkbox', 'input');
|
1964 |
+
$cb->set_property('type', 'checkbox');
|
1965 |
+
$cb->set_property('value', null);
|
1966 |
+
$cb->set_layout('form_attr', '{inherit} {checked}');
|
1967 |
+
$cb->set_layout('form', '{label ref_base="layout"} <{form_attr ref_base="layout"} />');
|
1968 |
+
$this->add($cb);
|
1969 |
+
|
1970 |
+
//Textarea
|
1971 |
+
$ta = new SLB_Field_Type('textarea', 'base_closed');
|
1972 |
+
$ta->set_property('tag', 'textarea');
|
1973 |
+
$ta->set_property('cols', 40, 'attr');
|
1974 |
+
$ta->set_property('rows', 3, 'attr');
|
1975 |
+
$this->add($ta);
|
1976 |
+
|
1977 |
+
//Rich Text
|
1978 |
+
$rt = new SLB_Field_Type('richtext', 'textarea');
|
1979 |
+
$rt->set_property('class', 'theEditor {inherit}');
|
1980 |
+
$rt->set_layout('form', '<div class="rt_container">{inherit}</div>');
|
1981 |
+
$rt->add_action('admin_print_footer_scripts', 'wp_tiny_mce', 25);
|
1982 |
+
$this->add($rt);
|
1983 |
+
|
1984 |
+
//Hidden
|
1985 |
+
$hidden = new SLB_Field_Type('hidden');
|
1986 |
+
$hidden->set_parent('input');
|
1987 |
+
$hidden->set_description('Hidden Field');
|
1988 |
+
$hidden->set_property('type', 'hidden');
|
1989 |
+
$this->add($hidden);
|
1990 |
+
|
1991 |
+
//Select
|
1992 |
+
$select = new SLB_Field_Type('select', 'base_closed');
|
1993 |
+
$select->set_description('Select tag');
|
1994 |
+
$select->set_property('tag', 'select');
|
1995 |
+
$select->set_property('tag_option', 'option');
|
1996 |
+
$select->set_property('options', array());
|
1997 |
+
$select->set_layout('form', '{label ref_base="layout"} {form_start ref_base="layout"}{option_loop ref_base="layout"}{form_end ref_base="layout"}');
|
1998 |
+
$select->set_layout('option_loop', '{loop data="properties.options" layout="option" layout_data="option_data"}');
|
1999 |
+
$select->set_layout('option', '<{tag_option} value="{data_ext id="option_value"}">{data_ext id="option_text"}</{tag_option}>');
|
2000 |
+
$select->set_layout('option_data', '<{tag_option} value="{data_ext id="option_value"}" selected="selected">{data_ext id="option_text"}</{tag_option}>');
|
2001 |
+
$this->add($select);
|
2002 |
+
|
2003 |
+
//Span
|
2004 |
+
$span = new SLB_Field_Type('span', 'base_closed');
|
2005 |
+
$span->set_description('Inline wrapper');
|
2006 |
+
$span->set_property('tag', 'span');
|
2007 |
+
$span->set_property('value', 'Hello there!');
|
2008 |
+
$this->add($span);
|
2009 |
+
|
2010 |
+
//Enable plugins to modify (add, remove, etc.) field types
|
2011 |
+
do_action_ref_array($this->add_prefix('register_fields'), array(&$this));
|
2012 |
+
|
2013 |
+
//Signal completion of field registration
|
2014 |
+
do_action_ref_array($this->add_prefix('fields_registered'), array(&$this));
|
2015 |
+
}
|
2016 |
+
|
2017 |
+
/* Placeholder handlers */
|
2018 |
+
|
2019 |
+
function register_placeholders() {
|
2020 |
+
//Default placeholder handlers
|
2021 |
+
$this->register_placeholder('all', $this->m('process_placeholder_default'), 11);
|
2022 |
+
$this->register_placeholder('field_id', $this->m('process_placeholder_id'));
|
2023 |
+
$this->register_placeholder('field_name', $this->m('process_placeholder_name'));
|
2024 |
+
$this->register_placeholder('data', $this->m('process_placeholder_data'));
|
2025 |
+
$this->register_placeholder('data_ext',$this->m('process_placeholder_data_ext'));
|
2026 |
+
$this->register_placeholder('loop', $this->m('process_placeholder_loop'));
|
2027 |
+
$this->register_placeholder('label', $this->m('process_placeholder_label'));
|
2028 |
+
$this->register_placeholder('checked', $this->m('process_placeholder_checked'));
|
2029 |
+
|
2030 |
+
//Allow other code to register placeholders
|
2031 |
+
do_action_ref_array($this->add_prefix('register_field_placeholders'), array(&$this));
|
2032 |
+
|
2033 |
+
//Signal completion of field placeholder registration
|
2034 |
+
do_action_ref_array($this->add_prefix('field_placeholders_registered'), array(&$this));
|
2035 |
+
}
|
2036 |
+
|
2037 |
+
/**
|
2038 |
+
* Register a function to handle a placeholder
|
2039 |
+
* Multiple handlers may be registered for a single placeholder
|
2040 |
+
* Adds filter hook to WP for handling specified placeholder
|
2041 |
+
* Placeholders are in layouts and are replaced with data at runtime
|
2042 |
+
* @uses add_filter()
|
2043 |
+
* @param string $placeholder Name of placeholder to add handler for (Using 'all' will set the function as a handler for all placeholders
|
2044 |
+
* @param callback $callback Function to set as a handler
|
2045 |
+
* @param int $priority (optional) Priority of handler
|
2046 |
+
* @return void
|
2047 |
+
*/
|
2048 |
+
function register_placeholder($placeholder, $callback, $priority = 10) {
|
2049 |
+
if ( 'all' == $placeholder )
|
2050 |
+
$placeholder = '';
|
2051 |
+
else
|
2052 |
+
$placeholder = '_' . $placeholder;
|
2053 |
+
$hook = $this->add_prefix('process_placeholder' . $placeholder);
|
2054 |
+
add_filter($hook, $callback, $priority, 5);
|
2055 |
+
}
|
2056 |
+
|
2057 |
+
/**
|
2058 |
+
* Default placeholder processing
|
2059 |
+
* To be executed when current placeholder has not been handled by another handler
|
2060 |
+
* @param string $output Value to be used in place of placeholder
|
2061 |
+
* @param SLB_Field $item Field containing placeholder
|
2062 |
+
* @param array $placeholder Current placeholder
|
2063 |
+
* @see SLB_Field::parse_layout for structure of $placeholder array
|
2064 |
+
* @param string $layout Layout to build
|
2065 |
+
* @param array $data Extended data for item
|
2066 |
+
* @return string Value to use in place of current placeholder
|
2067 |
+
*/
|
2068 |
+
function process_placeholder_default($output, $item, $placeholder, $layout, $data) {
|
2069 |
+
//Validate parameters before processing
|
2070 |
+
if ( empty($output) && is_a($item, 'SLB_Field_Type') && is_array($placeholder) ) {
|
2071 |
+
//Build path to replacement data
|
2072 |
+
$output = $item->get_member_value($placeholder);
|
2073 |
+
|
2074 |
+
//Check if value is group (properties, etc.)
|
2075 |
+
//All groups must have additional attributes (beyond reserved attributes) that define how items in group are used
|
2076 |
+
if (is_array($output)
|
2077 |
+
&& !empty($placeholder['attributes'])
|
2078 |
+
&& is_array($placeholder['attributes'])
|
2079 |
+
&& ($ph = $item->get_placeholder_defaults())
|
2080 |
+
&& $attribs = array_diff(array_keys($placeholder['attributes']), array_values($ph->reserved))
|
2081 |
+
) {
|
2082 |
+
/* Targeted property is an array, but the placeholder contains additional options on how property is to be used */
|
2083 |
+
|
2084 |
+
//Find items matching criteria in $output
|
2085 |
+
//Check for group criteria
|
2086 |
+
if ( 'properties' == $placeholder['tag'] && ($prop_group = $item->get_group($placeholder['attributes']['group'])) && !empty($prop_group) ) {
|
2087 |
+
/* Process group */
|
2088 |
+
$group_out = array();
|
2089 |
+
//Iterate through properties in group and build string
|
2090 |
+
foreach ( array_keys($prop_group) as $prop_key ) {
|
2091 |
+
$prop_val = $item->get_property($prop_key);
|
2092 |
+
if ( !is_null($prop_val) )
|
2093 |
+
$group_out[] = $prop_key . '="' . $prop_val . '"';
|
2094 |
+
}
|
2095 |
+
$output = implode(' ', $group_out);
|
2096 |
+
}
|
2097 |
+
} elseif ( is_object($output) && is_a($output, $item->base_class) ) {
|
2098 |
+
/* Targeted property is actually a nested item */
|
2099 |
+
//Set caller to current item
|
2100 |
+
$output->set_caller($item);
|
2101 |
+
//Build layout for nested element
|
2102 |
+
$output = $output->build_layout($layout);
|
2103 |
+
}
|
2104 |
+
}
|
2105 |
+
|
2106 |
+
return $output;
|
2107 |
+
}
|
2108 |
+
|
2109 |
+
/**
|
2110 |
+
* Build Field ID attribute
|
2111 |
+
* @see SLB_Field_Type::process_placeholder_default for parameter descriptions
|
2112 |
+
* @return string Placeholder output
|
2113 |
+
*/
|
2114 |
+
function process_placeholder_id($output, $item, $placeholder, $layout, $data) {
|
2115 |
+
//Get attributes
|
2116 |
+
$args = wp_parse_args($placeholder['attributes'], array('format' => 'attr_id'));
|
2117 |
+
return $item->get_id($args);
|
2118 |
+
}
|
2119 |
+
|
2120 |
+
/**
|
2121 |
+
* Build Field name attribute
|
2122 |
+
* Name is formatted as an associative array for processing by PHP after submission
|
2123 |
+
* @see SLB_Field_Type::process_placeholder_default for parameter descriptions
|
2124 |
+
* @return string Placeholder output
|
2125 |
+
*/
|
2126 |
+
function process_placeholder_name($output, $item, $placeholder, $layout, $data) {
|
2127 |
+
//Get attributes
|
2128 |
+
$args = wp_parse_args($placeholder['attributes'], array('format' => 'attr_name'));
|
2129 |
+
return $item->get_id($args);
|
2130 |
+
}
|
2131 |
+
|
2132 |
+
/**
|
2133 |
+
* Build item label
|
2134 |
+
* @see SLB_Fields::process_placeholder_default for parameter descriptions
|
2135 |
+
* @return string Field label
|
2136 |
+
*/
|
2137 |
+
function process_placeholder_label($output, $item, $placeholder, $layout, $data) {
|
2138 |
+
//Check if item has label property (e.g. sub-elements)
|
2139 |
+
$out = $item->get_property('label');
|
2140 |
+
//If property not set, use item title
|
2141 |
+
if ( empty($out) )
|
2142 |
+
$out = $item->get_title();
|
2143 |
+
return $out;
|
2144 |
+
}
|
2145 |
+
|
2146 |
+
/**
|
2147 |
+
* Retrieve data for item
|
2148 |
+
* @see SLB_Field_Type::process_placeholder_default for parameter descriptions
|
2149 |
+
* @return string Placeholder output
|
2150 |
+
*/
|
2151 |
+
function process_placeholder_data($output, $item, $placeholder, $layout) {
|
2152 |
+
$attr_default = array (
|
2153 |
+
'context' => '',
|
2154 |
+
);
|
2155 |
+
$opts = wp_parse_args($placeholder['attributes'], $attr_default);
|
2156 |
+
//Save context to separate variable
|
2157 |
+
$context = $opts['context'];
|
2158 |
+
unset($opts['context']);
|
2159 |
+
//Get data
|
2160 |
+
$out = $item->get_data($opts);
|
2161 |
+
if ( !is_null($out) ) {
|
2162 |
+
//Get specific member in value (e.g. value from a specific item element)
|
2163 |
+
if ( isset($opts['element']) && is_array($out) && ( $el = $opts['element'] ) && isset($out[$el]) )
|
2164 |
+
$out = $out[$el];
|
2165 |
+
}
|
2166 |
+
|
2167 |
+
//Format data based on context
|
2168 |
+
$out = $item->format($out, $context);
|
2169 |
+
//Return data
|
2170 |
+
return $out;
|
2171 |
+
}
|
2172 |
+
|
2173 |
+
/**
|
2174 |
+
* Set checked attribute on item
|
2175 |
+
* Evaluates item's data to see if item should be checked or not
|
2176 |
+
* @see SLB_Fields::process_placeholder_default for parameter descriptions
|
2177 |
+
* @return string Appropriate checkbox attribute
|
2178 |
+
*/
|
2179 |
+
function process_placeholder_checked($output, $item, $placeholder, $layout, $data) {
|
2180 |
+
$out = '';
|
2181 |
+
$c = $item->get_container();
|
2182 |
+
$d = ( isset($c->data[$item->get_id()]) ) ? $c->data[$item->get_id()] : null;
|
2183 |
+
$item->set_property('d', true);
|
2184 |
+
if ( $item->get_data() )
|
2185 |
+
$out = 'checked="checked"';
|
2186 |
+
$item->set_property('d', false);
|
2187 |
+
return $out;
|
2188 |
+
}
|
2189 |
+
|
2190 |
+
/**
|
2191 |
+
* Loops over data to build item output
|
2192 |
+
* Options:
|
2193 |
+
* data - Dot-delimited path in item that contains data to loop through
|
2194 |
+
* layout - Name of layout to use for each data item in loop
|
2195 |
+
* layout_data - Name of layout to use for data item that matches previously-saved item data
|
2196 |
+
* @see SLB_Field_Type::process_placeholder_default for parameter descriptions
|
2197 |
+
* @return string Placeholder output
|
2198 |
+
*/
|
2199 |
+
function process_placeholder_loop($output, $item, $placeholder, $layout, $data) {
|
2200 |
+
//Setup loop options
|
2201 |
+
$attr_defaults = array (
|
2202 |
+
'layout' => '',
|
2203 |
+
'layout_data' => null,
|
2204 |
+
'data' => ''
|
2205 |
+
);
|
2206 |
+
$attr = wp_parse_args($placeholder['attributes'], $attr_defaults);
|
2207 |
+
if ( is_null($attr['layout_data']) )
|
2208 |
+
$attr['layout_data'] =& $attr['layout'];
|
2209 |
+
//Get data for loop
|
2210 |
+
$path = explode('.', $attr['data']);
|
2211 |
+
$loop_data = $item->get_member_value($path);
|
2212 |
+
|
2213 |
+
//Check if data is callback
|
2214 |
+
if ( is_callable($loop_data) )
|
2215 |
+
$loop_data = call_user_func($loop_data);
|
2216 |
+
|
2217 |
+
//Get item data
|
2218 |
+
$data = $item->get_data();
|
2219 |
+
|
2220 |
+
//Iterate over data and build output
|
2221 |
+
$out = array();
|
2222 |
+
if ( is_array($loop_data) && !empty($loop_data) ) {
|
2223 |
+
foreach ( $loop_data as $value => $label ) {
|
2224 |
+
//Load appropriate layout based on item value
|
2225 |
+
$layout = ( ($data === 0 && $value === $data) xor $data == $value ) ? $attr['layout_data'] : $attr['layout'];
|
2226 |
+
//Stop processing if no valid layout is returned
|
2227 |
+
if ( empty($layout) )
|
2228 |
+
continue;
|
2229 |
+
//Prep extended item data
|
2230 |
+
$data_ext = array('option_value' => $value, 'option_text' => $label);
|
2231 |
+
$out[] = $item->build_layout($layout, $data_ext);
|
2232 |
+
}
|
2233 |
+
}
|
2234 |
+
|
2235 |
+
//Return output
|
2236 |
+
return implode($out);
|
2237 |
+
}
|
2238 |
+
|
2239 |
+
/**
|
2240 |
+
* Returns specified value from extended data array for item
|
2241 |
+
* @see SLB_Field_Type::process_placeholder_default for parameter descriptions
|
2242 |
+
* @return string Placeholder output
|
2243 |
+
*/
|
2244 |
+
function process_placeholder_data_ext($output, $item, $placeholder, $layout, $data) {
|
2245 |
+
if ( isset($placeholder['attributes']['id']) && ($key = $placeholder['attributes']['id']) && isset($data[$key]) ) {
|
2246 |
+
$output = strval($data[$key]);
|
2247 |
+
}
|
2248 |
+
|
2249 |
+
return $output;
|
2250 |
+
}
|
2251 |
+
}
|
includes/class.options.php
ADDED
@@ -0,0 +1,517 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
require_once 'class.fields.php';
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Option object
|
6 |
+
* @package Simple Lightbox
|
7 |
+
* @subpackage Options
|
8 |
+
* @author SM
|
9 |
+
*/
|
10 |
+
class SLB_Option extends SLB_Field {
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Child mapping
|
14 |
+
* @see SLB_Field_Base::map
|
15 |
+
* @var array
|
16 |
+
*/
|
17 |
+
var $map = array(
|
18 |
+
'default' => 'data',
|
19 |
+
'attr' => 'properties'
|
20 |
+
);
|
21 |
+
|
22 |
+
/* Init */
|
23 |
+
|
24 |
+
function SLB_Option($id, $title = '', $default = '') {
|
25 |
+
$args = func_get_args();
|
26 |
+
call_user_func_array(array(&$this, '__construct'), $args);
|
27 |
+
}
|
28 |
+
|
29 |
+
/**
|
30 |
+
* @see SLB_Field::__construct()
|
31 |
+
* @uses parent::__construct() to initialize instance
|
32 |
+
* @param $id
|
33 |
+
* @param $title
|
34 |
+
* @param $default
|
35 |
+
*/
|
36 |
+
function __construct($id, $title = '', $default = '') {
|
37 |
+
//Normalize properties
|
38 |
+
$args = func_get_args();
|
39 |
+
$props = SLB_Utilities::func_get_options($args);
|
40 |
+
$props = wp_parse_args($props, array ('id' => $id, 'title' => $title, 'default' => $default));
|
41 |
+
//Send to parent constructor
|
42 |
+
parent::__construct($props);
|
43 |
+
}
|
44 |
+
|
45 |
+
/* Getters/Setters */
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Retrieve default value for option
|
49 |
+
* @return mixed Default option value
|
50 |
+
*/
|
51 |
+
function get_default($context = '') {
|
52 |
+
return $this->get_data($context, false);
|
53 |
+
}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Sets parent based on default value
|
57 |
+
*/
|
58 |
+
function set_parent($parent = null) {
|
59 |
+
$p =& $this->get_parent();
|
60 |
+
if ( empty($parent) && empty($p) ) {
|
61 |
+
$parent = 'text';
|
62 |
+
$d = $this->get_default();
|
63 |
+
if ( is_bool($d) )
|
64 |
+
$parent = 'checkbox';
|
65 |
+
$parent = 'option_' . $parent;
|
66 |
+
} elseif ( !empty($p) && !is_object($p) ) {
|
67 |
+
$parent =& $p;
|
68 |
+
}
|
69 |
+
parent::set_parent($parent);
|
70 |
+
}
|
71 |
+
|
72 |
+
/* Formatting */
|
73 |
+
|
74 |
+
/**
|
75 |
+
* Format data as string for browser output
|
76 |
+
* @see SLB_Field_Base::format()
|
77 |
+
* @param mixed $value Data to format
|
78 |
+
* @param string $context (optional) Current context
|
79 |
+
* @return string Formatted value
|
80 |
+
*/
|
81 |
+
function format_display($value, $context = '') {
|
82 |
+
if ( !is_string($value) ) {
|
83 |
+
if ( is_bool($value) )
|
84 |
+
$value = ( $value ) ? 'Enabled' : 'Disabled';
|
85 |
+
elseif ( is_null($value) )
|
86 |
+
$value = '';
|
87 |
+
else
|
88 |
+
$value = strval($value);
|
89 |
+
}
|
90 |
+
return htmlentities($value);
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Format data as boolean (true/false)
|
95 |
+
* @see SLB_Field_Base::format()
|
96 |
+
* @param mixed $value Data to format
|
97 |
+
* @param string $context (optional) Current context
|
98 |
+
* @return bool Option value
|
99 |
+
*/
|
100 |
+
function format_bool($value, $context = '') {
|
101 |
+
if ( !is_bool($value) )
|
102 |
+
$value = !!$value;
|
103 |
+
return $value;
|
104 |
+
}
|
105 |
+
|
106 |
+
/**
|
107 |
+
* Format data as string
|
108 |
+
* @see SLB_Field_Base::format()
|
109 |
+
* @param mixed $value Data to format
|
110 |
+
* @param string $context (optional) Current context
|
111 |
+
* @return string Option string value
|
112 |
+
*/
|
113 |
+
function format_string($value, $context = '') {
|
114 |
+
if ( is_bool($value) ) {
|
115 |
+
$value = ( $value ) ? 'true' : 'false';
|
116 |
+
}
|
117 |
+
elseif ( is_object($value) ) {
|
118 |
+
$value = get_class($value);
|
119 |
+
}
|
120 |
+
elseif ( is_array($value) ) {
|
121 |
+
$value = implode(' ', $value);
|
122 |
+
}
|
123 |
+
else {
|
124 |
+
$value = strval($value);
|
125 |
+
}
|
126 |
+
}
|
127 |
+
}
|
128 |
+
|
129 |
+
/**
|
130 |
+
* Options collection
|
131 |
+
* @package Simple Lightbox
|
132 |
+
* @subpackage Options
|
133 |
+
* @author SM
|
134 |
+
* @uses SLB_Field_Collection
|
135 |
+
*/
|
136 |
+
class SLB_Options extends SLB_Field_Collection {
|
137 |
+
|
138 |
+
/* Properties */
|
139 |
+
|
140 |
+
var $item_type = 'SLB_Option';
|
141 |
+
|
142 |
+
/**
|
143 |
+
* Key for saving version to DB
|
144 |
+
* @var string
|
145 |
+
*/
|
146 |
+
var $version_key = 'version';
|
147 |
+
|
148 |
+
|
149 |
+
/**
|
150 |
+
* Whether verison has been checked
|
151 |
+
* @var bool
|
152 |
+
*/
|
153 |
+
var $version_checked = false;
|
154 |
+
|
155 |
+
/* Init */
|
156 |
+
|
157 |
+
function SLB_Options($id = '', $props = array()) {
|
158 |
+
$args = func_get_args();
|
159 |
+
call_user_func_array(array(&$this, '__construct'), $args);
|
160 |
+
}
|
161 |
+
|
162 |
+
function __construct($id = '', $props = array()) {
|
163 |
+
$args = func_get_args();
|
164 |
+
//Validate arguments
|
165 |
+
if ( count($args) == 1 && is_array($args[0]) ) {
|
166 |
+
$props = $id;
|
167 |
+
$id = '';
|
168 |
+
}
|
169 |
+
//Set default ID
|
170 |
+
if ( !is_string($id) || empty($id) ) {
|
171 |
+
$id = 'options';
|
172 |
+
}
|
173 |
+
parent::__construct($id, $props);
|
174 |
+
$this->add_prefix_ref($this->version_key);
|
175 |
+
}
|
176 |
+
|
177 |
+
function register_hooks() {
|
178 |
+
parent::register_hooks();
|
179 |
+
//Register fields
|
180 |
+
add_action($this->add_prefix('register_fields'), $this->m('register_fields'));
|
181 |
+
//Set option parents
|
182 |
+
add_action($this->add_prefix('fields_registered'), $this->m('set_parents'));
|
183 |
+
}
|
184 |
+
|
185 |
+
/* Legacy/Migration */
|
186 |
+
|
187 |
+
/**
|
188 |
+
* Checks whether new version has been installed and migrates necessary settings
|
189 |
+
* @uses $version_key as option name
|
190 |
+
* @uses get_option() to retrieve saved version number
|
191 |
+
* @uses SLB_Utilities::get_plugin_version() to retrieve current version
|
192 |
+
* @return bool TRUE if version has been changed
|
193 |
+
*/
|
194 |
+
function check_update() {
|
195 |
+
if ( !$this->version_checked ) {
|
196 |
+
$this->version_checked = true;
|
197 |
+
//Get version from DB
|
198 |
+
$vo = get_option($this->version_key);
|
199 |
+
//Get current version
|
200 |
+
$vn = $this->util->get_plugin_version();
|
201 |
+
//Compare versions
|
202 |
+
if ( $vo != $vn ) {
|
203 |
+
//Update saved version
|
204 |
+
$this->set_version($vn);
|
205 |
+
//Migrate old version to new version
|
206 |
+
if ( strcasecmp($vo, $vn) < 0 ) {
|
207 |
+
//Migrate
|
208 |
+
$this->migrate();
|
209 |
+
}
|
210 |
+
}
|
211 |
+
}
|
212 |
+
return $this->version_checked;
|
213 |
+
}
|
214 |
+
|
215 |
+
/**
|
216 |
+
* Save plugin version to DB
|
217 |
+
* If no version supplied, will fetch plugin data to determine version
|
218 |
+
* @uses $version_key as option name
|
219 |
+
* @uses update_option() to save version to options table
|
220 |
+
* @param string $ver (optional) Plugin version
|
221 |
+
*/
|
222 |
+
function set_version($ver = null) {
|
223 |
+
if ( empty($ver) ) {
|
224 |
+
$ver = $this->util->get_plugin_version();
|
225 |
+
}
|
226 |
+
return update_option($this->version_key, $ver);
|
227 |
+
}
|
228 |
+
|
229 |
+
/**
|
230 |
+
* Migrate options from old versions to current version
|
231 |
+
*/
|
232 |
+
function migrate() {
|
233 |
+
//Legacy options
|
234 |
+
$d = null;
|
235 |
+
$this->load_data();
|
236 |
+
|
237 |
+
//Migrate separate options to unified option
|
238 |
+
$items =& $this->get_items();
|
239 |
+
foreach ( $items as $id => $opt ) {
|
240 |
+
$oid = $this->add_prefix($id);
|
241 |
+
$o = get_option($oid, $d);
|
242 |
+
if ( $o !== $d ) {
|
243 |
+
//Migrate value to data array
|
244 |
+
$this->set_data($id, $o, false);
|
245 |
+
//Delete legacy option
|
246 |
+
delete_option($oid);
|
247 |
+
}
|
248 |
+
}
|
249 |
+
|
250 |
+
//Migrate legacy items
|
251 |
+
if ( is_array($this->properties_init) && isset($this->properties_init['legacy']) && is_array($this->properties_init['legacy']) ) {
|
252 |
+
foreach( $this->properties_init['legacy'] as $opt => $dest ) {
|
253 |
+
$oid = $this->add_prefix($opt);
|
254 |
+
$o = get_option($oid, $d);
|
255 |
+
//Only migrate valid values
|
256 |
+
if ( $o !== $d ) {
|
257 |
+
//Wrap single destination in array
|
258 |
+
if ( is_string($dest) ) {
|
259 |
+
$dest = array($dest);
|
260 |
+
}
|
261 |
+
//Process destinations
|
262 |
+
if ( is_array($dest) ) {
|
263 |
+
foreach ( $dest as $id ) {
|
264 |
+
$this->set_data($id, $o, false);
|
265 |
+
}
|
266 |
+
}
|
267 |
+
}
|
268 |
+
//Remove legacy item
|
269 |
+
delete_option($this->add_prefix($opt));
|
270 |
+
}
|
271 |
+
}
|
272 |
+
//Save changes
|
273 |
+
$this->save();
|
274 |
+
}
|
275 |
+
|
276 |
+
/* Option setup */
|
277 |
+
|
278 |
+
/**
|
279 |
+
* Register option-specific fields
|
280 |
+
* @param SLB_Fields $fields Reference to global fields object
|
281 |
+
* @return void
|
282 |
+
*/
|
283 |
+
function register_fields(&$fields) {
|
284 |
+
//Layouts
|
285 |
+
$layout_label = '<label for="{field_id}" class="title block">{label}</label>';
|
286 |
+
$label_ref = '{label ref_base="layout"}';
|
287 |
+
$field_pre = '<div class="input block">';
|
288 |
+
$field_post = '</div>';
|
289 |
+
$opt_pre = '<div class="' . $this->add_prefix('option_item') . '">';
|
290 |
+
$opt_post = '</div>';
|
291 |
+
$layout_form = '<{form_attr ref_base="layout"} /> <span class="description">(Default: {data context="display" top="0"})</span>';
|
292 |
+
|
293 |
+
//Text input
|
294 |
+
$otxt = new SLB_Field_Type('option_text', 'text');
|
295 |
+
$otxt->set_property('class', '{inherit} code');
|
296 |
+
$otxt->set_property('size', null);
|
297 |
+
$otxt->set_property('value', '{data context="form"}');
|
298 |
+
$otxt->set_layout('label', $layout_label);
|
299 |
+
$otxt->set_layout('form', $opt_pre . $label_ref . $field_pre . $layout_form . $field_post . $opt_post);
|
300 |
+
$fields->add($otxt);
|
301 |
+
|
302 |
+
//Checkbox
|
303 |
+
$ocb = new SLB_Field_Type('option_checkbox', 'checkbox');
|
304 |
+
$ocb->set_layout('label', $layout_label);
|
305 |
+
$ocb->set_layout('form', $opt_pre . $label_ref . $field_pre . $layout_form . $field_post . $opt_post);
|
306 |
+
$fields->add($ocb);
|
307 |
+
|
308 |
+
//Theme
|
309 |
+
$othm = new SLB_Field_Type('option_theme', 'select');
|
310 |
+
$othm->set_layout('label', $layout_label);
|
311 |
+
$othm->set_layout('form_start', $field_pre . '{inherit}');
|
312 |
+
$othm->set_layout('form_end', '{inherit}' . $field_post);
|
313 |
+
$othm->set_layout('form', $opt_pre . '{inherit}' . $opt_post);
|
314 |
+
$fields->add($othm);
|
315 |
+
}
|
316 |
+
|
317 |
+
/**
|
318 |
+
* Set parent field types for options
|
319 |
+
* Parent only set for Admin pages
|
320 |
+
* @uses SLB_Option::set_parent() to set parent field for each option item
|
321 |
+
* @uses is_admin() to determine if current request is admin page
|
322 |
+
* @param object $fields Collection of default field types
|
323 |
+
* @return void
|
324 |
+
*/
|
325 |
+
function set_parents(&$fields) {
|
326 |
+
if ( !is_admin() )
|
327 |
+
return false;
|
328 |
+
$items =& $this->get_items();
|
329 |
+
foreach ( array_keys($items) as $opt ) {
|
330 |
+
$items[$opt]->set_parent();
|
331 |
+
}
|
332 |
+
foreach ( $this->items as $opt ) {
|
333 |
+
$p = $opt->parent;
|
334 |
+
if ( is_object($p) )
|
335 |
+
$p = 'o:' . $p->id;
|
336 |
+
}
|
337 |
+
}
|
338 |
+
|
339 |
+
/* Processing */
|
340 |
+
|
341 |
+
function validate($values) {
|
342 |
+
if ( is_array($values) ) {
|
343 |
+
//Format data based on option type (bool, string, etc.)
|
344 |
+
foreach ( $values as $id => $val ) {
|
345 |
+
//Get default
|
346 |
+
$d = $this->get_default($id);
|
347 |
+
if ( is_bool($d) && !empty($val) )
|
348 |
+
$values[$id] = true;
|
349 |
+
}
|
350 |
+
//Merge in additional options that are not in post data
|
351 |
+
//Missing options (e.g. disabled checkboxes) & defaults
|
352 |
+
$items =& $this->get_items();
|
353 |
+
foreach ( $items as $id => $opt ) {
|
354 |
+
//Add options that were not included in form submission
|
355 |
+
if ( !array_key_exists($id, $values) ) {
|
356 |
+
if ( is_bool($opt->get_default()) )
|
357 |
+
$values[$id] = false;
|
358 |
+
else
|
359 |
+
$values[$id] = $opt->get_default();
|
360 |
+
}
|
361 |
+
}
|
362 |
+
}
|
363 |
+
|
364 |
+
//Return value
|
365 |
+
return $values;
|
366 |
+
}
|
367 |
+
|
368 |
+
/* Data */
|
369 |
+
|
370 |
+
/**
|
371 |
+
* Retrieve options from database
|
372 |
+
* @uses get_option to retrieve option data
|
373 |
+
* @return array Options data
|
374 |
+
*/
|
375 |
+
function fetch_data($sanitize = true) {
|
376 |
+
//Check update
|
377 |
+
$this->check_update();
|
378 |
+
//Get data
|
379 |
+
$data = get_option($this->get_key(), null);
|
380 |
+
if ( $sanitize && is_array($data) ) {
|
381 |
+
//Sanitize loaded data based on default values
|
382 |
+
foreach ( $data as $id => $val ) {
|
383 |
+
if ( $this->has($id) ) {
|
384 |
+
$opt = $this->get($id);
|
385 |
+
if ( is_bool($opt->get_default()) )
|
386 |
+
$data[$id] = !!$val;
|
387 |
+
} else {
|
388 |
+
unset($data[$id]);
|
389 |
+
}
|
390 |
+
}
|
391 |
+
}
|
392 |
+
return $data;
|
393 |
+
}
|
394 |
+
|
395 |
+
/**
|
396 |
+
* Retrieves option data for collection
|
397 |
+
* @see SLB_Field_Collection::load_data()
|
398 |
+
*/
|
399 |
+
function load_data() {
|
400 |
+
if ( !$this->data_fetched ) {
|
401 |
+
//Retrieve data
|
402 |
+
$this->data = $this->fetch_data();
|
403 |
+
$this->data_fetched = true;
|
404 |
+
}
|
405 |
+
}
|
406 |
+
|
407 |
+
/**
|
408 |
+
* Resets option values to their default values
|
409 |
+
* @param bool $hard Reset all options if TRUE (default), Reset only unset options if FALSE
|
410 |
+
*/
|
411 |
+
function reset($hard = true) {
|
412 |
+
$this->load_data();
|
413 |
+
//Reset data
|
414 |
+
if ( $hard ) {
|
415 |
+
$this->data = null;
|
416 |
+
}
|
417 |
+
//Save
|
418 |
+
$this->save();
|
419 |
+
}
|
420 |
+
|
421 |
+
/**
|
422 |
+
* Save options data to database
|
423 |
+
*/
|
424 |
+
function save() {
|
425 |
+
$opts =& $this->get_items();
|
426 |
+
$data = array();
|
427 |
+
foreach ( $opts as $id => $opt ) {
|
428 |
+
$data[$id] = $opt->get_data();
|
429 |
+
}
|
430 |
+
$this->data = $data;
|
431 |
+
update_option($this->get_key(), $data);
|
432 |
+
}
|
433 |
+
|
434 |
+
/* Collection */
|
435 |
+
|
436 |
+
/**
|
437 |
+
* Build key for saving/retrieving data to options table
|
438 |
+
* @return string Key
|
439 |
+
*/
|
440 |
+
function get_key() {
|
441 |
+
return $this->add_prefix($this->get_id());
|
442 |
+
}
|
443 |
+
|
444 |
+
/**
|
445 |
+
* Add option to collection
|
446 |
+
* @uses SLB_Field_Collection::add() to add item
|
447 |
+
* @param string $id Unique item ID
|
448 |
+
* @param string $title Item title
|
449 |
+
* @param mixed $default Default value
|
450 |
+
* @param string $group (optional) Group ID to add item to
|
451 |
+
* @return SLB_Option Option instance reference
|
452 |
+
*/
|
453 |
+
function &add($id, $title = '', $default = '', $group = null) {
|
454 |
+
//Build properties array
|
455 |
+
$properties = $this->make_properties($title, array('title' => $title, 'group' => $group, 'default' => $default));
|
456 |
+
|
457 |
+
//Create item
|
458 |
+
/**
|
459 |
+
* @var SLB_Option
|
460 |
+
*/
|
461 |
+
$item =& parent::add($id, $properties);
|
462 |
+
|
463 |
+
return $item;
|
464 |
+
}
|
465 |
+
|
466 |
+
/**
|
467 |
+
* Retrieve option value
|
468 |
+
* @uses get_data() to retrieve option data
|
469 |
+
* @param string $option Option ID to retrieve value for
|
470 |
+
* @param string $context (optional) Context for formatting data
|
471 |
+
* @return mixed Option value
|
472 |
+
*/
|
473 |
+
function get_value($option, $context = '') {
|
474 |
+
return $this->get_data($option, $context);
|
475 |
+
}
|
476 |
+
|
477 |
+
/**
|
478 |
+
* Retrieve option value as boolean (true/false)
|
479 |
+
* @uses get_data() to retrieve option data
|
480 |
+
* @param string $option Option ID to retrieve value for
|
481 |
+
* @return bool Option value
|
482 |
+
*/
|
483 |
+
function get_bool($option) {
|
484 |
+
return $this->get_value($option, 'bool');
|
485 |
+
}
|
486 |
+
|
487 |
+
function get_string($option) {
|
488 |
+
return $this->get_value($option, 'string');
|
489 |
+
}
|
490 |
+
|
491 |
+
/**
|
492 |
+
* Retrieve option's default value
|
493 |
+
* @uses get_data() to retrieve option data
|
494 |
+
* @param string $option Option ID to retrieve value for
|
495 |
+
* @param string $context (optional) Context for formatting data
|
496 |
+
* @return mixed Option's default value
|
497 |
+
*/
|
498 |
+
function get_default($option, $context = '') {
|
499 |
+
return $this->get_data($option, $context, false);
|
500 |
+
}
|
501 |
+
|
502 |
+
/* Output */
|
503 |
+
|
504 |
+
function build_group($group) {
|
505 |
+
if ( !$this->group_exists($group) )
|
506 |
+
return false;
|
507 |
+
$group =& $this->get_group($group);
|
508 |
+
//Stop processing if group contains no items
|
509 |
+
if ( !count($this->get_items($group)) )
|
510 |
+
return false;
|
511 |
+
|
512 |
+
//Group header
|
513 |
+
echo '<h4 class="subhead">' . $group->title . '</h4>';
|
514 |
+
//Build items
|
515 |
+
echo $this->build_items($group);
|
516 |
+
}
|
517 |
+
}
|
includes/class.utilities.php
CHANGED
@@ -10,12 +10,35 @@
|
|
10 |
*/
|
11 |
class SLB_Utilities {
|
12 |
|
13 |
-
|
14 |
-
$this->__construct();
|
15 |
-
}
|
16 |
|
17 |
-
|
18 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
}
|
20 |
|
21 |
/**
|
@@ -33,6 +56,423 @@ class SLB_Utilities {
|
|
33 |
|
34 |
/* Helper Functions */
|
35 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
/*-** WP **-*/
|
37 |
|
38 |
/**
|
@@ -59,14 +499,220 @@ class SLB_Utilities {
|
|
59 |
return true;
|
60 |
}
|
61 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
62 |
/*-** Request **-*/
|
63 |
|
64 |
/**
|
65 |
-
* Checks
|
66 |
* @param string $filename Filename to check for
|
67 |
* @return bool TRUE if current page matches specified filename, FALSE otherwise
|
68 |
*/
|
69 |
-
function
|
70 |
return ( $filename == basename( $_SERVER['SCRIPT_NAME'] ) );
|
71 |
}
|
72 |
|
@@ -76,112 +722,267 @@ class SLB_Utilities {
|
|
76 |
*/
|
77 |
function is_admin_management_page() {
|
78 |
return ( is_admin()
|
79 |
-
&& ( $this->
|
80 |
-
|| ( $this->
|
81 |
&& isset($_GET['page'])
|
82 |
&& strpos($_GET['page'], 'cnr') === 0 )
|
83 |
)
|
84 |
);
|
85 |
}
|
86 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
87 |
/**
|
88 |
* Joins and normalizes the slashes in the paths passed to method
|
89 |
* All forward/back slashes are converted to forward slashes
|
90 |
* Multiple path segments can be passed as additional argments
|
91 |
* @param string $path Path to normalize
|
92 |
-
* @param bool $trailing_slash (optional) Whether or not normalized path should have a trailing slash or not (Default: FALSE)
|
93 |
-
* If
|
|
|
94 |
*/
|
95 |
function normalize_path($path, $trailing_slash = false) {
|
96 |
$sl_f = '/';
|
97 |
$sl_b = '\\';
|
98 |
$parts = func_get_args();
|
|
|
|
|
99 |
if ( func_num_args() > 1 ) {
|
100 |
-
|
101 |
-
|
102 |
-
|
|
|
|
|
|
|
|
|
|
|
103 |
array_pop($parts);
|
104 |
-
|
105 |
-
$
|
|
|
|
|
|
|
106 |
}
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
$first = !$first;
|
121 |
-
else
|
122 |
-
continue;
|
123 |
-
//Add back leading slash if necessary
|
124 |
-
if ( $part[0] == $sl_f || $part[0] == $sl_b )
|
125 |
-
$parts[$key] = $sl_f . $parts[$key];
|
126 |
-
|
127 |
}
|
128 |
}
|
|
|
129 |
//Join path parts together
|
130 |
$parts = implode($sl_b, $parts);
|
131 |
$parts = str_replace($sl_b, $sl_f, $parts);
|
132 |
//Add trailing slash (if necessary)
|
133 |
if ( $trailing_slash )
|
134 |
-
$parts
|
|
|
|
|
|
|
|
|
|
|
135 |
return $parts;
|
136 |
}
|
137 |
|
138 |
/**
|
139 |
* Returns URL of file (assumes that it is in plugin directory)
|
140 |
* @param string $file name of file get URL
|
141 |
-
* @return string File
|
142 |
*/
|
143 |
function get_file_url($file) {
|
144 |
-
if (is_string($file) && '' != trim($file)) {
|
145 |
-
$file = $this->normalize_path($this->get_url_base(), $file);
|
146 |
}
|
147 |
return $file;
|
148 |
}
|
149 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
150 |
/**
|
151 |
* Retrieves file extension
|
152 |
* @param string $file file name/path
|
|
|
153 |
* @return string File's extension
|
154 |
*/
|
155 |
-
function get_file_extension($file) {
|
156 |
$ret = '';
|
157 |
$sep = '.';
|
158 |
-
if ( is_string($
|
|
|
|
|
159 |
$ret = substr($file, $rpos + 1);
|
|
|
|
|
160 |
return $ret;
|
161 |
}
|
162 |
|
163 |
/**
|
164 |
* Checks if file has specified extension
|
|
|
165 |
* @param string $file File name/path
|
166 |
-
* @param string $extension File ending to check $file for
|
|
|
167 |
* @return bool TRUE if file has extension
|
168 |
*/
|
169 |
-
function has_file_extension($file, $extension) {
|
170 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
171 |
}
|
172 |
|
173 |
/**
|
174 |
* Retrieve base URL for plugin-specific files
|
|
|
|
|
175 |
* @return string Base URL
|
176 |
*/
|
177 |
function get_url_base() {
|
178 |
static $url_base = '';
|
179 |
if ( '' == $url_base ) {
|
180 |
-
$url_base = $this->normalize_path(
|
181 |
}
|
182 |
return $url_base;
|
183 |
}
|
184 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
185 |
function get_path_base() {
|
186 |
static $path_base = '';
|
187 |
if ( '' == $path_base ) {
|
@@ -189,23 +990,125 @@ class SLB_Utilities {
|
|
189 |
}
|
190 |
return $path_base;
|
191 |
}
|
192 |
-
|
193 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
194 |
static $plugin_dir = '';
|
195 |
if ( '' == $plugin_dir ) {
|
196 |
$plugin_dir = str_replace($this->normalize_path(WP_PLUGIN_DIR), '', $this->normalize_path(dirname(dirname(__FILE__))));
|
197 |
}
|
|
|
|
|
198 |
return $plugin_dir;
|
199 |
}
|
200 |
|
|
|
|
|
|
|
|
|
|
|
|
|
201 |
function get_plugin_base_file() {
|
202 |
-
$file = '
|
203 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
204 |
}
|
205 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
206 |
function get_plugin_base_name() {
|
207 |
-
$
|
208 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
209 |
}
|
210 |
|
211 |
/**
|
@@ -246,6 +1149,22 @@ class SLB_Utilities {
|
|
246 |
|
247 |
/*-** General **-*/
|
248 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
249 |
/**
|
250 |
* Checks if a property exists in a class or object
|
251 |
* (Compatibility method for PHP 4
|
@@ -284,6 +1203,60 @@ class SLB_Utilities {
|
|
284 |
}
|
285 |
}
|
286 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
287 |
/**
|
288 |
* Merges 1 or more arrays together
|
289 |
* Methodology
|
@@ -295,7 +1268,6 @@ class SLB_Utilities {
|
|
295 |
* - Merge item in base array with current item based on key name
|
296 |
* - If the current item's value AND the corresponding item in the base array are BOTH arrays, recursively merge the the arrays
|
297 |
* - If the current item's value OR the corresponding item in the base array is NOT an array, current item overwrites base item
|
298 |
-
* @todo Append numerical elements (as opposed to overwriting element at same index in base array)
|
299 |
* @param array Variable number of arrays
|
300 |
* @param array $arr1 Default array
|
301 |
* @return array Merged array
|
@@ -303,24 +1275,33 @@ class SLB_Utilities {
|
|
303 |
function array_merge_recursive_distinct($arr1) {
|
304 |
//Get all arrays passed to function
|
305 |
$args = func_get_args();
|
306 |
-
if (empty($args))
|
307 |
return false;
|
|
|
|
|
|
|
308 |
//Set first array as base array
|
309 |
$merged = $args[0];
|
310 |
//Iterate through arrays to merge
|
311 |
$arg_length = count($args);
|
312 |
-
for ($x = 1; $x < $arg_length; $x++) {
|
313 |
//Skip if argument is not an array (only merge arrays)
|
314 |
-
if (!is_array($args[$x]))
|
315 |
continue;
|
316 |
//Iterate through argument items
|
317 |
-
foreach ($args[$x] as $key => $val) {
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
324 |
}
|
325 |
}
|
326 |
return $merged;
|
@@ -375,6 +1356,13 @@ class SLB_Utilities {
|
|
375 |
return $item;
|
376 |
}
|
377 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
378 |
function get_array_path($attribute = '', $format = null) {
|
379 |
//Formatted value
|
380 |
$fmtd = '';
|
@@ -440,6 +1428,34 @@ class SLB_Utilities {
|
|
440 |
return $path;
|
441 |
}
|
442 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
443 |
/**
|
444 |
* Builds attribute string for HTML element
|
445 |
* @param array $attr Attributes
|
@@ -460,6 +1476,11 @@ class SLB_Utilities {
|
|
460 |
return $ret;
|
461 |
}
|
462 |
|
|
|
|
|
|
|
|
|
|
|
463 |
/**
|
464 |
* Generate external stylesheet element
|
465 |
* @param $url Stylesheet URL
|
@@ -470,6 +1491,33 @@ class SLB_Utilities {
|
|
470 |
return $this->build_html_element(array('tag' => 'link', 'wrap' => false, 'attributes' => $attributes));
|
471 |
}
|
472 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
473 |
/**
|
474 |
* Generate external script element
|
475 |
* @param $url Script URL
|
@@ -542,23 +1590,24 @@ class SLB_Utilities {
|
|
542 |
//Get last submenu added
|
543 |
$parent = $this->get_submenu_parent_file($parent);
|
544 |
if ( isset($submenu[$parent]) ) {
|
545 |
-
|
546 |
-
|
547 |
-
|
548 |
-
|
549 |
-
|
550 |
-
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
}
|
560 |
}
|
561 |
}
|
|
|
562 |
|
563 |
return $hookname;
|
564 |
}
|
10 |
*/
|
11 |
class SLB_Utilities {
|
12 |
|
13 |
+
/* Properties */
|
|
|
|
|
14 |
|
15 |
+
/**
|
16 |
+
* Instance parent
|
17 |
+
* @var object
|
18 |
+
*/
|
19 |
+
var $parent = null;
|
20 |
+
|
21 |
+
/**
|
22 |
+
* Default plugin headers
|
23 |
+
* @var array
|
24 |
+
*/
|
25 |
+
var $plugin_headers = array (
|
26 |
+
'Name' => 'Plugin Name',
|
27 |
+
'PluginURI' => 'Plugin URI',
|
28 |
+
'Version' => 'Version',
|
29 |
+
'Description' => 'Description',
|
30 |
+
'Author' => 'Author',
|
31 |
+
'AuthorURI' => 'Author URI',
|
32 |
+
'TextDomain' => 'Text Domain',
|
33 |
+
'DomainPath' => 'Domain Path',
|
34 |
+
'Network' => 'Network',
|
35 |
+
);
|
36 |
+
|
37 |
+
/* Constructors */
|
38 |
+
|
39 |
+
function __construct(&$obj) {
|
40 |
+
if ( is_object($obj) )
|
41 |
+
$this->parent =& $obj;
|
42 |
}
|
43 |
|
44 |
/**
|
56 |
|
57 |
/* Helper Functions */
|
58 |
|
59 |
+
/*-** Prefix **-*/
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Get valid separator
|
63 |
+
* @param string $sep (optional) Separator supplied
|
64 |
+
* @return string Separator
|
65 |
+
*/
|
66 |
+
function get_sep($sep = false) {
|
67 |
+
if ( is_null($sep) )
|
68 |
+
$sep = '';
|
69 |
+
return ( is_string($sep) ) ? $sep : '_';
|
70 |
+
}
|
71 |
+
|
72 |
+
/**
|
73 |
+
* Retrieve class prefix (with separator if set)
|
74 |
+
* @param bool|string $sep Separator to append to class prefix (Default: no separator)
|
75 |
+
* @return string Class prefix
|
76 |
+
*/
|
77 |
+
function get_prefix($sep = null) {
|
78 |
+
$sep = $this->get_sep($sep);
|
79 |
+
$prefix = ( !empty($this->parent->prefix) ) ? $this->parent->prefix . $sep : '';
|
80 |
+
return $prefix;
|
81 |
+
}
|
82 |
+
|
83 |
+
/**
|
84 |
+
* Check if a string is prefixed
|
85 |
+
* @param string $text Text to check for prefix
|
86 |
+
* @param string $sep (optional) Separator used
|
87 |
+
*/
|
88 |
+
function has_prefix($text, $sep = null) {
|
89 |
+
return ( !empty($text) && stripos($text, $this->get_prefix($sep)) === 0 );
|
90 |
+
}
|
91 |
+
|
92 |
+
/**
|
93 |
+
* Prepend plugin prefix to some text
|
94 |
+
* @param string $text Text to add to prefix
|
95 |
+
* @param string $sep (optional) Text used to separate prefix and text
|
96 |
+
* @param bool $once (optional) Whether to add prefix to text that already contains a prefix or not
|
97 |
+
* @return string Text with prefix prepended
|
98 |
+
*/
|
99 |
+
function add_prefix($text, $sep = '_', $once = true) {
|
100 |
+
if ( $once && $this->has_prefix($text, $sep) )
|
101 |
+
return $text;
|
102 |
+
return $this->get_prefix($sep) . $text;
|
103 |
+
}
|
104 |
+
|
105 |
+
/**
|
106 |
+
* Prepend uppercased plugin prefix to some text
|
107 |
+
* @param string $text Text to add to prefix
|
108 |
+
* @param string $sep (optional) Text used to separate prefix and text
|
109 |
+
* @param bool $once (optional) Whether to add prefix to text that already contains a prefix or not
|
110 |
+
* @return string Text with prefix prepended
|
111 |
+
*/
|
112 |
+
function add_prefix_uc($text, $sep = '_', $once = true) {
|
113 |
+
$args = func_get_args();
|
114 |
+
$var = call_user_func_array($this->m($this, 'add_prefix'), $args);
|
115 |
+
$pre = $this->get_prefix();
|
116 |
+
return str_replace($pre . $sep, strtoupper($pre) . $sep, $var);
|
117 |
+
}
|
118 |
+
|
119 |
+
/**
|
120 |
+
* Add prefix to variable reference
|
121 |
+
* Updates actual variable rather than return value
|
122 |
+
* @uses add_prefix() to add prefix to variable
|
123 |
+
* @param string $var Variable to add prefix to
|
124 |
+
* @param string $sep (optional) Separator text
|
125 |
+
* @param bool $once (optional) Add prefix only once
|
126 |
+
* @return void
|
127 |
+
*/
|
128 |
+
function add_prefix_ref(&$var, $sep = null, $once = true) {
|
129 |
+
$args = func_get_args();
|
130 |
+
$var = call_user_func_array($this->m($this, 'add_prefix'), $args);
|
131 |
+
}
|
132 |
+
|
133 |
+
/**
|
134 |
+
* Remove prefix from specified string
|
135 |
+
* @param string $text String to remove prefix from
|
136 |
+
* @param string $sep (optional) Separator used with prefix
|
137 |
+
*/
|
138 |
+
function remove_prefix($text, $sep = '_') {
|
139 |
+
if ( $this->has_prefix($text,$sep) )
|
140 |
+
$text = substr($text, strlen($this->get_prefix($sep)));
|
141 |
+
return $text;
|
142 |
+
}
|
143 |
+
|
144 |
+
/**
|
145 |
+
* Returns Database prefix for plugin-related DB Tables
|
146 |
+
* @return string Database prefix
|
147 |
+
*/
|
148 |
+
function get_db_prefix() {
|
149 |
+
global $wpdb;
|
150 |
+
return $wpdb->prefix . $this->get_prefix('_');
|
151 |
+
}
|
152 |
+
|
153 |
+
/* Wrapped Values */
|
154 |
+
|
155 |
+
/**
|
156 |
+
* Returns validated object of start/end wrapper values
|
157 |
+
* @param string|array $start Start text (Can also be array defining start & end values)
|
158 |
+
* @param string $end (optional) End text
|
159 |
+
* If $end not defined, then $start is used
|
160 |
+
* @return obj Wrapper
|
161 |
+
*/
|
162 |
+
function get_wrapper($start = null, $end = null) {
|
163 |
+
//Return pre-built wrapper
|
164 |
+
if ( is_object($start) && isset($start->start) && isset($start->end) )
|
165 |
+
return $start;
|
166 |
+
//Default wrapper
|
167 |
+
if ( is_null($start) && is_null($end) )
|
168 |
+
$start = array('[', ']');
|
169 |
+
$wrapper = compact('start', 'end');
|
170 |
+
if ( is_array($start) && count($start) > 1 ) {
|
171 |
+
$wrapper['start'] = $start[0];
|
172 |
+
$wrapper['end'] = $start[1];
|
173 |
+
}
|
174 |
+
if ( !is_string($wrapper['start']) || empty($wrapper['start'] ) )
|
175 |
+
$wrapper['start'] = '';
|
176 |
+
if ( !is_string($wrapper['end']) || empty($wrapper['end']) )
|
177 |
+
$wrapper['end'] = $wrapper['start'];
|
178 |
+
|
179 |
+
return (object) $wrapper;
|
180 |
+
}
|
181 |
+
|
182 |
+
/**
|
183 |
+
* Check if text is wrapped by specified character(s)
|
184 |
+
* @uses this->get_wrapper() to Validate wrapper text
|
185 |
+
* @param string $text Text to check
|
186 |
+
* @param string|array $start (optional) Start text (Array defines both start/end text)
|
187 |
+
* @param string $end (optional) End text
|
188 |
+
*/
|
189 |
+
function has_wrapper($text, $start = null, $end = null) {
|
190 |
+
if ( !is_string($text) || empty($text) )
|
191 |
+
return false;
|
192 |
+
//Validate wrapper)
|
193 |
+
$w = $this->get_wrapper($start, $end);
|
194 |
+
|
195 |
+
//Check for wrapper
|
196 |
+
return ( substr($text, 0, 1) == $w->start && substr($text, -1, 1) == $w->end ) ? true : false;
|
197 |
+
}
|
198 |
+
|
199 |
+
/**
|
200 |
+
* Remove wrapper from specified text
|
201 |
+
* @uses this->has_wrapper() to check if text is wrapped
|
202 |
+
* @uses this->get_wrapper() to retrieve wrapper object
|
203 |
+
* @param string $text Text to check
|
204 |
+
* @param string|array $start (optional) Start text (Array defines both start/end text)
|
205 |
+
* @param string $end (optional) End text
|
206 |
+
* @return string Unwrapped text
|
207 |
+
*/
|
208 |
+
function remove_wrapper($text, $start = null, $end = null) {
|
209 |
+
if ( $this->has_wrapper($text, $start, $end) ) {
|
210 |
+
$w = $this->get_wrapper($start, $end);
|
211 |
+
$text = substr($text, strlen($w->start), strlen($text) - strlen($w->start) - strlen($w->end) );
|
212 |
+
}
|
213 |
+
|
214 |
+
return $text;
|
215 |
+
}
|
216 |
+
|
217 |
+
/**
|
218 |
+
* Add wrapper to specified text
|
219 |
+
* @uses this->get_wrapper() to retrieve wrapper object
|
220 |
+
* @param string $text Text to wrap
|
221 |
+
* @param string|array $start (optional) Start text (Array defines both start/end text)
|
222 |
+
* @param string $end (optional) End text
|
223 |
+
* @param bool $once (optional) Whether to wrap text only once (Default: TRUE)
|
224 |
+
* @return string Wrapped text
|
225 |
+
*/
|
226 |
+
function add_wrapper($text, $start = null, $end = null, $once = true) {
|
227 |
+
$w = $this->get_wrapper($start, $end);
|
228 |
+
if ( !$once || !$this->has_wrapper($text, $w) )
|
229 |
+
$text = $w->start . $text . $w->end;
|
230 |
+
return $text;
|
231 |
+
}
|
232 |
+
|
233 |
+
/*-** Client **-*/
|
234 |
+
|
235 |
+
/**
|
236 |
+
* Parses client files array
|
237 |
+
* > Adds ID property (prefixed file key)
|
238 |
+
* > Parses and validates internal dependencies
|
239 |
+
* > Converts properties array to object
|
240 |
+
* Properties
|
241 |
+
* > file (string|array): File name (string) or callback (array) to retrieve file name
|
242 |
+
* > deps (array) [optional]: Dependencies
|
243 |
+
* > Values wrapped in square brackets (`[` & `]`) are internal files
|
244 |
+
* > callback (string|array) [optional]: Global callback to determine whether file should be loaded
|
245 |
+
* > Values wrapped in square brackets (`[` & `]`) are internal methods (of parent object)
|
246 |
+
* > context (array) [optional]: Context(s) in which to load the file
|
247 |
+
* Acceptable values
|
248 |
+
* > string: Context name
|
249 |
+
* > array: Context name + callback (both must return TRUE to load file)
|
250 |
+
* > Callback follows same pattern as `callback` member
|
251 |
+
* @param array $files Files array
|
252 |
+
* @return object Client files
|
253 |
+
*/
|
254 |
+
function parse_client_files($files, $type = 'scripts') {
|
255 |
+
if ( is_array($files) && !empty($files) ) {
|
256 |
+
//Defaults
|
257 |
+
$defaults = array(
|
258 |
+
'file' => null,
|
259 |
+
'deps' => array(),
|
260 |
+
'callback' => null,
|
261 |
+
'context' => array()
|
262 |
+
);
|
263 |
+
switch ( $type ) {
|
264 |
+
case 'styles':
|
265 |
+
$defaults['media'] = 'all';
|
266 |
+
break;
|
267 |
+
default:
|
268 |
+
$defaults['in_footer'] = false;
|
269 |
+
}
|
270 |
+
//Iterate through files
|
271 |
+
foreach ( $files as $h => $p ) {
|
272 |
+
unset($file, $cb, $ctxs, $ctx);
|
273 |
+
//Set ID
|
274 |
+
$p['id'] = $this->add_prefix($h);
|
275 |
+
//Type Validation
|
276 |
+
foreach ( $defaults as $m => $d ) {
|
277 |
+
//Check if value requires validation
|
278 |
+
if ( !is_array($d) || !isset($p[$m]) || is_array($p[$m]) )
|
279 |
+
continue;
|
280 |
+
//Wrap value in array or destroy it
|
281 |
+
if ( is_scalar($p[$m]) )
|
282 |
+
$p[$m] = array($p[$m]);
|
283 |
+
else
|
284 |
+
unset($p[$m]);
|
285 |
+
}
|
286 |
+
|
287 |
+
$p = array_merge($defaults, $p);
|
288 |
+
|
289 |
+
/* File name */
|
290 |
+
|
291 |
+
//Validate file
|
292 |
+
$file =& $p['file'];
|
293 |
+
|
294 |
+
//Determine if filename or callback
|
295 |
+
if ( !$this->is_file($file) )
|
296 |
+
$file = $this->parse_client_file_callback($file);
|
297 |
+
//Remove invalid file and move on to next
|
298 |
+
if ( empty($file) ) {
|
299 |
+
unset($files[$h]);
|
300 |
+
continue;
|
301 |
+
}
|
302 |
+
|
303 |
+
/* Dependencies */
|
304 |
+
|
305 |
+
//Format internal dependencies
|
306 |
+
foreach ( $p['deps'] as $idx => $dep ) {
|
307 |
+
if ( $this->has_wrapper($dep) ) {
|
308 |
+
$dep = $this->remove_wrapper($dep);
|
309 |
+
$p['deps'][$idx] = $this->add_prefix($dep);
|
310 |
+
}
|
311 |
+
}
|
312 |
+
|
313 |
+
/* Context */
|
314 |
+
|
315 |
+
//Validate callback
|
316 |
+
$cb =& $p['callback'];
|
317 |
+
if ( !is_null($cb) ) {
|
318 |
+
$cb = $this->parse_client_file_callback($cb);
|
319 |
+
//Remove files with invalid callbacks (will never be loaded)
|
320 |
+
if ( is_null($cb) ) {
|
321 |
+
unset($files[$h]);
|
322 |
+
continue;
|
323 |
+
}
|
324 |
+
}
|
325 |
+
|
326 |
+
//Validate contexts
|
327 |
+
$ctxs =& $p['context'];
|
328 |
+
$ctxs = array_unique($ctxs);
|
329 |
+
$has_contexts = ( count($ctxs) > 0 ) ? true : false;
|
330 |
+
foreach ( $ctxs as $idx => $ctx ) {
|
331 |
+
//Convert to array
|
332 |
+
$ctx = array_values( array_slice( (array) $ctx, 0, 2 ) );
|
333 |
+
switch ( count($ctx) ) {
|
334 |
+
case 1 :
|
335 |
+
//Simple context
|
336 |
+
$ctx = $ctx[0];
|
337 |
+
break;
|
338 |
+
case 2 :
|
339 |
+
//Context + Callback
|
340 |
+
$ctx[1] = $this->parse_client_file_callback($ctx[1]);
|
341 |
+
if ( !is_null($ctx[1]) ) {
|
342 |
+
break;
|
343 |
+
}
|
344 |
+
//Continue to default case if callback is invalid
|
345 |
+
default :
|
346 |
+
//Context is invalid
|
347 |
+
$ctx = false;
|
348 |
+
break;
|
349 |
+
}
|
350 |
+
|
351 |
+
//Remove invalid contexts
|
352 |
+
if ( empty($ctx) ) {
|
353 |
+
unset($ctxs[$idx]);
|
354 |
+
} else {
|
355 |
+
$ctxs[$idx] = $ctx;
|
356 |
+
}
|
357 |
+
}
|
358 |
+
//Remove file if all specified contexts invalid (no context is OK)
|
359 |
+
if ( $has_contexts && empty($ctxs) ) {
|
360 |
+
unset($files[$h]);
|
361 |
+
continue;
|
362 |
+
}
|
363 |
+
$ctxs = array_values($ctxs);
|
364 |
+
|
365 |
+
/* Finalize Properties */
|
366 |
+
|
367 |
+
//Convert properties to object
|
368 |
+
$files[$h] = (object) $p;
|
369 |
+
}
|
370 |
+
}
|
371 |
+
//Cast to object before returning
|
372 |
+
$files = (object) $files;
|
373 |
+
return $files;
|
374 |
+
}
|
375 |
+
|
376 |
+
/**
|
377 |
+
* Parses callbacks set for client files
|
378 |
+
* @param string $callback Callback value
|
379 |
+
* > Values wrapped in square brackets (`[` & `]`) are internal methods (of parent object)
|
380 |
+
* @return callback|null Validated callback (NULL if callback is invalid)
|
381 |
+
*/
|
382 |
+
function parse_client_file_callback($callback) {
|
383 |
+
if ( $this->has_wrapper($callback) ) {
|
384 |
+
$callback = $this->m($this->parent, $this->remove_wrapper($callback));
|
385 |
+
}
|
386 |
+
if ( !is_callable($callback) )
|
387 |
+
$callback = null;
|
388 |
+
return $callback;
|
389 |
+
}
|
390 |
+
|
391 |
+
/**
|
392 |
+
* Build JS client object
|
393 |
+
* @param string (optional) $path Additional object path
|
394 |
+
* @return string Client object
|
395 |
+
*/
|
396 |
+
function get_client_object($path = null) {
|
397 |
+
$obj = strtoupper($this->get_prefix());
|
398 |
+
if ( !empty($path) && is_string($path) ) {
|
399 |
+
if ( 0 !== strpos($path, '[') )
|
400 |
+
$obj .= '.';
|
401 |
+
$obj .= $path;
|
402 |
+
}
|
403 |
+
return $obj;
|
404 |
+
}
|
405 |
+
|
406 |
+
/**
|
407 |
+
* Build jQuery JS expression to add data to specified client object
|
408 |
+
* @param string|obj $obj Name of client object (Set to root object if not a valid name)
|
409 |
+
* @param mixed $data Data to add to client object
|
410 |
+
* @param bool (optional) $out Whether or not to output code (Default: false)
|
411 |
+
* @return string JS expression to extend client object
|
412 |
+
*/
|
413 |
+
function extend_client_object($obj, $data = null, $out = false) {
|
414 |
+
//Validate parameters
|
415 |
+
$args = func_get_args();
|
416 |
+
switch ( count($args) ) {
|
417 |
+
case 2:
|
418 |
+
if ( !is_scalar($args[0]) ) {
|
419 |
+
if ( is_bool($args[1]) )
|
420 |
+
$out = $args[1];
|
421 |
+
} else {
|
422 |
+
break;
|
423 |
+
}
|
424 |
+
case 1:
|
425 |
+
$data = $args[0];
|
426 |
+
$obj = null;
|
427 |
+
break;
|
428 |
+
}
|
429 |
+
//Default client object
|
430 |
+
if ( !is_string($obj) || empty($obj) )
|
431 |
+
$obj = null;
|
432 |
+
//Default data
|
433 |
+
if ( is_array($data) )
|
434 |
+
$data = (object)$data;
|
435 |
+
//Build expression
|
436 |
+
if ( empty($data) || ( empty($obj) && is_scalar($data) ) ) {
|
437 |
+
$ret = '';
|
438 |
+
} else {
|
439 |
+
$ret = array();
|
440 |
+
//Validate object(s) being extended
|
441 |
+
$c_obj = $this->get_client_object($obj);
|
442 |
+
$sep = '.';
|
443 |
+
$c_obj = trim($c_obj, $sep);
|
444 |
+
//Start with full object
|
445 |
+
$objs = array($c_obj);
|
446 |
+
$offset = 0;
|
447 |
+
$len = strlen($c_obj);
|
448 |
+
//Add segments to array (in reverse)
|
449 |
+
while ( ( $pos = strrpos($c_obj, $sep, $offset) ) && $pos !== false ) {
|
450 |
+
$objs[] = substr($c_obj, 0, $pos);
|
451 |
+
$offset = $pos - $len - 1;
|
452 |
+
}
|
453 |
+
|
454 |
+
$condition = 'if ( ' . implode(' && ', array_reverse($objs)) . ' ) ';
|
455 |
+
$ret = $condition . '$.extend(' . $c_obj . ', ' . json_encode($data) . ');';
|
456 |
+
if ( $out )
|
457 |
+
echo $this->build_script_element($ret);
|
458 |
+
}
|
459 |
+
return $ret;
|
460 |
+
}
|
461 |
+
|
462 |
+
/**
|
463 |
+
* Build client method call
|
464 |
+
* @uses get_client_object() to generate the body of the method call
|
465 |
+
* @param string $method Method name
|
466 |
+
* @param mixed Parameters to pass to method (will be JSON-encoded)
|
467 |
+
* @return string Method call
|
468 |
+
*/
|
469 |
+
function call_client_method($method, $params = null) {
|
470 |
+
if ( !$method )
|
471 |
+
return '';
|
472 |
+
$params = ( !is_null($params) ) ? json_encode($params) : '';
|
473 |
+
return $this->get_client_object($method) . '(' . $params. ');';
|
474 |
+
}
|
475 |
+
|
476 |
/*-** WP **-*/
|
477 |
|
478 |
/**
|
499 |
return true;
|
500 |
}
|
501 |
|
502 |
+
/* Hooks */
|
503 |
+
|
504 |
+
/**
|
505 |
+
* Retrieve parent object
|
506 |
+
* @return obj|bool Parent object (FALSE if no valid parent set)
|
507 |
+
*/
|
508 |
+
function &get_parent() {
|
509 |
+
if ( is_object($this->parent) )
|
510 |
+
return $this->parent;
|
511 |
+
else
|
512 |
+
return false;
|
513 |
+
}
|
514 |
+
|
515 |
+
/**
|
516 |
+
* Retrieve parent property value
|
517 |
+
* @uses self::get_parent()
|
518 |
+
* @param string $prop Property name
|
519 |
+
* @param mixed $default Default value
|
520 |
+
* @return mixed Parent property value
|
521 |
+
*/
|
522 |
+
function get_parent_property($prop, $default = '') {
|
523 |
+
$p =& $this->get_parent();
|
524 |
+
return ( !!$p && property_exists($p, $prop) ) ? $p->{$prop} : $default;
|
525 |
+
}
|
526 |
+
|
527 |
+
/**
|
528 |
+
* Retrieve formatted name for internal hooks
|
529 |
+
* Prefixes with parent prefix and hook prefix
|
530 |
+
* @uses self::get_parent_property() to retrieve hook prefix
|
531 |
+
* @uses self::add_prefix()
|
532 |
+
* @param string $tag Base tag
|
533 |
+
* @return string Formatted hook
|
534 |
+
*/
|
535 |
+
function get_hook($tag) {
|
536 |
+
//Hook prefix
|
537 |
+
$hook = $this->get_parent_property('hook_prefix', '');
|
538 |
+
if ( !empty($hook) )
|
539 |
+
$hook .= '_';
|
540 |
+
//Prefix
|
541 |
+
return $this->add_prefix($hook . $tag);
|
542 |
+
}
|
543 |
+
|
544 |
+
/**
|
545 |
+
* Run internal action
|
546 |
+
* Namespaces $tag
|
547 |
+
* @uses self::get_hook()
|
548 |
+
* @see do_action()
|
549 |
+
*/
|
550 |
+
function do_action($tag, $arg = '') {
|
551 |
+
$args = func_get_args();
|
552 |
+
$args[0] = $this->get_hook($tag);
|
553 |
+
return call_user_func_array('do_action', $args);
|
554 |
+
}
|
555 |
+
|
556 |
+
/**
|
557 |
+
* Run internal action passing arguments in array
|
558 |
+
* @uses do_action_ref_array()
|
559 |
+
*/
|
560 |
+
function do_action_ref_array($tag, $args) {
|
561 |
+
return do_action_ref_array($this->get_hook($tag), $args);
|
562 |
+
}
|
563 |
+
|
564 |
+
/**
|
565 |
+
* Run internal filter
|
566 |
+
* Namespaces $tag
|
567 |
+
* @uses self::get_hook()
|
568 |
+
* @see apply_filters()
|
569 |
+
*/
|
570 |
+
function apply_filters($tag, $value) {
|
571 |
+
$args = func_get_args();
|
572 |
+
$args[0] = $this->get_hook($tag);
|
573 |
+
return call_user_func_array('apply_filters', $args);
|
574 |
+
}
|
575 |
+
|
576 |
+
/**
|
577 |
+
* Run internal filter passing arguments in array
|
578 |
+
* @uses apply_filters_ref_array()
|
579 |
+
*/
|
580 |
+
function apply_filters_ref_array($tag, $args) {
|
581 |
+
return apply_filters_ref_array($this->get_hook($tag), $args);
|
582 |
+
}
|
583 |
+
|
584 |
+
/**
|
585 |
+
* Add internal action
|
586 |
+
* Namespaces $tag
|
587 |
+
* @uses self::get_hook()
|
588 |
+
* @see add_action()
|
589 |
+
*/
|
590 |
+
function add_action($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
|
591 |
+
return add_action($this->get_hook($tag), $function_to_add, $priority, $accepted_args);
|
592 |
+
}
|
593 |
+
|
594 |
+
/**
|
595 |
+
* Add internal filter
|
596 |
+
* Namespaces $tag
|
597 |
+
* @uses self::get_hook()
|
598 |
+
* @see add_filter()
|
599 |
+
*/
|
600 |
+
function add_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
|
601 |
+
return add_filter($this->get_hook($tag), $function_to_add, $priority, $accepted_args);
|
602 |
+
}
|
603 |
+
|
604 |
+
/**
|
605 |
+
* Remove internal action
|
606 |
+
* Namespaces $tag
|
607 |
+
* @uses self::get_hook()
|
608 |
+
* @uses remove_action()
|
609 |
+
*/
|
610 |
+
function remove_action($tag, $function_to_remove, $priority = 10, $accepted_args = 1) {
|
611 |
+
return remove_action($this->get_hook($tag), $function_to_remove, $priority, $accepted_args);
|
612 |
+
}
|
613 |
+
|
614 |
+
/**
|
615 |
+
* Remove internal filter
|
616 |
+
* Namespaces $tag
|
617 |
+
* @uses self::get_hook()
|
618 |
+
* @uses remove_filter()
|
619 |
+
*/
|
620 |
+
function remove_filter($tag, $function_to_remove, $priority = 10, $accepted_args = 1) {
|
621 |
+
return remove_filter($this->get_hook($tag), $function_to_remove, $priority, $accepted_args);
|
622 |
+
}
|
623 |
+
|
624 |
+
/* Meta */
|
625 |
+
|
626 |
+
/**
|
627 |
+
* Retrieves post metadata for internal methods
|
628 |
+
* Metadata set internally is wrapped in an array so it is unwrapped before returned the retrieved value
|
629 |
+
* @see get_post_meta()
|
630 |
+
* @param int $post_id Post ID
|
631 |
+
* @param string $key Name of metadata to retrieve
|
632 |
+
* @param boolean $single Whether or not to retrieve single value or not
|
633 |
+
* @return mixed Retrieved post metadata
|
634 |
+
*/
|
635 |
+
function post_meta_get($post_id, $key, $single = false) {
|
636 |
+
$meta_value = get_post_meta($post_id, $this->post_meta_get_key($key), $single);
|
637 |
+
if (is_array($meta_value) && count($meta_value) == 1)
|
638 |
+
$meta_value = $meta_value[0];
|
639 |
+
return $meta_value;
|
640 |
+
}
|
641 |
+
|
642 |
+
/**
|
643 |
+
* Wraps metadata in array for storage in database
|
644 |
+
* @param mixed $meta_value Value to be set as metadata
|
645 |
+
* @return array Wrapped metadata value
|
646 |
+
*/
|
647 |
+
function post_meta_prepare_value($meta_value) {
|
648 |
+
return array($meta_value);
|
649 |
+
}
|
650 |
+
|
651 |
+
/**
|
652 |
+
* Adds Metadata for a post to database
|
653 |
+
* For internal methods
|
654 |
+
* @see add_post_meta
|
655 |
+
* @param $post_id
|
656 |
+
* @param $meta_key
|
657 |
+
* @param $meta_value
|
658 |
+
* @param $unique
|
659 |
+
* @return boolean Result of operation
|
660 |
+
*/
|
661 |
+
function post_meta_add($post_id, $meta_key, $meta_value, $unique = false) {
|
662 |
+
$meta_value = $this->post_meta_value_prepare($meta_value);
|
663 |
+
return add_post_meta($post_id, $meta_key, $meta_value, $unique);
|
664 |
+
}
|
665 |
+
|
666 |
+
/**
|
667 |
+
* Updates post metadata for internal data/methods
|
668 |
+
* @see update_post_meta()
|
669 |
+
* @param $post_id
|
670 |
+
* @param $meta_key
|
671 |
+
* @param $meta_value
|
672 |
+
* @param $prev_value
|
673 |
+
* @return boolean Result of operation
|
674 |
+
*/
|
675 |
+
function post_meta_update($post_id, $meta_key, $meta_value, $prev_value = '') {
|
676 |
+
$meta_value = $this->post_meta_prepare_value($meta_value);
|
677 |
+
return update_post_meta($post_id, $meta_key, $meta_value, $prev_value);
|
678 |
+
}
|
679 |
+
|
680 |
+
/**
|
681 |
+
* Builds postmeta key for custom data set by plugin
|
682 |
+
* @param string $key Base key name
|
683 |
+
* @return string Formatted postmeta key
|
684 |
+
*/
|
685 |
+
function post_meta_get_key($key) {
|
686 |
+
$sep = '_';
|
687 |
+
if ( strpos($key, $sep . $this->prefix) !== 0 ) {
|
688 |
+
$key_base = func_get_args();
|
689 |
+
if ( !empty($key_base) ) {
|
690 |
+
$key = array_merge((array)$this->prefix, $key_base);
|
691 |
+
return $sep . implode($sep, $key);
|
692 |
+
}
|
693 |
+
}
|
694 |
+
|
695 |
+
return $key;
|
696 |
+
}
|
697 |
+
|
698 |
+
/**
|
699 |
+
* Creates a meta key for storing post meta data
|
700 |
+
* Prefixes standard prefixed text with underscore to hide meta data on post edit forms
|
701 |
+
* @param string $text Text to use as base of meta key
|
702 |
+
* @return string Formatted meta key
|
703 |
+
*/
|
704 |
+
function make_meta_key($text = '') {
|
705 |
+
return '_' . $this->add_prefix($text);
|
706 |
+
}
|
707 |
+
|
708 |
/*-** Request **-*/
|
709 |
|
710 |
/**
|
711 |
+
* Checks if the currently executing file matches specified file name
|
712 |
* @param string $filename Filename to check for
|
713 |
* @return bool TRUE if current page matches specified filename, FALSE otherwise
|
714 |
*/
|
715 |
+
function is_current_file( $filename ) {
|
716 |
return ( $filename == basename( $_SERVER['SCRIPT_NAME'] ) );
|
717 |
}
|
718 |
|
722 |
*/
|
723 |
function is_admin_management_page() {
|
724 |
return ( is_admin()
|
725 |
+
&& ( $this->is_current_file('edit.php')
|
726 |
+
|| ( $this->is_current_file('admin.php')
|
727 |
&& isset($_GET['page'])
|
728 |
&& strpos($_GET['page'], 'cnr') === 0 )
|
729 |
)
|
730 |
);
|
731 |
}
|
732 |
|
733 |
+
function is_a($obj, $class_name) {
|
734 |
+
return ( is_object($obj) && is_a($obj, $this->add_prefix_uc($class_name)) ) ? true : false;
|
735 |
+
}
|
736 |
+
|
737 |
+
/* Context */
|
738 |
+
|
739 |
+
/**
|
740 |
+
* Retrieve context for current request
|
741 |
+
* @return array Context
|
742 |
+
*/
|
743 |
+
function get_context() {
|
744 |
+
//Context
|
745 |
+
static $ctx = null;
|
746 |
+
if ( !is_array($ctx) ) {
|
747 |
+
//Standard
|
748 |
+
$ctx = array($this->build_context());
|
749 |
+
//Action
|
750 |
+
$action = $this->get_action();
|
751 |
+
if ( !empty($action) )
|
752 |
+
$ctx[] = $this->build_context('action', $action);
|
753 |
+
//Admin page
|
754 |
+
if ( is_admin() ) {
|
755 |
+
global $pagenow;
|
756 |
+
$pg = $this->strip_file_extension($pagenow);
|
757 |
+
$ctx[] = $this->build_context('page', $pg);
|
758 |
+
if ( !empty($action) )
|
759 |
+
$ctx[] = $this->build_context('page', $pg, 'action', $action);
|
760 |
+
}
|
761 |
+
//User
|
762 |
+
$u = wp_get_current_user();
|
763 |
+
$ctx[] = $this->build_context('user', ( $u->ID ) ? 'registered' : 'guest', false);
|
764 |
+
}
|
765 |
+
|
766 |
+
return $ctx;
|
767 |
+
}
|
768 |
+
|
769 |
+
/**
|
770 |
+
* Builds context from multiple components
|
771 |
+
* Usage:
|
772 |
+
* > $prefix can be omitted and context strings can be added as needed
|
773 |
+
* > Multiple context strings may be passed to be joined together
|
774 |
+
*
|
775 |
+
* @param string (optional) $context Variable number of components to add to context
|
776 |
+
* @param bool (optional) $prefix Whether or not to prefix context with request type (public or admin) [Default: TRUE]
|
777 |
+
* @return string Context
|
778 |
+
*/
|
779 |
+
function build_context($context = null, $prefix = true) {
|
780 |
+
$args = func_get_args();
|
781 |
+
//Get prefix option
|
782 |
+
if ( !empty($args) ) {
|
783 |
+
$prefix = ( is_bool($args[count($args) - 1]) ) ? array_pop($args) : true;
|
784 |
+
}
|
785 |
+
|
786 |
+
//Validate
|
787 |
+
$context = array_filter($args, 'is_string');
|
788 |
+
$sep = '_';
|
789 |
+
|
790 |
+
//Context Prefix
|
791 |
+
if ( $prefix )
|
792 |
+
array_unshift($context, ( is_admin() ) ? 'admin' : 'public' );
|
793 |
+
return implode($sep, $context);
|
794 |
+
}
|
795 |
+
|
796 |
+
/**
|
797 |
+
* Check if context exists in current request
|
798 |
+
* @param string $context Context to check for
|
799 |
+
* @return bool TRUE if context exists FALSE otherwise
|
800 |
+
*/
|
801 |
+
function is_context($context) {
|
802 |
+
$ret = false;
|
803 |
+
if ( is_scalar($context) )
|
804 |
+
$context = array($context);
|
805 |
+
if ( is_array($context) && !empty($context) ) {
|
806 |
+
$ictx = array_intersect($this->get_context(), $context);
|
807 |
+
if ( !empty($ictx) )
|
808 |
+
$ret = true;
|
809 |
+
}
|
810 |
+
return $ret;
|
811 |
+
}
|
812 |
+
|
813 |
/**
|
814 |
* Joins and normalizes the slashes in the paths passed to method
|
815 |
* All forward/back slashes are converted to forward slashes
|
816 |
* Multiple path segments can be passed as additional argments
|
817 |
* @param string $path Path to normalize
|
818 |
+
* @param bool|array $trailing_slash (optional) Whether or not normalized path should have a trailing slash or not (Default: FALSE)
|
819 |
+
* If array is passed, first index is trailing, second is leading slash
|
820 |
+
* If multiple path segments are passed, $trailing_slash will be the LAST parameter (default value used if omitted)
|
821 |
*/
|
822 |
function normalize_path($path, $trailing_slash = false) {
|
823 |
$sl_f = '/';
|
824 |
$sl_b = '\\';
|
825 |
$parts = func_get_args();
|
826 |
+
//Slash defaults (trailing, leading);
|
827 |
+
$slashes = array(false, true);
|
828 |
if ( func_num_args() > 1 ) {
|
829 |
+
//Get last argument
|
830 |
+
$arg_last = $parts[count($parts) - 1];
|
831 |
+
if ( is_bool($arg_last) ) {
|
832 |
+
$arg_last = array($arg_last);
|
833 |
+
}
|
834 |
+
|
835 |
+
if ( is_array($arg_last) && count($arg_last) > 0 && is_bool($arg_last[0]) ) {
|
836 |
+
//Remove slash paramter from args array
|
837 |
array_pop($parts);
|
838 |
+
//Normalize slashes options
|
839 |
+
if ( isset($arg_last[0]) )
|
840 |
+
$slashes[0] = $arg_last[0];
|
841 |
+
if ( isset($arg_last[1]) )
|
842 |
+
$slashes[1] = $arg_last[1];
|
843 |
}
|
844 |
+
}
|
845 |
+
//Extract to slash options local variables
|
846 |
+
list($trailing_slash, $leading_slash) = $slashes;
|
847 |
+
|
848 |
+
//Clean path segments
|
849 |
+
foreach ( $parts as $key => $part ) {
|
850 |
+
//Trim slashes/spaces
|
851 |
+
$parts[$key] = trim($part, " " . $sl_f . $sl_b);
|
852 |
+
|
853 |
+
//Verify path segment still contains value
|
854 |
+
if ( empty($parts[$key]) ) {
|
855 |
+
unset($parts[$key]);
|
856 |
+
continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
857 |
}
|
858 |
}
|
859 |
+
|
860 |
//Join path parts together
|
861 |
$parts = implode($sl_b, $parts);
|
862 |
$parts = str_replace($sl_b, $sl_f, $parts);
|
863 |
//Add trailing slash (if necessary)
|
864 |
if ( $trailing_slash )
|
865 |
+
$parts .= $sl_f;
|
866 |
+
//Add leading slash (if necessary)
|
867 |
+
$regex = '#^.+:[\\/]#';
|
868 |
+
if ( $leading_slash && !preg_match($regex, $parts) ) {
|
869 |
+
$parts = $sl_f . $parts;
|
870 |
+
}
|
871 |
return $parts;
|
872 |
}
|
873 |
|
874 |
/**
|
875 |
* Returns URL of file (assumes that it is in plugin directory)
|
876 |
* @param string $file name of file get URL
|
877 |
+
* @return string File URL
|
878 |
*/
|
879 |
function get_file_url($file) {
|
880 |
+
if ( is_string($file) && '' != trim($file) ) {
|
881 |
+
$file = str_replace(' ', '%20', $this->normalize_path($this->get_url_base(), $file));
|
882 |
}
|
883 |
return $file;
|
884 |
}
|
885 |
|
886 |
+
/**
|
887 |
+
* Returns path to plugin file
|
888 |
+
* @param string $file file name
|
889 |
+
* @return string File path
|
890 |
+
*/
|
891 |
+
function get_file_path($file) {
|
892 |
+
if ( is_string($file) && '' != trim($file) ) {
|
893 |
+
$file = $this->normalize_path($this->get_path_base(), $file);
|
894 |
+
}
|
895 |
+
return $file;
|
896 |
+
}
|
897 |
+
|
898 |
+
function get_plugin_file_path($file, $trailing_slash = false) {
|
899 |
+
if ( is_string($file) && '' != trim($file) )
|
900 |
+
$file = $this->normalize_path($this->get_plugin_base(), $file, $trailing_slash);
|
901 |
+
return $file;
|
902 |
+
}
|
903 |
+
|
904 |
+
/**
|
905 |
+
* Checks if value is valid file name
|
906 |
+
* @param string $filename File name to check
|
907 |
+
* @return bool TRUE if valid file name, FALSE otherwise
|
908 |
+
*/
|
909 |
+
function is_file($filename) {
|
910 |
+
$ext = $this->get_file_extension($filename);
|
911 |
+
return ( empty($ext) ) ? false : true;
|
912 |
+
}
|
913 |
+
|
914 |
/**
|
915 |
* Retrieves file extension
|
916 |
* @param string $file file name/path
|
917 |
+
* @param bool (optional) $lowercase Whether lowercase extension should be returned (Default: TRUE)
|
918 |
* @return string File's extension
|
919 |
*/
|
920 |
+
function get_file_extension($file, $lowercase = true) {
|
921 |
$ret = '';
|
922 |
$sep = '.';
|
923 |
+
if ( !is_string($file) )
|
924 |
+
return $ret;
|
925 |
+
if ( ( $rpos = strrpos($file, $sep) ) > 0 )
|
926 |
$ret = substr($file, $rpos + 1);
|
927 |
+
if ( !!$lowercase )
|
928 |
+
$ret = strtolower($ret);
|
929 |
return $ret;
|
930 |
}
|
931 |
|
932 |
/**
|
933 |
* Checks if file has specified extension
|
934 |
+
* @uses get_file_extension()
|
935 |
* @param string $file File name/path
|
936 |
+
* @param string|array $extension File ending(s) to check $file for
|
937 |
+
* @param bool (optional) Whether check should be case senstive or not (Default: FALSE)
|
938 |
* @return bool TRUE if file has extension
|
939 |
*/
|
940 |
+
function has_file_extension($file, $extension, $case_sensitive = false) {
|
941 |
+
if ( !is_array($extension) )
|
942 |
+
$extension = array(strval($extension));
|
943 |
+
if ( !$case_sensitive ) {
|
944 |
+
//Normalize extensions
|
945 |
+
$extension = array_map('strtolower', $extension);
|
946 |
+
}
|
947 |
+
return ( in_array($this->get_file_extension($file, !$case_sensitive), $extension) ) ? true : false;
|
948 |
+
}
|
949 |
+
|
950 |
+
/**
|
951 |
+
* Removes file extension from file name
|
952 |
+
* The extension is the text following the last period ('.') in the file name
|
953 |
+
* @uses get_file_extension()
|
954 |
+
* @param string $file File name
|
955 |
+
* @return string File name without extension
|
956 |
+
*/
|
957 |
+
function strip_file_extension($file) {
|
958 |
+
$ext = $this->get_file_extension($file);
|
959 |
+
if ( !empty($ext) ) {
|
960 |
+
$file = substr($file, 0, (strlen($ext) + 1) * -1);
|
961 |
+
}
|
962 |
+
return $file;
|
963 |
}
|
964 |
|
965 |
/**
|
966 |
* Retrieve base URL for plugin-specific files
|
967 |
+
* @uses get_plugin_base()
|
968 |
+
* @uses normalize_path()
|
969 |
* @return string Base URL
|
970 |
*/
|
971 |
function get_url_base() {
|
972 |
static $url_base = '';
|
973 |
if ( '' == $url_base ) {
|
974 |
+
$url_base = $this->normalize_path(plugins_url(), $this->get_plugin_base());
|
975 |
}
|
976 |
return $url_base;
|
977 |
}
|
978 |
|
979 |
+
/**
|
980 |
+
* Retrieve plugin's base path
|
981 |
+
* @uses WP_PLUGIN_DIR
|
982 |
+
* @uses get_plugin_base()
|
983 |
+
* @uses normalize_path()
|
984 |
+
* @return string Base path
|
985 |
+
*/
|
986 |
function get_path_base() {
|
987 |
static $path_base = '';
|
988 |
if ( '' == $path_base ) {
|
990 |
}
|
991 |
return $path_base;
|
992 |
}
|
993 |
+
|
994 |
+
/**
|
995 |
+
* Retrieve plugin's base directory
|
996 |
+
* @uses WP_PLUGIN_DIR
|
997 |
+
* @uses normalize_path()
|
998 |
+
* @return string Base directory
|
999 |
+
*/
|
1000 |
+
function get_plugin_base($trim = false) {
|
1001 |
static $plugin_dir = '';
|
1002 |
if ( '' == $plugin_dir ) {
|
1003 |
$plugin_dir = str_replace($this->normalize_path(WP_PLUGIN_DIR), '', $this->normalize_path(dirname(dirname(__FILE__))));
|
1004 |
}
|
1005 |
+
if ( $trim )
|
1006 |
+
$plugin_dir = trim($plugin_dir, ' \/');
|
1007 |
return $plugin_dir;
|
1008 |
}
|
1009 |
|
1010 |
+
/**
|
1011 |
+
* Retrieve plugin's base file path
|
1012 |
+
* @uses get_path_base()
|
1013 |
+
* @uses get_file_path()
|
1014 |
+
* @return string Base file path
|
1015 |
+
*/
|
1016 |
function get_plugin_base_file() {
|
1017 |
+
static $file = '';
|
1018 |
+
if ( empty($file) ) {
|
1019 |
+
$dir = @ opendir($this->get_path_base());
|
1020 |
+
if ( $dir ) {
|
1021 |
+
while ( ($ftemp = readdir($dir)) !== false ) {
|
1022 |
+
//Only process PHP files
|
1023 |
+
$ftemp = $this->get_file_path($ftemp);
|
1024 |
+
if ( !$this->has_file_extension($ftemp, 'php') || !is_readable($ftemp) )
|
1025 |
+
continue;
|
1026 |
+
//Check for data
|
1027 |
+
$data = get_file_data($ftemp, $this->plugin_headers);
|
1028 |
+
if ( !empty($data['Name']) ) {
|
1029 |
+
//Set base file
|
1030 |
+
$file = $ftemp;
|
1031 |
+
break;
|
1032 |
+
}
|
1033 |
+
}
|
1034 |
+
}
|
1035 |
+
@closedir($dir);
|
1036 |
+
}
|
1037 |
+
//Return
|
1038 |
+
return $file;
|
1039 |
}
|
1040 |
|
1041 |
+
/**
|
1042 |
+
* Retrieve plugin's internal name
|
1043 |
+
* Internal name is used by WP core
|
1044 |
+
* @uses get_plugin_base_file()
|
1045 |
+
* @uses plugin_basename()
|
1046 |
+
* @return string Internal plugin name
|
1047 |
+
*/
|
1048 |
function get_plugin_base_name() {
|
1049 |
+
static $name = false;
|
1050 |
+
if ( !$name ) {
|
1051 |
+
$file = $this->get_plugin_base_file();
|
1052 |
+
$name = plugin_basename($file);
|
1053 |
+
}
|
1054 |
+
return $name;
|
1055 |
+
}
|
1056 |
+
|
1057 |
+
/**
|
1058 |
+
* Retrieve plugin info
|
1059 |
+
* Parses info comment in main plugin file
|
1060 |
+
* @uses get_plugin_base_file()
|
1061 |
+
*/
|
1062 |
+
function get_plugin_info($field = '') {
|
1063 |
+
static $data = array();
|
1064 |
+
$ret = '';
|
1065 |
+
//Get plugin data
|
1066 |
+
if ( empty($data) ) {
|
1067 |
+
$file = $this->get_plugin_base_file();
|
1068 |
+
$data = get_file_data($file, $this->plugin_headers);
|
1069 |
+
}
|
1070 |
+
//Return specified field
|
1071 |
+
if ( !empty($field) ) {
|
1072 |
+
if ( isset($data[$field]) )
|
1073 |
+
$ret = $data[$field];
|
1074 |
+
} else {
|
1075 |
+
$ret = $data;
|
1076 |
+
}
|
1077 |
+
return $ret;
|
1078 |
+
}
|
1079 |
+
|
1080 |
+
/**
|
1081 |
+
* Retrieve plugin version
|
1082 |
+
* @uses get_plugin_info()
|
1083 |
+
* @param bool $strip_desc Strip any additional version text
|
1084 |
+
* @return string Plugin version
|
1085 |
+
*/
|
1086 |
+
function get_plugin_version($strip_desc = true) {
|
1087 |
+
static $v = '';
|
1088 |
+
//Retrieve version
|
1089 |
+
if ( empty($v) ) {
|
1090 |
+
$field = 'Version';
|
1091 |
+
$v = $this->get_plugin_info($field);
|
1092 |
+
}
|
1093 |
+
//Format
|
1094 |
+
$ret = $v;
|
1095 |
+
if ( $strip_desc ) {
|
1096 |
+
$ret = explode(' ', $ret, 2);
|
1097 |
+
$ret = $ret[0];
|
1098 |
+
}
|
1099 |
+
//Return
|
1100 |
+
return $ret;
|
1101 |
+
}
|
1102 |
+
|
1103 |
+
/**
|
1104 |
+
* Retrieve plugin textdomain (for localization)
|
1105 |
+
* @return string
|
1106 |
+
*/
|
1107 |
+
function get_plugin_textdomain() {
|
1108 |
+
static $dom = '';
|
1109 |
+
if ( empty($dom) )
|
1110 |
+
$dom = $this->get_plugin_base(true);
|
1111 |
+
return $dom;
|
1112 |
}
|
1113 |
|
1114 |
/**
|
1149 |
|
1150 |
/*-** General **-*/
|
1151 |
|
1152 |
+
/**
|
1153 |
+
* Checks if last parameter sent to a function is an array of options and returns it
|
1154 |
+
* Calling function should use `func_get_args()` and pass the value to this method
|
1155 |
+
* @param array $args Parameters passed to calling function
|
1156 |
+
* @return array Options array (Default: empty array)
|
1157 |
+
*/
|
1158 |
+
function func_get_options($args) {
|
1159 |
+
$r = array();
|
1160 |
+
if ( is_array($args) && !empty($args) ) {
|
1161 |
+
$last = count($args) - 1;
|
1162 |
+
if ( is_array($args[$last]) )
|
1163 |
+
$r = $args[$last];
|
1164 |
+
}
|
1165 |
+
return $r;
|
1166 |
+
}
|
1167 |
+
|
1168 |
/**
|
1169 |
* Checks if a property exists in a class or object
|
1170 |
* (Compatibility method for PHP 4
|
1203 |
}
|
1204 |
}
|
1205 |
|
1206 |
+
/**
|
1207 |
+
* Remap array members based on a
|
1208 |
+
* mapping of source/destination keys
|
1209 |
+
* @param array $properties Associative array of properties
|
1210 |
+
* @param array $map Source/Destination mapping
|
1211 |
+
* > Key: Source member
|
1212 |
+
* > Val: Destination member
|
1213 |
+
* @param bool $overwrite If TRUE, source value will be set in destination regardless of whether member already exists or not
|
1214 |
+
* @return array Remapped properties
|
1215 |
+
*/
|
1216 |
+
function array_remap($arr, $map = array(), $overwrite = false) {
|
1217 |
+
if ( !empty($map) && is_array($map) ) {
|
1218 |
+
//Iterate through mappings
|
1219 |
+
foreach ( $map as $from => $to ) {
|
1220 |
+
if ( !array_key_exists($from, $arr) )
|
1221 |
+
continue;
|
1222 |
+
$move = $overwrite;
|
1223 |
+
//Only remap if parent property doesn't already exist in array
|
1224 |
+
if ( !array_key_exists($to, $arr) )
|
1225 |
+
$move = true;
|
1226 |
+
if ( $move ) {
|
1227 |
+
//Move member value to new key
|
1228 |
+
$arr[$to] = $arr[$from];
|
1229 |
+
//Remove source member
|
1230 |
+
unset($arr[$from]);
|
1231 |
+
}
|
1232 |
+
}
|
1233 |
+
}
|
1234 |
+
//Return remapped properties
|
1235 |
+
return $arr;
|
1236 |
+
}
|
1237 |
+
|
1238 |
+
function array_filter_keys($arr, $keys) {
|
1239 |
+
if ( is_array($arr) && !empty($arr) && is_array($keys) && !empty($keys) ) {
|
1240 |
+
foreach ( $keys as $rem ) {
|
1241 |
+
if ( array_key_exists($rem, $arr) )
|
1242 |
+
unset($arr[$rem]);
|
1243 |
+
}
|
1244 |
+
}
|
1245 |
+
|
1246 |
+
return $arr;
|
1247 |
+
}
|
1248 |
+
|
1249 |
+
/**
|
1250 |
+
* Insert an item into an array at the specified position
|
1251 |
+
* @param mixed $item Item to insert into array
|
1252 |
+
* @param int $pos Index position to insert item into array
|
1253 |
+
* @return array Modified array
|
1254 |
+
*/
|
1255 |
+
function array_insert($array, $item, $pos = null) {
|
1256 |
+
array_splice($array, $pos, 0, $item);
|
1257 |
+
return $array;
|
1258 |
+
}
|
1259 |
+
|
1260 |
/**
|
1261 |
* Merges 1 or more arrays together
|
1262 |
* Methodology
|
1268 |
* - Merge item in base array with current item based on key name
|
1269 |
* - If the current item's value AND the corresponding item in the base array are BOTH arrays, recursively merge the the arrays
|
1270 |
* - If the current item's value OR the corresponding item in the base array is NOT an array, current item overwrites base item
|
|
|
1271 |
* @param array Variable number of arrays
|
1272 |
* @param array $arr1 Default array
|
1273 |
* @return array Merged array
|
1275 |
function array_merge_recursive_distinct($arr1) {
|
1276 |
//Get all arrays passed to function
|
1277 |
$args = func_get_args();
|
1278 |
+
if ( empty($args) )
|
1279 |
return false;
|
1280 |
+
//Return empty array if first parameter is not an array
|
1281 |
+
if ( !is_array($args[0]) )
|
1282 |
+
return array();
|
1283 |
//Set first array as base array
|
1284 |
$merged = $args[0];
|
1285 |
//Iterate through arrays to merge
|
1286 |
$arg_length = count($args);
|
1287 |
+
for ( $x = 1; $x < $arg_length; $x++ ) {
|
1288 |
//Skip if argument is not an array (only merge arrays)
|
1289 |
+
if ( !is_array($args[$x]) )
|
1290 |
continue;
|
1291 |
//Iterate through argument items
|
1292 |
+
foreach ( $args[$x] as $key => $val ) {
|
1293 |
+
//Generate key for numeric indexes
|
1294 |
+
if ( is_int($key) ) {
|
1295 |
+
//Add new item to merged array
|
1296 |
+
$merged[] = null;
|
1297 |
+
//Get key of new item
|
1298 |
+
$key = array_pop(array_keys($merged));
|
1299 |
+
}
|
1300 |
+
if ( !isset($merged[$key]) || !is_array($merged[$key]) || !is_array($val) ) {
|
1301 |
+
$merged[$key] = $val;
|
1302 |
+
} elseif ( is_array($merged[$key]) && is_array($val) ) {
|
1303 |
+
$merged[$key] = $this->array_merge_recursive_distinct($merged[$key], $val);
|
1304 |
+
}
|
1305 |
}
|
1306 |
}
|
1307 |
return $merged;
|
1356 |
return $item;
|
1357 |
}
|
1358 |
|
1359 |
+
/**
|
1360 |
+
* Build formatted string based on array values
|
1361 |
+
* Array values in formatted string will be ordered by index order
|
1362 |
+
* @param array $attribute Values to build string with
|
1363 |
+
* @param string $format (optional) Format name (Default: Multidimensional array representation > ['value1']['value2']['value3'], etc.)
|
1364 |
+
* @return string Formatted string based on array values
|
1365 |
+
*/
|
1366 |
function get_array_path($attribute = '', $format = null) {
|
1367 |
//Formatted value
|
1368 |
$fmtd = '';
|
1428 |
return $path;
|
1429 |
}
|
1430 |
|
1431 |
+
/**
|
1432 |
+
* Parse string of attributes into array
|
1433 |
+
* For XML/XHTML tag attributes
|
1434 |
+
* @param string $txt Attribute text (Can be full tag or just attributes)
|
1435 |
+
* @return array Attributes as associative array
|
1436 |
+
*/
|
1437 |
+
function parse_attribute_string($txt, $defaults = array()) {
|
1438 |
+
$txt = trim($txt, ' >');
|
1439 |
+
$matches = $attr = array();
|
1440 |
+
//Strip tag
|
1441 |
+
if ( $txt[0] == '<' && ($s = strpos($txt, ' ')) && $s !== false ) {
|
1442 |
+
$txt = trim(substr($txt, $s + 1));
|
1443 |
+
}
|
1444 |
+
//Parse attributes
|
1445 |
+
$rgx = "/\b(\w+.*?)=([\"'])(.*?)\\2(?:\s|$)/i";
|
1446 |
+
preg_match_all($rgx, $txt, $matches);
|
1447 |
+
if ( count($matches) > 3 ) {
|
1448 |
+
foreach ( $matches[1] as $sub_idx => $val ) {
|
1449 |
+
if ( isset($matches[3][$sub_idx]) )
|
1450 |
+
$attr[trim($val)] = trim($matches[3][$sub_idx]);
|
1451 |
+
}
|
1452 |
+
}
|
1453 |
+
//Destroy parsing vars
|
1454 |
+
unset($txt, $matches);
|
1455 |
+
|
1456 |
+
return array_merge($defaults, $attr);
|
1457 |
+
}
|
1458 |
+
|
1459 |
/**
|
1460 |
* Builds attribute string for HTML element
|
1461 |
* @param array $attr Attributes
|
1476 |
return $ret;
|
1477 |
}
|
1478 |
|
1479 |
+
function build_html_link($uri, $content, $attributes = array()) {
|
1480 |
+
$attributes = array_merge(array('href' => $uri, 'title' => $content), $attributes);
|
1481 |
+
return $this->build_html_element(array('tag' => 'a', 'wrap' => true, 'content' => $content, 'attributes' => $attributes));
|
1482 |
+
}
|
1483 |
+
|
1484 |
/**
|
1485 |
* Generate external stylesheet element
|
1486 |
* @param $url Stylesheet URL
|
1491 |
return $this->build_html_element(array('tag' => 'link', 'wrap' => false, 'attributes' => $attributes));
|
1492 |
}
|
1493 |
|
1494 |
+
function build_script_element($content = '', $id = '', $wrap_jquery = true, $wait_doc_ready = false) {
|
1495 |
+
//Stop processing invalid content
|
1496 |
+
if ( empty($content) || !is_string($content) )
|
1497 |
+
return '';
|
1498 |
+
$attributes = array('type' => 'text/javascript');
|
1499 |
+
$start = array('/* <![CDATA[ */');
|
1500 |
+
$end = array('/* ]]> */');
|
1501 |
+
if ( $wrap_jquery ) {
|
1502 |
+
$start[] = '(function($){';
|
1503 |
+
$end[] = '})(jQuery);';
|
1504 |
+
|
1505 |
+
//Add event handler (if necessary)
|
1506 |
+
if ( $wait_doc_ready ) {
|
1507 |
+
$start[] = '$(document).ready(function(){';
|
1508 |
+
$end[] = '})';
|
1509 |
+
}
|
1510 |
+
}
|
1511 |
+
|
1512 |
+
//Reverse order of end values
|
1513 |
+
$end = array_reverse($end);
|
1514 |
+
$content = implode('', array_merge($start, array($content), $end));
|
1515 |
+
if ( is_string($id) && !empty($id) ) {
|
1516 |
+
$attributes['id'] = $this->add_prefix($id);
|
1517 |
+
}
|
1518 |
+
return $this->build_html_element(array('tag' => 'script', 'content' => $content, 'attributes' => $attributes)) . PHP_EOL;
|
1519 |
+
}
|
1520 |
+
|
1521 |
/**
|
1522 |
* Generate external script element
|
1523 |
* @param $url Script URL
|
1590 |
//Get last submenu added
|
1591 |
$parent = $this->get_submenu_parent_file($parent);
|
1592 |
if ( isset($submenu[$parent]) ) {
|
1593 |
+
$subs =& $submenu[$parent];
|
1594 |
+
|
1595 |
+
//Make sure menu isn't already in the desired position
|
1596 |
+
if ( $pos <= ( count($subs) - 1 ) ) {
|
1597 |
+
//Get submenu that was just added
|
1598 |
+
$sub = array_pop($subs);
|
1599 |
+
//Insert into desired position
|
1600 |
+
if ( 0 == $pos ) {
|
1601 |
+
array_unshift($subs, $sub);
|
1602 |
+
} else {
|
1603 |
+
$top = array_slice($subs, 0, $pos);
|
1604 |
+
$bottom = array_slice($subs, $pos);
|
1605 |
+
array_push($top, $sub);
|
1606 |
+
$subs = array_merge($top, $bottom);
|
1607 |
}
|
1608 |
}
|
1609 |
}
|
1610 |
+
}
|
1611 |
|
1612 |
return $hookname;
|
1613 |
}
|
js/dev/effects.js
DELETED
@@ -1,1094 +0,0 @@
|
|
1 |
-
// script.aculo.us effects.js v1.7.1_beta3, Fri May 25 17:19:41 +0200 2007
|
2 |
-
|
3 |
-
// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
|
4 |
-
// Contributors:
|
5 |
-
// Justin Palmer (http://encytemedia.com/)
|
6 |
-
// Mark Pilgrim (http://diveintomark.org/)
|
7 |
-
// Martin Bialasinki
|
8 |
-
//
|
9 |
-
// script.aculo.us is freely distributable under the terms of an MIT-style license.
|
10 |
-
// For details, see the script.aculo.us web site: http://script.aculo.us/
|
11 |
-
|
12 |
-
// converts rgb() and #xxx to #xxxxxx format,
|
13 |
-
// returns self (or first argument) if not convertable
|
14 |
-
String.prototype.parseColor = function() {
|
15 |
-
var color = '#';
|
16 |
-
if(this.slice(0,4) == 'rgb(') {
|
17 |
-
var cols = this.slice(4,this.length-1).split(',');
|
18 |
-
var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
|
19 |
-
} else {
|
20 |
-
if(this.slice(0,1) == '#') {
|
21 |
-
if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();
|
22 |
-
if(this.length==7) color = this.toLowerCase();
|
23 |
-
}
|
24 |
-
}
|
25 |
-
return(color.length==7 ? color : (arguments[0] || this));
|
26 |
-
}
|
27 |
-
|
28 |
-
/*--------------------------------------------------------------------------*/
|
29 |
-
|
30 |
-
Element.collectTextNodes = function(element) {
|
31 |
-
return $A($(element).childNodes).collect( function(node) {
|
32 |
-
return (node.nodeType==3 ? node.nodeValue :
|
33 |
-
(node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
|
34 |
-
}).flatten().join('');
|
35 |
-
}
|
36 |
-
|
37 |
-
Element.collectTextNodesIgnoreClass = function(element, className) {
|
38 |
-
return $A($(element).childNodes).collect( function(node) {
|
39 |
-
return (node.nodeType==3 ? node.nodeValue :
|
40 |
-
((node.hasChildNodes() && !Element.hasClassName(node,className)) ?
|
41 |
-
Element.collectTextNodesIgnoreClass(node, className) : ''));
|
42 |
-
}).flatten().join('');
|
43 |
-
}
|
44 |
-
|
45 |
-
Element.setContentZoom = function(element, percent) {
|
46 |
-
element = $(element);
|
47 |
-
element.setStyle({fontSize: (percent/100) + 'em'});
|
48 |
-
if(Prototype.Browser.WebKit) window.scrollBy(0,0);
|
49 |
-
return element;
|
50 |
-
}
|
51 |
-
|
52 |
-
Element.getInlineOpacity = function(element){
|
53 |
-
return $(element).style.opacity || '';
|
54 |
-
}
|
55 |
-
|
56 |
-
Element.forceRerendering = function(element) {
|
57 |
-
try {
|
58 |
-
element = $(element);
|
59 |
-
var n = document.createTextNode(' ');
|
60 |
-
element.appendChild(n);
|
61 |
-
element.removeChild(n);
|
62 |
-
} catch(e) { }
|
63 |
-
};
|
64 |
-
|
65 |
-
/*--------------------------------------------------------------------------*/
|
66 |
-
|
67 |
-
Array.prototype.call = function() {
|
68 |
-
var args = arguments;
|
69 |
-
this.each(function(f){ f.apply(this, args) });
|
70 |
-
}
|
71 |
-
|
72 |
-
/*--------------------------------------------------------------------------*/
|
73 |
-
|
74 |
-
var Effect = {
|
75 |
-
_elementDoesNotExistError: {
|
76 |
-
name: 'ElementDoesNotExistError',
|
77 |
-
message: 'The specified DOM element does not exist, but is required for this effect to operate'
|
78 |
-
},
|
79 |
-
tagifyText: function(element) {
|
80 |
-
if(typeof Builder == 'undefined')
|
81 |
-
throw("Effect.tagifyText requires including script.aculo.us' builder.js library");
|
82 |
-
|
83 |
-
var tagifyStyle = 'position:relative';
|
84 |
-
if(Prototype.Browser.IE) tagifyStyle += ';zoom:1';
|
85 |
-
|
86 |
-
element = $(element);
|
87 |
-
$A(element.childNodes).each( function(child) {
|
88 |
-
if(child.nodeType==3) {
|
89 |
-
child.nodeValue.toArray().each( function(character) {
|
90 |
-
element.insertBefore(
|
91 |
-
Builder.node('span',{style: tagifyStyle},
|
92 |
-
character == ' ' ? String.fromCharCode(160) : character),
|
93 |
-
child);
|
94 |
-
});
|
95 |
-
Element.remove(child);
|
96 |
-
}
|
97 |
-
});
|
98 |
-
},
|
99 |
-
multiple: function(element, effect) {
|
100 |
-
var elements;
|
101 |
-
if(((typeof element == 'object') ||
|
102 |
-
(typeof element == 'function')) &&
|
103 |
-
(element.length))
|
104 |
-
elements = element;
|
105 |
-
else
|
106 |
-
elements = $(element).childNodes;
|
107 |
-
|
108 |
-
var options = Object.extend({
|
109 |
-
speed: 0.1,
|
110 |
-
delay: 0.0
|
111 |
-
}, arguments[2] || {});
|
112 |
-
var masterDelay = options.delay;
|
113 |
-
|
114 |
-
$A(elements).each( function(element, index) {
|
115 |
-
new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
|
116 |
-
});
|
117 |
-
},
|
118 |
-
PAIRS: {
|
119 |
-
'slide': ['SlideDown','SlideUp'],
|
120 |
-
'blind': ['BlindDown','BlindUp'],
|
121 |
-
'appear': ['Appear','Fade']
|
122 |
-
},
|
123 |
-
toggle: function(element, effect) {
|
124 |
-
element = $(element);
|
125 |
-
effect = (effect || 'appear').toLowerCase();
|
126 |
-
var options = Object.extend({
|
127 |
-
queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
|
128 |
-
}, arguments[2] || {});
|
129 |
-
Effect[element.visible() ?
|
130 |
-
Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
|
131 |
-
}
|
132 |
-
};
|
133 |
-
|
134 |
-
var Effect2 = Effect; // deprecated
|
135 |
-
|
136 |
-
/* ------------- transitions ------------- */
|
137 |
-
|
138 |
-
Effect.Transitions = {
|
139 |
-
linear: Prototype.K,
|
140 |
-
sinoidal: function(pos) {
|
141 |
-
return (-Math.cos(pos*Math.PI)/2) + 0.5;
|
142 |
-
},
|
143 |
-
reverse: function(pos) {
|
144 |
-
return 1-pos;
|
145 |
-
},
|
146 |
-
flicker: function(pos) {
|
147 |
-
var pos = ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
|
148 |
-
return (pos > 1 ? 1 : pos);
|
149 |
-
},
|
150 |
-
wobble: function(pos) {
|
151 |
-
return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
|
152 |
-
},
|
153 |
-
pulse: function(pos, pulses) {
|
154 |
-
pulses = pulses || 5;
|
155 |
-
return (
|
156 |
-
Math.round((pos % (1/pulses)) * pulses) == 0 ?
|
157 |
-
((pos * pulses * 2) - Math.floor(pos * pulses * 2)) :
|
158 |
-
1 - ((pos * pulses * 2) - Math.floor(pos * pulses * 2))
|
159 |
-
);
|
160 |
-
},
|
161 |
-
none: function(pos) {
|
162 |
-
return 0;
|
163 |
-
},
|
164 |
-
full: function(pos) {
|
165 |
-
return 1;
|
166 |
-
}
|
167 |
-
};
|
168 |
-
|
169 |
-
/* ------------- core effects ------------- */
|
170 |
-
|
171 |
-
Effect.ScopedQueue = Class.create();
|
172 |
-
Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {
|
173 |
-
initialize: function() {
|
174 |
-
this.effects = [];
|
175 |
-
this.interval = null;
|
176 |
-
},
|
177 |
-
_each: function(iterator) {
|
178 |
-
this.effects._each(iterator);
|
179 |
-
},
|
180 |
-
add: function(effect) {
|
181 |
-
var timestamp = new Date().getTime();
|
182 |
-
|
183 |
-
var position = (typeof effect.options.queue == 'string') ?
|
184 |
-
effect.options.queue : effect.options.queue.position;
|
185 |
-
|
186 |
-
switch(position) {
|
187 |
-
case 'front':
|
188 |
-
// move unstarted effects after this effect
|
189 |
-
this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
|
190 |
-
e.startOn += effect.finishOn;
|
191 |
-
e.finishOn += effect.finishOn;
|
192 |
-
});
|
193 |
-
break;
|
194 |
-
case 'with-last':
|
195 |
-
timestamp = this.effects.pluck('startOn').max() || timestamp;
|
196 |
-
break;
|
197 |
-
case 'end':
|
198 |
-
// start effect after last queued effect has finished
|
199 |
-
timestamp = this.effects.pluck('finishOn').max() || timestamp;
|
200 |
-
break;
|
201 |
-
}
|
202 |
-
|
203 |
-
effect.startOn += timestamp;
|
204 |
-
effect.finishOn += timestamp;
|
205 |
-
|
206 |
-
if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
|
207 |
-
this.effects.push(effect);
|
208 |
-
|
209 |
-
if(!this.interval)
|
210 |
-
this.interval = setInterval(this.loop.bind(this), 15);
|
211 |
-
},
|
212 |
-
remove: function(effect) {
|
213 |
-
this.effects = this.effects.reject(function(e) { return e==effect });
|
214 |
-
if(this.effects.length == 0) {
|
215 |
-
clearInterval(this.interval);
|
216 |
-
this.interval = null;
|
217 |
-
}
|
218 |
-
},
|
219 |
-
loop: function() {
|
220 |
-
var timePos = new Date().getTime();
|
221 |
-
for(var i=0, len=this.effects.length;i<len;i++)
|
222 |
-
this.effects[i] && this.effects[i].loop(timePos);
|
223 |
-
}
|
224 |
-
});
|
225 |
-
|
226 |
-
Effect.Queues = {
|
227 |
-
instances: $H(),
|
228 |
-
get: function(queueName) {
|
229 |
-
if(typeof queueName != 'string') return queueName;
|
230 |
-
|
231 |
-
if(!this.instances[queueName])
|
232 |
-
this.instances[queueName] = new Effect.ScopedQueue();
|
233 |
-
|
234 |
-
return this.instances[queueName];
|
235 |
-
}
|
236 |
-
}
|
237 |
-
Effect.Queue = Effect.Queues.get('global');
|
238 |
-
|
239 |
-
Effect.DefaultOptions = {
|
240 |
-
transition: Effect.Transitions.sinoidal,
|
241 |
-
duration: 1.0, // seconds
|
242 |
-
fps: 100, // 100= assume 66fps max.
|
243 |
-
sync: false, // true for combining
|
244 |
-
from: 0.0,
|
245 |
-
to: 1.0,
|
246 |
-
delay: 0.0,
|
247 |
-
queue: 'parallel'
|
248 |
-
}
|
249 |
-
|
250 |
-
Effect.Base = function() {};
|
251 |
-
Effect.Base.prototype = {
|
252 |
-
position: null,
|
253 |
-
start: function(options) {
|
254 |
-
function codeForEvent(options,eventName){
|
255 |
-
return (
|
256 |
-
(options[eventName+'Internal'] ? 'this.options.'+eventName+'Internal(this);' : '') +
|
257 |
-
(options[eventName] ? 'this.options.'+eventName+'(this);' : '')
|
258 |
-
);
|
259 |
-
}
|
260 |
-
if(options.transition === false) options.transition = Effect.Transitions.linear;
|
261 |
-
this.options = Object.extend(Object.extend({},Effect.DefaultOptions), options || {});
|
262 |
-
this.currentFrame = 0;
|
263 |
-
this.state = 'idle';
|
264 |
-
this.startOn = this.options.delay*1000;
|
265 |
-
this.finishOn = this.startOn+(this.options.duration*1000);
|
266 |
-
this.fromToDelta = this.options.to-this.options.from;
|
267 |
-
this.totalTime = this.finishOn-this.startOn;
|
268 |
-
this.totalFrames = this.options.fps*this.options.duration;
|
269 |
-
|
270 |
-
eval('this.render = function(pos){ '+
|
271 |
-
'if(this.state=="idle"){this.state="running";'+
|
272 |
-
codeForEvent(options,'beforeSetup')+
|
273 |
-
(this.setup ? 'this.setup();':'')+
|
274 |
-
codeForEvent(options,'afterSetup')+
|
275 |
-
'};if(this.state=="running"){'+
|
276 |
-
'pos=this.options.transition(pos)*'+this.fromToDelta+'+'+this.options.from+';'+
|
277 |
-
'this.position=pos;'+
|
278 |
-
codeForEvent(options,'beforeUpdate')+
|
279 |
-
(this.update ? 'this.update(pos);':'')+
|
280 |
-
codeForEvent(options,'afterUpdate')+
|
281 |
-
'}}');
|
282 |
-
|
283 |
-
this.event('beforeStart');
|
284 |
-
if(!this.options.sync)
|
285 |
-
Effect.Queues.get(typeof this.options.queue == 'string' ?
|
286 |
-
'global' : this.options.queue.scope).add(this);
|
287 |
-
},
|
288 |
-
loop: function(timePos) {
|
289 |
-
if(timePos >= this.startOn) {
|
290 |
-
if(timePos >= this.finishOn) {
|
291 |
-
this.render(1.0);
|
292 |
-
this.cancel();
|
293 |
-
this.event('beforeFinish');
|
294 |
-
if(this.finish) this.finish();
|
295 |
-
this.event('afterFinish');
|
296 |
-
return;
|
297 |
-
}
|
298 |
-
var pos = (timePos - this.startOn) / this.totalTime,
|
299 |
-
frame = Math.round(pos * this.totalFrames);
|
300 |
-
if(frame > this.currentFrame) {
|
301 |
-
this.render(pos);
|
302 |
-
this.currentFrame = frame;
|
303 |
-
}
|
304 |
-
}
|
305 |
-
},
|
306 |
-
cancel: function() {
|
307 |
-
if(!this.options.sync)
|
308 |
-
Effect.Queues.get(typeof this.options.queue == 'string' ?
|
309 |
-
'global' : this.options.queue.scope).remove(this);
|
310 |
-
this.state = 'finished';
|
311 |
-
},
|
312 |
-
event: function(eventName) {
|
313 |
-
if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
|
314 |
-
if(this.options[eventName]) this.options[eventName](this);
|
315 |
-
},
|
316 |
-
inspect: function() {
|
317 |
-
var data = $H();
|
318 |
-
for(property in this)
|
319 |
-
if(typeof this[property] != 'function') data[property] = this[property];
|
320 |
-
return '#<Effect:' + data.inspect() + ',options:' + $H(this.options).inspect() + '>';
|
321 |
-
}
|
322 |
-
}
|
323 |
-
|
324 |
-
Effect.Parallel = Class.create();
|
325 |
-
Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), {
|
326 |
-
initialize: function(effects) {
|
327 |
-
this.effects = effects || [];
|
328 |
-
this.start(arguments[1]);
|
329 |
-
},
|
330 |
-
update: function(position) {
|
331 |
-
this.effects.invoke('render', position);
|
332 |
-
},
|
333 |
-
finish: function(position) {
|
334 |
-
this.effects.each( function(effect) {
|
335 |
-
effect.render(1.0);
|
336 |
-
effect.cancel();
|
337 |
-
effect.event('beforeFinish');
|
338 |
-
if(effect.finish) effect.finish(position);
|
339 |
-
effect.event('afterFinish');
|
340 |
-
});
|
341 |
-
}
|
342 |
-
});
|
343 |
-
|
344 |
-
Effect.Event = Class.create();
|
345 |
-
Object.extend(Object.extend(Effect.Event.prototype, Effect.Base.prototype), {
|
346 |
-
initialize: function() {
|
347 |
-
var options = Object.extend({
|
348 |
-
duration: 0
|
349 |
-
}, arguments[0] || {});
|
350 |
-
this.start(options);
|
351 |
-
},
|
352 |
-
update: Prototype.emptyFunction
|
353 |
-
});
|
354 |
-
|
355 |
-
Effect.Opacity = Class.create();
|
356 |
-
Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
|
357 |
-
initialize: function(element) {
|
358 |
-
this.element = $(element);
|
359 |
-
if(!this.element) throw(Effect._elementDoesNotExistError);
|
360 |
-
// make this work on IE on elements without 'layout'
|
361 |
-
if(Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
|
362 |
-
this.element.setStyle({zoom: 1});
|
363 |
-
var options = Object.extend({
|
364 |
-
from: this.element.getOpacity() || 0.0,
|
365 |
-
to: 1.0
|
366 |
-
}, arguments[1] || {});
|
367 |
-
this.start(options);
|
368 |
-
},
|
369 |
-
update: function(position) {
|
370 |
-
this.element.setOpacity(position);
|
371 |
-
}
|
372 |
-
});
|
373 |
-
|
374 |
-
Effect.Move = Class.create();
|
375 |
-
Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), {
|
376 |
-
initialize: function(element) {
|
377 |
-
this.element = $(element);
|
378 |
-
if(!this.element) throw(Effect._elementDoesNotExistError);
|
379 |
-
var options = Object.extend({
|
380 |
-
x: 0,
|
381 |
-
y: 0,
|
382 |
-
mode: 'relative'
|
383 |
-
}, arguments[1] || {});
|
384 |
-
this.start(options);
|
385 |
-
},
|
386 |
-
setup: function() {
|
387 |
-
// Bug in Opera: Opera returns the "real" position of a static element or
|
388 |
-
// relative element that does not have top/left explicitly set.
|
389 |
-
// ==> Always set top and left for position relative elements in your stylesheets
|
390 |
-
// (to 0 if you do not need them)
|
391 |
-
this.element.makePositioned();
|
392 |
-
this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
|
393 |
-
this.originalTop = parseFloat(this.element.getStyle('top') || '0');
|
394 |
-
if(this.options.mode == 'absolute') {
|
395 |
-
// absolute movement, so we need to calc deltaX and deltaY
|
396 |
-
this.options.x = this.options.x - this.originalLeft;
|
397 |
-
this.options.y = this.options.y - this.originalTop;
|
398 |
-
}
|
399 |
-
},
|
400 |
-
update: function(position) {
|
401 |
-
this.element.setStyle({
|
402 |
-
left: Math.round(this.options.x * position + this.originalLeft) + 'px',
|
403 |
-
top: Math.round(this.options.y * position + this.originalTop) + 'px'
|
404 |
-
});
|
405 |
-
}
|
406 |
-
});
|
407 |
-
|
408 |
-
// for backwards compatibility
|
409 |
-
Effect.MoveBy = function(element, toTop, toLeft) {
|
410 |
-
return new Effect.Move(element,
|
411 |
-
Object.extend({ x: toLeft, y: toTop }, arguments[3] || {}));
|
412 |
-
};
|
413 |
-
|
414 |
-
Effect.Scale = Class.create();
|
415 |
-
Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
|
416 |
-
initialize: function(element, percent) {
|
417 |
-
this.element = $(element);
|
418 |
-
if(!this.element) throw(Effect._elementDoesNotExistError);
|
419 |
-
var options = Object.extend({
|
420 |
-
scaleX: true,
|
421 |
-
scaleY: true,
|
422 |
-
scaleContent: true,
|
423 |
-
scaleFromCenter: false,
|
424 |
-
scaleMode: 'box', // 'box' or 'contents' or {} with provided values
|
425 |
-
scaleFrom: 100.0,
|
426 |
-
scaleTo: percent
|
427 |
-
}, arguments[2] || {});
|
428 |
-
this.start(options);
|
429 |
-
},
|
430 |
-
setup: function() {
|
431 |
-
this.restoreAfterFinish = this.options.restoreAfterFinish || false;
|
432 |
-
this.elementPositioning = this.element.getStyle('position');
|
433 |
-
|
434 |
-
this.originalStyle = {};
|
435 |
-
['top','left','width','height','fontSize'].each( function(k) {
|
436 |
-
this.originalStyle[k] = this.element.style[k];
|
437 |
-
}.bind(this));
|
438 |
-
|
439 |
-
this.originalTop = this.element.offsetTop;
|
440 |
-
this.originalLeft = this.element.offsetLeft;
|
441 |
-
|
442 |
-
var fontSize = this.element.getStyle('font-size') || '100%';
|
443 |
-
['em','px','%','pt'].each( function(fontSizeType) {
|
444 |
-
if(fontSize.indexOf(fontSizeType)>0) {
|
445 |
-
this.fontSize = parseFloat(fontSize);
|
446 |
-
this.fontSizeType = fontSizeType;
|
447 |
-
}
|
448 |
-
}.bind(this));
|
449 |
-
|
450 |
-
this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
|
451 |
-
|
452 |
-
this.dims = null;
|
453 |
-
if(this.options.scaleMode=='box')
|
454 |
-
this.dims = [this.element.offsetHeight, this.element.offsetWidth];
|
455 |
-
if(/^content/.test(this.options.scaleMode))
|
456 |
-
this.dims = [this.element.scrollHeight, this.element.scrollWidth];
|
457 |
-
if(!this.dims)
|
458 |
-
this.dims = [this.options.scaleMode.originalHeight,
|
459 |
-
this.options.scaleMode.originalWidth];
|
460 |
-
},
|
461 |
-
update: function(position) {
|
462 |
-
var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
|
463 |
-
if(this.options.scaleContent && this.fontSize)
|
464 |
-
this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
|
465 |
-
this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
|
466 |
-
},
|
467 |
-
finish: function(position) {
|
468 |
-
if(this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
|
469 |
-
},
|
470 |
-
setDimensions: function(height, width) {
|
471 |
-
var d = {};
|
472 |
-
if(this.options.scaleX) d.width = Math.round(width) + 'px';
|
473 |
-
if(this.options.scaleY) d.height = Math.round(height) + 'px';
|
474 |
-
if(this.options.scaleFromCenter) {
|
475 |
-
var topd = (height - this.dims[0])/2;
|
476 |
-
var leftd = (width - this.dims[1])/2;
|
477 |
-
if(this.elementPositioning == 'absolute') {
|
478 |
-
if(this.options.scaleY) d.top = this.originalTop-topd + 'px';
|
479 |
-
if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
|
480 |
-
} else {
|
481 |
-
if(this.options.scaleY) d.top = -topd + 'px';
|
482 |
-
if(this.options.scaleX) d.left = -leftd + 'px';
|
483 |
-
}
|
484 |
-
}
|
485 |
-
this.element.setStyle(d);
|
486 |
-
}
|
487 |
-
});
|
488 |
-
|
489 |
-
Effect.Highlight = Class.create();
|
490 |
-
Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), {
|
491 |
-
initialize: function(element) {
|
492 |
-
this.element = $(element);
|
493 |
-
if(!this.element) throw(Effect._elementDoesNotExistError);
|
494 |
-
var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {});
|
495 |
-
this.start(options);
|
496 |
-
},
|
497 |
-
setup: function() {
|
498 |
-
// Prevent executing on elements not in the layout flow
|
499 |
-
if(this.element.getStyle('display')=='none') { this.cancel(); return; }
|
500 |
-
// Disable background image during the effect
|
501 |
-
this.oldStyle = {};
|
502 |
-
if (!this.options.keepBackgroundImage) {
|
503 |
-
this.oldStyle.backgroundImage = this.element.getStyle('background-image');
|
504 |
-
this.element.setStyle({backgroundImage: 'none'});
|
505 |
-
}
|
506 |
-
if(!this.options.endcolor)
|
507 |
-
this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');
|
508 |
-
if(!this.options.restorecolor)
|
509 |
-
this.options.restorecolor = this.element.getStyle('background-color');
|
510 |
-
// init color calculations
|
511 |
-
this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
|
512 |
-
this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this));
|
513 |
-
},
|
514 |
-
update: function(position) {
|
515 |
-
this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){
|
516 |
-
return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) });
|
517 |
-
},
|
518 |
-
finish: function() {
|
519 |
-
this.element.setStyle(Object.extend(this.oldStyle, {
|
520 |
-
backgroundColor: this.options.restorecolor
|
521 |
-
}));
|
522 |
-
}
|
523 |
-
});
|
524 |
-
|
525 |
-
Effect.ScrollTo = Class.create();
|
526 |
-
Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), {
|
527 |
-
initialize: function(element) {
|
528 |
-
this.element = $(element);
|
529 |
-
this.start(arguments[1] || {});
|
530 |
-
},
|
531 |
-
setup: function() {
|
532 |
-
Position.prepare();
|
533 |
-
var offsets = Position.cumulativeOffset(this.element);
|
534 |
-
if(this.options.offset) offsets[1] += this.options.offset;
|
535 |
-
var max = window.innerHeight ?
|
536 |
-
window.height - window.innerHeight :
|
537 |
-
document.body.scrollHeight -
|
538 |
-
(document.documentElement.clientHeight ?
|
539 |
-
document.documentElement.clientHeight : document.body.clientHeight);
|
540 |
-
this.scrollStart = Position.deltaY;
|
541 |
-
this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart;
|
542 |
-
},
|
543 |
-
update: function(position) {
|
544 |
-
Position.prepare();
|
545 |
-
window.scrollTo(Position.deltaX,
|
546 |
-
this.scrollStart + (position*this.delta));
|
547 |
-
}
|
548 |
-
});
|
549 |
-
|
550 |
-
/* ------------- combination effects ------------- */
|
551 |
-
|
552 |
-
Effect.Fade = function(element) {
|
553 |
-
element = $(element);
|
554 |
-
var oldOpacity = element.getInlineOpacity();
|
555 |
-
var options = Object.extend({
|
556 |
-
from: element.getOpacity() || 1.0,
|
557 |
-
to: 0.0,
|
558 |
-
afterFinishInternal: function(effect) {
|
559 |
-
if(effect.options.to!=0) return;
|
560 |
-
effect.element.hide().setStyle({opacity: oldOpacity});
|
561 |
-
}}, arguments[1] || {});
|
562 |
-
return new Effect.Opacity(element,options);
|
563 |
-
}
|
564 |
-
|
565 |
-
Effect.Appear = function(element) {
|
566 |
-
element = $(element);
|
567 |
-
var options = Object.extend({
|
568 |
-
from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0),
|
569 |
-
to: 1.0,
|
570 |
-
// force Safari to render floated elements properly
|
571 |
-
afterFinishInternal: function(effect) {
|
572 |
-
effect.element.forceRerendering();
|
573 |
-
},
|
574 |
-
beforeSetup: function(effect) {
|
575 |
-
effect.element.setOpacity(effect.options.from).show();
|
576 |
-
}}, arguments[1] || {});
|
577 |
-
return new Effect.Opacity(element,options);
|
578 |
-
}
|
579 |
-
|
580 |
-
Effect.Puff = function(element) {
|
581 |
-
element = $(element);
|
582 |
-
var oldStyle = {
|
583 |
-
opacity: element.getInlineOpacity(),
|
584 |
-
position: element.getStyle('position'),
|
585 |
-
top: element.style.top,
|
586 |
-
left: element.style.left,
|
587 |
-
width: element.style.width,
|
588 |
-
height: element.style.height
|
589 |
-
};
|
590 |
-
return new Effect.Parallel(
|
591 |
-
[ new Effect.Scale(element, 200,
|
592 |
-
{ sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }),
|
593 |
-
new Effect.Opacity(element, { sync: true, to: 0.0 } ) ],
|
594 |
-
Object.extend({ duration: 1.0,
|
595 |
-
beforeSetupInternal: function(effect) {
|
596 |
-
Position.absolutize(effect.effects[0].element)
|
597 |
-
},
|
598 |
-
afterFinishInternal: function(effect) {
|
599 |
-
effect.effects[0].element.hide().setStyle(oldStyle); }
|
600 |
-
}, arguments[1] || {})
|
601 |
-
);
|
602 |
-
}
|
603 |
-
|
604 |
-
Effect.BlindUp = function(element) {
|
605 |
-
element = $(element);
|
606 |
-
element.makeClipping();
|
607 |
-
return new Effect.Scale(element, 0,
|
608 |
-
Object.extend({ scaleContent: false,
|
609 |
-
scaleX: false,
|
610 |
-
restoreAfterFinish: true,
|
611 |
-
afterFinishInternal: function(effect) {
|
612 |
-
effect.element.hide().undoClipping();
|
613 |
-
}
|
614 |
-
}, arguments[1] || {})
|
615 |
-
);
|
616 |
-
}
|
617 |
-
|
618 |
-
Effect.BlindDown = function(element) {
|
619 |
-
element = $(element);
|
620 |
-
var elementDimensions = element.getDimensions();
|
621 |
-
return new Effect.Scale(element, 100, Object.extend({
|
622 |
-
scaleContent: false,
|
623 |
-
scaleX: false,
|
624 |
-
scaleFrom: 0,
|
625 |
-
scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
|
626 |
-
restoreAfterFinish: true,
|
627 |
-
afterSetup: function(effect) {
|
628 |
-
effect.element.makeClipping().setStyle({height: '0px'}).show();
|
629 |
-
},
|
630 |
-
afterFinishInternal: function(effect) {
|
631 |
-
effect.element.undoClipping();
|
632 |
-
}
|
633 |
-
}, arguments[1] || {}));
|
634 |
-
}
|
635 |
-
|
636 |
-
Effect.SwitchOff = function(element) {
|
637 |
-
element = $(element);
|
638 |
-
var oldOpacity = element.getInlineOpacity();
|
639 |
-
return new Effect.Appear(element, Object.extend({
|
640 |
-
duration: 0.4,
|
641 |
-
from: 0,
|
642 |
-
transition: Effect.Transitions.flicker,
|
643 |
-
afterFinishInternal: function(effect) {
|
644 |
-
new Effect.Scale(effect.element, 1, {
|
645 |
-
duration: 0.3, scaleFromCenter: true,
|
646 |
-
scaleX: false, scaleContent: false, restoreAfterFinish: true,
|
647 |
-
beforeSetup: function(effect) {
|
648 |
-
effect.element.makePositioned().makeClipping();
|
649 |
-
},
|
650 |
-
afterFinishInternal: function(effect) {
|
651 |
-
effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});
|
652 |
-
}
|
653 |
-
})
|
654 |
-
}
|
655 |
-
}, arguments[1] || {}));
|
656 |
-
}
|
657 |
-
|
658 |
-
Effect.DropOut = function(element) {
|
659 |
-
element = $(element);
|
660 |
-
var oldStyle = {
|
661 |
-
top: element.getStyle('top'),
|
662 |
-
left: element.getStyle('left'),
|
663 |
-
opacity: element.getInlineOpacity() };
|
664 |
-
return new Effect.Parallel(
|
665 |
-
[ new Effect.Move(element, {x: 0, y: 100, sync: true }),
|
666 |
-
new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
|
667 |
-
Object.extend(
|
668 |
-
{ duration: 0.5,
|
669 |
-
beforeSetup: function(effect) {
|
670 |
-
effect.effects[0].element.makePositioned();
|
671 |
-
},
|
672 |
-
afterFinishInternal: function(effect) {
|
673 |
-
effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
|
674 |
-
}
|
675 |
-
}, arguments[1] || {}));
|
676 |
-
}
|
677 |
-
|
678 |
-
Effect.Shake = function(element) {
|
679 |
-
element = $(element);
|
680 |
-
var oldStyle = {
|
681 |
-
top: element.getStyle('top'),
|
682 |
-
left: element.getStyle('left') };
|
683 |
-
return new Effect.Move(element,
|
684 |
-
{ x: 20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
|
685 |
-
new Effect.Move(effect.element,
|
686 |
-
{ x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
|
687 |
-
new Effect.Move(effect.element,
|
688 |
-
{ x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
|
689 |
-
new Effect.Move(effect.element,
|
690 |
-
{ x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
|
691 |
-
new Effect.Move(effect.element,
|
692 |
-
{ x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
|
693 |
-
new Effect.Move(effect.element,
|
694 |
-
{ x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
|
695 |
-
effect.element.undoPositioned().setStyle(oldStyle);
|
696 |
-
}}) }}) }}) }}) }}) }});
|
697 |
-
}
|
698 |
-
|
699 |
-
Effect.SlideDown = function(element) {
|
700 |
-
element = $(element).cleanWhitespace();
|
701 |
-
// SlideDown need to have the content of the element wrapped in a container element with fixed height!
|
702 |
-
var oldInnerBottom = element.down().getStyle('bottom');
|
703 |
-
var elementDimensions = element.getDimensions();
|
704 |
-
return new Effect.Scale(element, 100, Object.extend({
|
705 |
-
scaleContent: false,
|
706 |
-
scaleX: false,
|
707 |
-
scaleFrom: window.opera ? 0 : 1,
|
708 |
-
scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
|
709 |
-
restoreAfterFinish: true,
|
710 |
-
afterSetup: function(effect) {
|
711 |
-
effect.element.makePositioned();
|
712 |
-
effect.element.down().makePositioned();
|
713 |
-
if(window.opera) effect.element.setStyle({top: ''});
|
714 |
-
effect.element.makeClipping().setStyle({height: '0px'}).show();
|
715 |
-
},
|
716 |
-
afterUpdateInternal: function(effect) {
|
717 |
-
effect.element.down().setStyle({bottom:
|
718 |
-
(effect.dims[0] - effect.element.clientHeight) + 'px' });
|
719 |
-
},
|
720 |
-
afterFinishInternal: function(effect) {
|
721 |
-
effect.element.undoClipping().undoPositioned();
|
722 |
-
effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
|
723 |
-
}, arguments[1] || {})
|
724 |
-
);
|
725 |
-
}
|
726 |
-
|
727 |
-
Effect.SlideUp = function(element) {
|
728 |
-
element = $(element).cleanWhitespace();
|
729 |
-
var oldInnerBottom = element.down().getStyle('bottom');
|
730 |
-
return new Effect.Scale(element, window.opera ? 0 : 1,
|
731 |
-
Object.extend({ scaleContent: false,
|
732 |
-
scaleX: false,
|
733 |
-
scaleMode: 'box',
|
734 |
-
scaleFrom: 100,
|
735 |
-
restoreAfterFinish: true,
|
736 |
-
beforeStartInternal: function(effect) {
|
737 |
-
effect.element.makePositioned();
|
738 |
-
effect.element.down().makePositioned();
|
739 |
-
if(window.opera) effect.element.setStyle({top: ''});
|
740 |
-
effect.element.makeClipping().show();
|
741 |
-
},
|
742 |
-
afterUpdateInternal: function(effect) {
|
743 |
-
effect.element.down().setStyle({bottom:
|
744 |
-
(effect.dims[0] - effect.element.clientHeight) + 'px' });
|
745 |
-
},
|
746 |
-
afterFinishInternal: function(effect) {
|
747 |
-
effect.element.hide().undoClipping().undoPositioned().setStyle({bottom: oldInnerBottom});
|
748 |
-
effect.element.down().undoPositioned();
|
749 |
-
}
|
750 |
-
}, arguments[1] || {})
|
751 |
-
);
|
752 |
-
}
|
753 |
-
|
754 |
-
// Bug in opera makes the TD containing this element expand for a instance after finish
|
755 |
-
Effect.Squish = function(element) {
|
756 |
-
return new Effect.Scale(element, window.opera ? 1 : 0, {
|
757 |
-
restoreAfterFinish: true,
|
758 |
-
beforeSetup: function(effect) {
|
759 |
-
effect.element.makeClipping();
|
760 |
-
},
|
761 |
-
afterFinishInternal: function(effect) {
|
762 |
-
effect.element.hide().undoClipping();
|
763 |
-
}
|
764 |
-
});
|
765 |
-
}
|
766 |
-
|
767 |
-
Effect.Grow = function(element) {
|
768 |
-
element = $(element);
|
769 |
-
var options = Object.extend({
|
770 |
-
direction: 'center',
|
771 |
-
moveTransition: Effect.Transitions.sinoidal,
|
772 |
-
scaleTransition: Effect.Transitions.sinoidal,
|
773 |
-
opacityTransition: Effect.Transitions.full
|
774 |
-
}, arguments[1] || {});
|
775 |
-
var oldStyle = {
|
776 |
-
top: element.style.top,
|
777 |
-
left: element.style.left,
|
778 |
-
height: element.style.height,
|
779 |
-
width: element.style.width,
|
780 |
-
opacity: element.getInlineOpacity() };
|
781 |
-
|
782 |
-
var dims = element.getDimensions();
|
783 |
-
var initialMoveX, initialMoveY;
|
784 |
-
var moveX, moveY;
|
785 |
-
|
786 |
-
switch (options.direction) {
|
787 |
-
case 'top-left':
|
788 |
-
initialMoveX = initialMoveY = moveX = moveY = 0;
|
789 |
-
break;
|
790 |
-
case 'top-right':
|
791 |
-
initialMoveX = dims.width;
|
792 |
-
initialMoveY = moveY = 0;
|
793 |
-
moveX = -dims.width;
|
794 |
-
break;
|
795 |
-
case 'bottom-left':
|
796 |
-
initialMoveX = moveX = 0;
|
797 |
-
initialMoveY = dims.height;
|
798 |
-
moveY = -dims.height;
|
799 |
-
break;
|
800 |
-
case 'bottom-right':
|
801 |
-
initialMoveX = dims.width;
|
802 |
-
initialMoveY = dims.height;
|
803 |
-
moveX = -dims.width;
|
804 |
-
moveY = -dims.height;
|
805 |
-
break;
|
806 |
-
case 'center':
|
807 |
-
initialMoveX = dims.width / 2;
|
808 |
-
initialMoveY = dims.height / 2;
|
809 |
-
moveX = -dims.width / 2;
|
810 |
-
moveY = -dims.height / 2;
|
811 |
-
break;
|
812 |
-
}
|
813 |
-
|
814 |
-
return new Effect.Move(element, {
|
815 |
-
x: initialMoveX,
|
816 |
-
y: initialMoveY,
|
817 |
-
duration: 0.01,
|
818 |
-
beforeSetup: function(effect) {
|
819 |
-
effect.element.hide().makeClipping().makePositioned();
|
820 |
-
},
|
821 |
-
afterFinishInternal: function(effect) {
|
822 |
-
new Effect.Parallel(
|
823 |
-
[ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
|
824 |
-
new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
|
825 |
-
new Effect.Scale(effect.element, 100, {
|
826 |
-
scaleMode: { originalHeight: dims.height, originalWidth: dims.width },
|
827 |
-
sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
|
828 |
-
], Object.extend({
|
829 |
-
beforeSetup: function(effect) {
|
830 |
-
effect.effects[0].element.setStyle({height: '0px'}).show();
|
831 |
-
},
|
832 |
-
afterFinishInternal: function(effect) {
|
833 |
-
effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle);
|
834 |
-
}
|
835 |
-
}, options)
|
836 |
-
)
|
837 |
-
}
|
838 |
-
});
|
839 |
-
}
|
840 |
-
|
841 |
-
Effect.Shrink = function(element) {
|
842 |
-
element = $(element);
|
843 |
-
var options = Object.extend({
|
844 |
-
direction: 'center',
|
845 |
-
moveTransition: Effect.Transitions.sinoidal,
|
846 |
-
scaleTransition: Effect.Transitions.sinoidal,
|
847 |
-
opacityTransition: Effect.Transitions.none
|
848 |
-
}, arguments[1] || {});
|
849 |
-
var oldStyle = {
|
850 |
-
top: element.style.top,
|
851 |
-
left: element.style.left,
|
852 |
-
height: element.style.height,
|
853 |
-
width: element.style.width,
|
854 |
-
opacity: element.getInlineOpacity() };
|
855 |
-
|
856 |
-
var dims = element.getDimensions();
|
857 |
-
var moveX, moveY;
|
858 |
-
|
859 |
-
switch (options.direction) {
|
860 |
-
case 'top-left':
|
861 |
-
moveX = moveY = 0;
|
862 |
-
break;
|
863 |
-
case 'top-right':
|
864 |
-
moveX = dims.width;
|
865 |
-
moveY = 0;
|
866 |
-
break;
|
867 |
-
case 'bottom-left':
|
868 |
-
moveX = 0;
|
869 |
-
moveY = dims.height;
|
870 |
-
break;
|
871 |
-
case 'bottom-right':
|
872 |
-
moveX = dims.width;
|
873 |
-
moveY = dims.height;
|
874 |
-
break;
|
875 |
-
case 'center':
|
876 |
-
moveX = dims.width / 2;
|
877 |
-
moveY = dims.height / 2;
|
878 |
-
break;
|
879 |
-
}
|
880 |
-
|
881 |
-
return new Effect.Parallel(
|
882 |
-
[ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
|
883 |
-
new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
|
884 |
-
new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
|
885 |
-
], Object.extend({
|
886 |
-
beforeStartInternal: function(effect) {
|
887 |
-
effect.effects[0].element.makePositioned().makeClipping();
|
888 |
-
},
|
889 |
-
afterFinishInternal: function(effect) {
|
890 |
-
effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
|
891 |
-
}, options)
|
892 |
-
);
|
893 |
-
}
|
894 |
-
|
895 |
-
Effect.Pulsate = function(element) {
|
896 |
-
element = $(element);
|
897 |
-
var options = arguments[1] || {};
|
898 |
-
var oldOpacity = element.getInlineOpacity();
|
899 |
-
var transition = options.transition || Effect.Transitions.sinoidal;
|
900 |
-
var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) };
|
901 |
-
reverser.bind(transition);
|
902 |
-
return new Effect.Opacity(element,
|
903 |
-
Object.extend(Object.extend({ duration: 2.0, from: 0,
|
904 |
-
afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
|
905 |
-
}, options), {transition: reverser}));
|
906 |
-
}
|
907 |
-
|
908 |
-
Effect.Fold = function(element) {
|
909 |
-
element = $(element);
|
910 |
-
var oldStyle = {
|
911 |
-
top: element.style.top,
|
912 |
-
left: element.style.left,
|
913 |
-
width: element.style.width,
|
914 |
-
height: element.style.height };
|
915 |
-
element.makeClipping();
|
916 |
-
return new Effect.Scale(element, 5, Object.extend({
|
917 |
-
scaleContent: false,
|
918 |
-
scaleX: false,
|
919 |
-
afterFinishInternal: function(effect) {
|
920 |
-
new Effect.Scale(element, 1, {
|
921 |
-
scaleContent: false,
|
922 |
-
scaleY: false,
|
923 |
-
afterFinishInternal: function(effect) {
|
924 |
-
effect.element.hide().undoClipping().setStyle(oldStyle);
|
925 |
-
} });
|
926 |
-
}}, arguments[1] || {}));
|
927 |
-
};
|
928 |
-
|
929 |
-
Effect.Morph = Class.create();
|
930 |
-
Object.extend(Object.extend(Effect.Morph.prototype, Effect.Base.prototype), {
|
931 |
-
initialize: function(element) {
|
932 |
-
this.element = $(element);
|
933 |
-
if(!this.element) throw(Effect._elementDoesNotExistError);
|
934 |
-
var options = Object.extend({
|
935 |
-
style: {}
|
936 |
-
}, arguments[1] || {});
|
937 |
-
if (typeof options.style == 'string') {
|
938 |
-
if(options.style.indexOf(':') == -1) {
|
939 |
-
var cssText = '', selector = '.' + options.style;
|
940 |
-
$A(document.styleSheets).reverse().each(function(styleSheet) {
|
941 |
-
if (styleSheet.cssRules) cssRules = styleSheet.cssRules;
|
942 |
-
else if (styleSheet.rules) cssRules = styleSheet.rules;
|
943 |
-
$A(cssRules).reverse().each(function(rule) {
|
944 |
-
if (selector == rule.selectorText) {
|
945 |
-
cssText = rule.style.cssText;
|
946 |
-
throw $break;
|
947 |
-
}
|
948 |
-
});
|
949 |
-
if (cssText) throw $break;
|
950 |
-
});
|
951 |
-
this.style = cssText.parseStyle();
|
952 |
-
options.afterFinishInternal = function(effect){
|
953 |
-
effect.element.addClassName(effect.options.style);
|
954 |
-
effect.transforms.each(function(transform) {
|
955 |
-
if(transform.style != 'opacity')
|
956 |
-
effect.element.style[transform.style] = '';
|
957 |
-
});
|
958 |
-
}
|
959 |
-
} else this.style = options.style.parseStyle();
|
960 |
-
} else this.style = $H(options.style)
|
961 |
-
this.start(options);
|
962 |
-
},
|
963 |
-
setup: function(){
|
964 |
-
function parseColor(color){
|
965 |
-
if(!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
|
966 |
-
color = color.parseColor();
|
967 |
-
return $R(0,2).map(function(i){
|
968 |
-
return parseInt( color.slice(i*2+1,i*2+3), 16 )
|
969 |
-
});
|
970 |
-
}
|
971 |
-
this.transforms = this.style.map(function(pair){
|
972 |
-
var property = pair[0], value = pair[1], unit = null;
|
973 |
-
|
974 |
-
if(value.parseColor('#zzzzzz') != '#zzzzzz') {
|
975 |
-
value = value.parseColor();
|
976 |
-
unit = 'color';
|
977 |
-
} else if(property == 'opacity') {
|
978 |
-
value = parseFloat(value);
|
979 |
-
if(Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
|
980 |
-
this.element.setStyle({zoom: 1});
|
981 |
-
} else if(Element.CSS_LENGTH.test(value)) {
|
982 |
-
var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/);
|
983 |
-
value = parseFloat(components[1]);
|
984 |
-
unit = (components.length == 3) ? components[2] : null;
|
985 |
-
}
|
986 |
-
|
987 |
-
var originalValue = this.element.getStyle(property);
|
988 |
-
return {
|
989 |
-
style: property.camelize(),
|
990 |
-
originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0),
|
991 |
-
targetValue: unit=='color' ? parseColor(value) : value,
|
992 |
-
unit: unit
|
993 |
-
};
|
994 |
-
}.bind(this)).reject(function(transform){
|
995 |
-
return (
|
996 |
-
(transform.originalValue == transform.targetValue) ||
|
997 |
-
(
|
998 |
-
transform.unit != 'color' &&
|
999 |
-
(isNaN(transform.originalValue) || isNaN(transform.targetValue))
|
1000 |
-
)
|
1001 |
-
)
|
1002 |
-
});
|
1003 |
-
},
|
1004 |
-
update: function(position) {
|
1005 |
-
var style = {}, transform, i = this.transforms.length;
|
1006 |
-
while(i--)
|
1007 |
-
style[(transform = this.transforms[i]).style] =
|
1008 |
-
transform.unit=='color' ? '#'+
|
1009 |
-
(Math.round(transform.originalValue[0]+
|
1010 |
-
(transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() +
|
1011 |
-
(Math.round(transform.originalValue[1]+
|
1012 |
-
(transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() +
|
1013 |
-
(Math.round(transform.originalValue[2]+
|
1014 |
-
(transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() :
|
1015 |
-
transform.originalValue + Math.round(
|
1016 |
-
((transform.targetValue - transform.originalValue) * position) * 1000)/1000 + transform.unit;
|
1017 |
-
this.element.setStyle(style, true);
|
1018 |
-
}
|
1019 |
-
});
|
1020 |
-
|
1021 |
-
Effect.Transform = Class.create();
|
1022 |
-
Object.extend(Effect.Transform.prototype, {
|
1023 |
-
initialize: function(tracks){
|
1024 |
-
this.tracks = [];
|
1025 |
-
this.options = arguments[1] || {};
|
1026 |
-
this.addTracks(tracks);
|
1027 |
-
},
|
1028 |
-
addTracks: function(tracks){
|
1029 |
-
tracks.each(function(track){
|
1030 |
-
var data = $H(track).values().first();
|
1031 |
-
this.tracks.push($H({
|
1032 |
-
ids: $H(track).keys().first(),
|
1033 |
-
effect: Effect.Morph,
|
1034 |
-
options: { style: data }
|
1035 |
-
}));
|
1036 |
-
}.bind(this));
|
1037 |
-
return this;
|
1038 |
-
},
|
1039 |
-
play: function(){
|
1040 |
-
return new Effect.Parallel(
|
1041 |
-
this.tracks.map(function(track){
|
1042 |
-
var elements = [$(track.ids) || $$(track.ids)].flatten();
|
1043 |
-
return elements.map(function(e){ return new track.effect(e, Object.extend({ sync:true }, track.options)) });
|
1044 |
-
}).flatten(),
|
1045 |
-
this.options
|
1046 |
-
);
|
1047 |
-
}
|
1048 |
-
});
|
1049 |
-
|
1050 |
-
Element.CSS_PROPERTIES = $w(
|
1051 |
-
'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' +
|
1052 |
-
'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +
|
1053 |
-
'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +
|
1054 |
-
'borderTopColor borderTopStyle borderTopWidth bottom clip color ' +
|
1055 |
-
'fontSize fontWeight height left letterSpacing lineHeight ' +
|
1056 |
-
'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+
|
1057 |
-
'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +
|
1058 |
-
'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +
|
1059 |
-
'right textIndent top width wordSpacing zIndex');
|
1060 |
-
|
1061 |
-
Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
|
1062 |
-
|
1063 |
-
String.prototype.parseStyle = function(){
|
1064 |
-
var element = document.createElement('div');
|
1065 |
-
element.innerHTML = '<div style="' + this + '"></div>';
|
1066 |
-
var style = element.childNodes[0].style, styleRules = $H();
|
1067 |
-
|
1068 |
-
Element.CSS_PROPERTIES.each(function(property){
|
1069 |
-
if(style[property]) styleRules[property] = style[property];
|
1070 |
-
});
|
1071 |
-
if(Prototype.Browser.IE && this.indexOf('opacity') > -1) {
|
1072 |
-
styleRules.opacity = this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1];
|
1073 |
-
}
|
1074 |
-
return styleRules;
|
1075 |
-
};
|
1076 |
-
|
1077 |
-
Element.morph = function(element, style) {
|
1078 |
-
new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || {}));
|
1079 |
-
return element;
|
1080 |
-
};
|
1081 |
-
|
1082 |
-
['getInlineOpacity','forceRerendering','setContentZoom',
|
1083 |
-
'collectTextNodes','collectTextNodesIgnoreClass','morph'].each(
|
1084 |
-
function(f) { Element.Methods[f] = Element[f]; }
|
1085 |
-
);
|
1086 |
-
|
1087 |
-
Element.Methods.visualEffect = function(element, effect, options) {
|
1088 |
-
s = effect.dasherize().camelize();
|
1089 |
-
effect_class = s.charAt(0).toUpperCase() + s.substring(1);
|
1090 |
-
new Effect[effect_class](element, options);
|
1091 |
-
return $(element);
|
1092 |
-
};
|
1093 |
-
|
1094 |
-
Element.addMethods();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
js/dev/lib.dev.js
ADDED
@@ -0,0 +1,1230 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Simple Lightbox
|
3 |
+
* @author Archetyped (http://archetyped.com/tools/simple-lightbox/)
|
4 |
+
*
|
5 |
+
* Inspiration/History
|
6 |
+
* > 2010: Originally based on Lightbox Slideshow v1.1
|
7 |
+
* > by Justin Barkhuff (http://www.justinbarkhuff.com/lab/lightbox_slideshow/)
|
8 |
+
* > Largely based on Lightbox v2.02
|
9 |
+
* > by Lokesh Dhakar - http://huddletogether.com/projects/lightbox2/
|
10 |
+
* > 2011-01-12: Rebuilt as jQuery-compatible codebase
|
11 |
+
*
|
12 |
+
*/
|
13 |
+
|
14 |
+
|
15 |
+
(function($) {
|
16 |
+
SLB = {
|
17 |
+
/* Properties */
|
18 |
+
|
19 |
+
//Core
|
20 |
+
prefix : 'slb',
|
21 |
+
options : {},
|
22 |
+
//Activation
|
23 |
+
trigger : null,
|
24 |
+
urls_checked : {},
|
25 |
+
//Items
|
26 |
+
items : [],
|
27 |
+
item_curr : null,
|
28 |
+
item_init : null,
|
29 |
+
group : null,
|
30 |
+
media : {},
|
31 |
+
//Content
|
32 |
+
content: {
|
33 |
+
caption_enabled: true,
|
34 |
+
caption_src: true,
|
35 |
+
desc_enabled: true,
|
36 |
+
labels : {
|
37 |
+
closeLink : 'close',
|
38 |
+
loadingMsg : 'loading',
|
39 |
+
nextLink : 'next »',
|
40 |
+
prevLink : '« prev',
|
41 |
+
startSlideshow : 'start slideshow',
|
42 |
+
stopSlideshow : 'stop slideshow',
|
43 |
+
numDisplayPrefix : 'Image',
|
44 |
+
numDisplaySeparator : 'of'
|
45 |
+
}
|
46 |
+
},
|
47 |
+
//Layout
|
48 |
+
container : document,
|
49 |
+
masks : ['select','object','embed','iframe'],
|
50 |
+
layout: {
|
51 |
+
template: '',
|
52 |
+
parsed: '',
|
53 |
+
placeholders : {
|
54 |
+
slbContent: '<img id="slb_slbContent" />',
|
55 |
+
slbLoading: '<span id="slb_slbLoading">loading</span>',
|
56 |
+
slbClose: '<a class="slb_slbClose" href="#">close</a>',
|
57 |
+
navPrev: '<a class="slb_navPrev slb_nav" href="#">« prev</a>',
|
58 |
+
navNext: '<a class="slb_navNext slb_nav" href="#">» next</a>',
|
59 |
+
navSlideControl: '<a class="slb_navSlideControl" href="#">Stop</a>',
|
60 |
+
dataCaption: '<span class="slb_dataCaption"></span>',
|
61 |
+
dataDescription: '<span class="slb_dataDescription"></span>',
|
62 |
+
dataNumber: '<span class="slb_dataNumber"></span>'
|
63 |
+
}
|
64 |
+
},
|
65 |
+
//Slideshow
|
66 |
+
slideshow: {
|
67 |
+
active: null,
|
68 |
+
enabled: true,
|
69 |
+
loop: true,
|
70 |
+
duration: 4,
|
71 |
+
timer: null
|
72 |
+
},
|
73 |
+
//Animation
|
74 |
+
anim: {
|
75 |
+
active: true,
|
76 |
+
overlay_duration: 0,
|
77 |
+
overlay_opacity: .8,
|
78 |
+
resize_duration: 0
|
79 |
+
},
|
80 |
+
|
81 |
+
/* Initialization */
|
82 |
+
|
83 |
+
/**
|
84 |
+
* Initialize lightbox instance
|
85 |
+
* @param object options Instance options
|
86 |
+
*/
|
87 |
+
init: function(options) {
|
88 |
+
//Options
|
89 |
+
this.options = $.extend(true, {
|
90 |
+
//Core
|
91 |
+
prefix: null,
|
92 |
+
|
93 |
+
//Activation
|
94 |
+
trigger : null,
|
95 |
+
validateLinks : false,
|
96 |
+
|
97 |
+
//Content
|
98 |
+
captionEnabled: true,
|
99 |
+
captionSrc : true,
|
100 |
+
descEnabled: true,
|
101 |
+
labels : {},
|
102 |
+
|
103 |
+
//Layout
|
104 |
+
layout : null,
|
105 |
+
placeholders : {},
|
106 |
+
|
107 |
+
//Animation
|
108 |
+
animate : true,
|
109 |
+
overlayDuration : .2,
|
110 |
+
overlayOpacity : .8,
|
111 |
+
resizeSpeed : 400,
|
112 |
+
|
113 |
+
//Slideshow
|
114 |
+
autoPlay : true,
|
115 |
+
enableSlideshow : true,
|
116 |
+
loop : true,
|
117 |
+
slideTime : 4
|
118 |
+
}, options);
|
119 |
+
|
120 |
+
//Stop if no layout is defined
|
121 |
+
if (!this.options.layout || this.options.layout.toString().length == 0)
|
122 |
+
this.end();
|
123 |
+
|
124 |
+
/* Setup Properties */
|
125 |
+
|
126 |
+
//Prefix
|
127 |
+
if ( $.type(this.options.prefix) == 'string' && this.options.prefix.length > 0 ) {
|
128 |
+
this.prefix = this.options.prefix;
|
129 |
+
}
|
130 |
+
|
131 |
+
//Activation
|
132 |
+
if ( !$.isArray(this.options.trigger) ) {
|
133 |
+
this.trigger = [this.prefix];
|
134 |
+
}
|
135 |
+
|
136 |
+
//Content
|
137 |
+
$.extend(true, this.content, {
|
138 |
+
caption_enabled: !!this.options.captionEnabled,
|
139 |
+
caption_src: !!this.options.captionSrc,
|
140 |
+
desc_enabled: !!this.options.descEnabled,
|
141 |
+
labels: ( $.isPlainObject(this.options.labels) ) ? this.options.labels : {}
|
142 |
+
});
|
143 |
+
|
144 |
+
//Layout
|
145 |
+
$.extend(true, this.layout, {
|
146 |
+
template: this.options.layout,
|
147 |
+
placeholders: this.options.placeholders
|
148 |
+
});
|
149 |
+
|
150 |
+
//Animation
|
151 |
+
$.extend(this.anim, {
|
152 |
+
overlay_opacity: Math.max(Math.min(this.options.overlayOpacity,1),0)
|
153 |
+
});
|
154 |
+
if ( this.options.animate ) {
|
155 |
+
$.extend(this.anim, {
|
156 |
+
active: true,
|
157 |
+
overlay_duration: Math.max(this.options.overlayDuration,0),
|
158 |
+
resize_duration: this.options.resizeSpeed
|
159 |
+
});
|
160 |
+
} else {
|
161 |
+
$.extend(this.anim, {
|
162 |
+
active: false,
|
163 |
+
overlay_duration: 0,
|
164 |
+
resize_duration: 0
|
165 |
+
});
|
166 |
+
}
|
167 |
+
|
168 |
+
//Slideshow
|
169 |
+
$.extend(this.slideshow, {
|
170 |
+
play: !!this.options.autoPlay,
|
171 |
+
active: !!this.options.autoPlay,
|
172 |
+
enabled: !!this.options.enableSlideshow,
|
173 |
+
loop: ( !!this.options.enableSlideshow && !!this.options.loop ),
|
174 |
+
duration: ( $.isNumeric(this.options.slideTime) ) ? parseInt(this.options.slideTime) : 0
|
175 |
+
});
|
176 |
+
|
177 |
+
/* Init Layout */
|
178 |
+
|
179 |
+
var t = this;
|
180 |
+
var body = $('body');
|
181 |
+
|
182 |
+
//Overlay
|
183 |
+
$('<div/>', {
|
184 |
+
'id': this.getID('overlay'),
|
185 |
+
'css': {'display': 'none'}
|
186 |
+
}).appendTo(body)
|
187 |
+
.click(function() {t.end();});
|
188 |
+
|
189 |
+
//Viewer
|
190 |
+
var viewer = $('<div/>', {
|
191 |
+
'id': this.getID('viewer'),
|
192 |
+
'css': {'display': 'none'}
|
193 |
+
}).appendTo(body)
|
194 |
+
.click(function() {t.end();});
|
195 |
+
|
196 |
+
//Build layout from template
|
197 |
+
this.layout.parsed = this.getLayout();
|
198 |
+
|
199 |
+
//Insert layout into viewer
|
200 |
+
$(this.layout.parsed).appendTo(viewer);
|
201 |
+
|
202 |
+
//Set UI
|
203 |
+
this.initUI();
|
204 |
+
|
205 |
+
//Add events
|
206 |
+
this.initEvents();
|
207 |
+
},
|
208 |
+
|
209 |
+
/**
|
210 |
+
* Set localized values for UI elements
|
211 |
+
*/
|
212 |
+
initUI: function() {
|
213 |
+
this.get('slbClose').html(this.getLabel('closeLink'));
|
214 |
+
this.get('navNext').html(this.getLabel('nextLink'));
|
215 |
+
this.get('navPrev').html(this.getLabel('prevLink'));
|
216 |
+
this.get('navSlideControl').html( this.getLabel((this.slideshowActive()) ? 'stopSlideshow' : 'startSlideshow') );
|
217 |
+
},
|
218 |
+
|
219 |
+
/**
|
220 |
+
* Add events to various UI elements
|
221 |
+
*/
|
222 |
+
initEvents: function() {
|
223 |
+
var t = this, delay = 500;
|
224 |
+
//Remove all previous handlers
|
225 |
+
this.get('container,details,navPrev,navNext,navSlideControl,slbClose').unbind('click');
|
226 |
+
|
227 |
+
//Set event handlers
|
228 |
+
this.get('container,details').click(function(ev) {
|
229 |
+
ev.stopPropagation();
|
230 |
+
});
|
231 |
+
|
232 |
+
var clickP = function() {
|
233 |
+
//Handle double clicks
|
234 |
+
t.get('navPrev').unbind('click').click(false);
|
235 |
+
setTimeout(function() {t.get('navPrev').click(clickP);}, delay);
|
236 |
+
t.navPrev();
|
237 |
+
return false;
|
238 |
+
};
|
239 |
+
this.get('navPrev').click(function(){
|
240 |
+
return clickP();
|
241 |
+
});
|
242 |
+
|
243 |
+
var clickN = function() {
|
244 |
+
//Handle double clicks
|
245 |
+
t.get('navNext').unbind('click').click(false);
|
246 |
+
setTimeout(function() {t.get('navNext').click(clickN);}, delay);
|
247 |
+
t.navNext();
|
248 |
+
return false;
|
249 |
+
};
|
250 |
+
this.get('navNext').click(function() {
|
251 |
+
return clickN();
|
252 |
+
});
|
253 |
+
|
254 |
+
this.get('navSlideControl').click(function() {
|
255 |
+
t.slideshowToggle();
|
256 |
+
return false;
|
257 |
+
});
|
258 |
+
this.get('slbClose').click(function() {
|
259 |
+
t.end();
|
260 |
+
return false;
|
261 |
+
});
|
262 |
+
|
263 |
+
//Handle links on page
|
264 |
+
this.initLinks();
|
265 |
+
},
|
266 |
+
|
267 |
+
/**
|
268 |
+
* Finds all compatible image links on page
|
269 |
+
* @return void
|
270 |
+
*/
|
271 |
+
initLinks: function() {
|
272 |
+
var ph = '{relattr}', t = this;
|
273 |
+
var sel = [], selBase = 'a[href][rel*="' + ph + '"]:not([rel~="' + this.addPrefix('off') + '"])';
|
274 |
+
|
275 |
+
//Click event handler
|
276 |
+
var handler = function() {
|
277 |
+
t.view(this);
|
278 |
+
return false;
|
279 |
+
};
|
280 |
+
|
281 |
+
//Build selector
|
282 |
+
for (var x = 0; x < this.trigger.length; x++) {
|
283 |
+
sel.push(selBase.replace(ph, this.trigger[x]));
|
284 |
+
}
|
285 |
+
sel = sel.join(',');
|
286 |
+
//Add event handler to links
|
287 |
+
$(sel, $(this.container)).live('click', handler);
|
288 |
+
},
|
289 |
+
|
290 |
+
/* Display */
|
291 |
+
|
292 |
+
/**
|
293 |
+
* Display viewer
|
294 |
+
* If item is part of a group, add other items in group
|
295 |
+
* @param node item Link element of item to display
|
296 |
+
*/
|
297 |
+
view: function(item) {
|
298 |
+
item = $(item);
|
299 |
+
this.mask();
|
300 |
+
|
301 |
+
this.items = [];
|
302 |
+
this.setGroup(item);
|
303 |
+
|
304 |
+
var t = this;
|
305 |
+
var groupTemp = {};
|
306 |
+
this.fileExists(this.itemSource(item),
|
307 |
+
function() {
|
308 |
+
/* File Exists */
|
309 |
+
|
310 |
+
/* Handlers */
|
311 |
+
|
312 |
+
/**
|
313 |
+
* Add item to group
|
314 |
+
* @param obj el Item to add
|
315 |
+
* @param int idx DOM position index of item
|
316 |
+
* @return int Total number of items in group
|
317 |
+
*/
|
318 |
+
var addItem = function(el, idx) {
|
319 |
+
groupTemp[idx] = el;
|
320 |
+
return groupTemp.length;
|
321 |
+
};
|
322 |
+
|
323 |
+
/**
|
324 |
+
* Build final item array & launch viewer
|
325 |
+
*/
|
326 |
+
var proceed = function() {
|
327 |
+
t.item_init = 0;
|
328 |
+
//Sort links by document order
|
329 |
+
var order = [], el;
|
330 |
+
for (var x in groupTemp) {
|
331 |
+
order.push(x);
|
332 |
+
}
|
333 |
+
order.sort(function(a, b) { return (a - b); });
|
334 |
+
for (x = 0; x < order.length; x++) {
|
335 |
+
el = groupTemp[order[x]];
|
336 |
+
// Check if link being evaluated is the same as the clicked link
|
337 |
+
if ($(el).get(0) == $(item).get(0)) {
|
338 |
+
t.item_init = x;
|
339 |
+
}
|
340 |
+
t.items.push({'link':t.itemSource($(el)), 'title':t.getCaption(el), 'desc': t.getDescription(el)});
|
341 |
+
}
|
342 |
+
// Calculate top offset for the viewer and display
|
343 |
+
var vwrTop = $(document).scrollTop() + ($(window).height() / 15);
|
344 |
+
t.get('viewer').css('top', vwrTop + 'px').show();
|
345 |
+
t.itemLoad(t.item_init);
|
346 |
+
};
|
347 |
+
|
348 |
+
/* Display */
|
349 |
+
|
350 |
+
//Overlay
|
351 |
+
t.get('overlay')
|
352 |
+
.height($(document).height())
|
353 |
+
.fadeTo(t.anim.overlay_duration, t.options.overlayOpacity);
|
354 |
+
|
355 |
+
//Single item (not in group)
|
356 |
+
if ( !t.hasGroup() ) {
|
357 |
+
//Display item
|
358 |
+
t.item_init = 0;
|
359 |
+
addItem(item, t.item_init);
|
360 |
+
proceed();
|
361 |
+
} else {
|
362 |
+
//Item in group
|
363 |
+
var links = $(t.container).find('a');
|
364 |
+
//Get other items in group
|
365 |
+
var grpLinks = [];
|
366 |
+
var i, link;
|
367 |
+
for ( i = 0; i < links.length; i++ ) {
|
368 |
+
link = $(links[i]);
|
369 |
+
if ( t.itemSource(link) && t.inGroup(link) ) {
|
370 |
+
//Add links in group
|
371 |
+
grpLinks.push(link);
|
372 |
+
}
|
373 |
+
}
|
374 |
+
|
375 |
+
//Loop through group links, validate, and add to items array
|
376 |
+
var processed = 0;
|
377 |
+
for ( i = 0; i < grpLinks.length; i++ ) {
|
378 |
+
link = grpLinks[i];
|
379 |
+
t.fileExists(t.itemSource($(link)),
|
380 |
+
function(args) {
|
381 |
+
/* File exists */
|
382 |
+
|
383 |
+
//Add item
|
384 |
+
var el = args.items[args.idx];
|
385 |
+
addItem(el, args.idx);
|
386 |
+
processed++;
|
387 |
+
//Display valid items after all items parsed
|
388 |
+
if ( processed == args.items.length )
|
389 |
+
proceed();
|
390 |
+
},
|
391 |
+
function(args) {
|
392 |
+
/* File does not exist */
|
393 |
+
processed++;
|
394 |
+
//Display valid items after all items parsed
|
395 |
+
if (args.idx == args.items.length)
|
396 |
+
proceed();
|
397 |
+
},
|
398 |
+
{'idx': i, 'items': grpLinks});
|
399 |
+
}
|
400 |
+
}
|
401 |
+
},
|
402 |
+
function() {
|
403 |
+
/* File does not exist */
|
404 |
+
t.end();
|
405 |
+
});
|
406 |
+
},
|
407 |
+
|
408 |
+
/**
|
409 |
+
* Close the viewer
|
410 |
+
*/
|
411 |
+
end: function() {
|
412 |
+
this.keyboardDisable();
|
413 |
+
this.slideshowPause();
|
414 |
+
this.get('viewer').hide();
|
415 |
+
this.get('overlay').fadeOut(this.anim.overlay_duration);
|
416 |
+
this.unmask();
|
417 |
+
},
|
418 |
+
|
419 |
+
/**
|
420 |
+
* Resizes viewer to fit image
|
421 |
+
* @param int imgWidth Image width in pixels
|
422 |
+
* @param int imgHeight Image height in pixels
|
423 |
+
*/
|
424 |
+
viewerResize: function(w, h) {
|
425 |
+
var d = this.viewerSize(w, h);
|
426 |
+
//Resize container
|
427 |
+
this.get('container').animate({width: d.width, height: d.height}, this.anim.resize_duration);
|
428 |
+
//Resize overlay
|
429 |
+
this.get('overlay').css('min-width', d.width);
|
430 |
+
this.itemShow();
|
431 |
+
},
|
432 |
+
|
433 |
+
/**
|
434 |
+
* Retrieve or build container size
|
435 |
+
* @param int w Container width to set
|
436 |
+
* @param int h Container height to set
|
437 |
+
* @return obj Container width (w)/height (h) values
|
438 |
+
*/
|
439 |
+
viewerSize: function(w, h) {
|
440 |
+
var style = 'padding';
|
441 |
+
var hz = ['left', 'right'], vt = ['top', 'bottom'];
|
442 |
+
var ph = 0, pv = 0;
|
443 |
+
var t = this;
|
444 |
+
//Calculate spacing around item
|
445 |
+
|
446 |
+
var getVal = function(prop) {
|
447 |
+
var unit = 'px';
|
448 |
+
prop = style + '-' + prop;
|
449 |
+
var ptemp = t.get('content').css( prop );
|
450 |
+
if ( ptemp.indexOf(unit) == -1 ) {
|
451 |
+
ptemp = 0;
|
452 |
+
} else {
|
453 |
+
ptemp = ptemp.replace(unit, '');
|
454 |
+
}
|
455 |
+
return ( $.isNumeric(ptemp) ) ? parseFloat(ptemp) : 0;
|
456 |
+
};
|
457 |
+
|
458 |
+
//Horizontal
|
459 |
+
for ( var x = 0; x < hz.length; x++) {
|
460 |
+
ph += getVal(hz[x]);
|
461 |
+
}
|
462 |
+
//Vertical
|
463 |
+
for ( x = 0; x < vt.length; x++) {
|
464 |
+
pv += getVal(vt[x]);
|
465 |
+
}
|
466 |
+
var c = {
|
467 |
+
'width': w + ph,
|
468 |
+
'height': h + pv
|
469 |
+
};
|
470 |
+
return c;
|
471 |
+
},
|
472 |
+
|
473 |
+
/**
|
474 |
+
* Displays objects that may conflict with the viewer
|
475 |
+
* @param bool show (optional) Whether or not to show objects (Default: TRUE)
|
476 |
+
*/
|
477 |
+
unmask: function (show) {
|
478 |
+
show = ( typeof(show) == 'undefined' ) ? true : !!show;
|
479 |
+
var vis = (show) ? 'visible' : 'hidden';
|
480 |
+
$(this.masks.join(',')).css('visibility', vis);
|
481 |
+
},
|
482 |
+
|
483 |
+
/**
|
484 |
+
* Hides objects that may conflict with the viewer
|
485 |
+
* @uses unmask() to hide objects
|
486 |
+
*/
|
487 |
+
mask: function () {
|
488 |
+
this.unmask(false);
|
489 |
+
},
|
490 |
+
|
491 |
+
/* Item */
|
492 |
+
|
493 |
+
/**
|
494 |
+
* Retrieve item property
|
495 |
+
* @uses items to retrieve property from item in array
|
496 |
+
* @param int idx Item position index
|
497 |
+
* @param string prop Item property to retrieve
|
498 |
+
* @return mixed Item property (Default: empty string)
|
499 |
+
*/
|
500 |
+
itemProp: function(idx, prop) {
|
501 |
+
return ( idx < this.items.length && prop in this.items[idx] ) ? this.items[idx][prop] : '';
|
502 |
+
},
|
503 |
+
|
504 |
+
/**
|
505 |
+
* Preloads requested item prior to displaying it in viewer
|
506 |
+
* @param int idx Index of item in items property
|
507 |
+
* @uses items to retrieve item at specified index
|
508 |
+
* @uses viewerResize() to resize viewer after item has loaded
|
509 |
+
*/
|
510 |
+
itemLoad: function(idx) {
|
511 |
+
this.item_curr = idx;
|
512 |
+
|
513 |
+
this.keyboardDisable();
|
514 |
+
this.slideshowPause();
|
515 |
+
|
516 |
+
//Hide elements during transition
|
517 |
+
this.get('slbLoading').show();
|
518 |
+
this.get('slbContent').hide();
|
519 |
+
this.get('details').hide();
|
520 |
+
var preloader = new Image();
|
521 |
+
var t = this;
|
522 |
+
|
523 |
+
//Event handler: Display item when loaded
|
524 |
+
$(preloader).bind('load', function() {
|
525 |
+
t.get('slbContent').attr('src', preloader.src);
|
526 |
+
t.viewerResize(preloader.width, preloader.height);
|
527 |
+
|
528 |
+
//Restart slideshow if active
|
529 |
+
if ( t.slideshowActive() )
|
530 |
+
t.slideshowStart();
|
531 |
+
});
|
532 |
+
|
533 |
+
//Load image
|
534 |
+
preloader.src = this.itemProp(this.item_curr, 'link');
|
535 |
+
},
|
536 |
+
|
537 |
+
/**
|
538 |
+
* Display image and begin preloading neighbors.
|
539 |
+
*/
|
540 |
+
itemShow: function() {
|
541 |
+
this.get('slbLoading').hide();
|
542 |
+
var t = this;
|
543 |
+
this.get('slbContent').fadeIn(500, function() { t.contentUpdate(); });
|
544 |
+
if ( this.hasItems() ) {
|
545 |
+
this.itemPreloadSiblings();
|
546 |
+
}
|
547 |
+
},
|
548 |
+
|
549 |
+
/**
|
550 |
+
* Preloads items surrounding current item
|
551 |
+
*/
|
552 |
+
itemPreloadSiblings: function() {
|
553 |
+
//Prev
|
554 |
+
var idxPrev = ( this.itemFirst() ) ? this.items.length - 1 : this.item_curr - 1;
|
555 |
+
var itemPrev = new Image();
|
556 |
+
itemPrev.src = this.itemProp(idxPrev, 'link');
|
557 |
+
|
558 |
+
//Next
|
559 |
+
var idxNext = ( this.itemLast() ) ? 0 : this.item_curr + 1;
|
560 |
+
if ( idxNext != idxPrev ) {
|
561 |
+
var itemNext = new Image();
|
562 |
+
itemNext.src = this.itemProp(idxNext, 'link');
|
563 |
+
}
|
564 |
+
},
|
565 |
+
|
566 |
+
/**
|
567 |
+
* Check if there is at least one image to display in the viewer
|
568 |
+
* @return bool TRUE if at least one image is found
|
569 |
+
* @uses items to check for images
|
570 |
+
*/
|
571 |
+
hasItem: function() {
|
572 |
+
return ( this.items.length > 0 );
|
573 |
+
},
|
574 |
+
|
575 |
+
/**
|
576 |
+
* Check if there are multiple images to display in the viewer
|
577 |
+
* @return bool TRUE if there are multiple images
|
578 |
+
* @uses items to determine the number of images
|
579 |
+
*/
|
580 |
+
hasItems: function() {
|
581 |
+
return ( this.items.length > 1 );
|
582 |
+
},
|
583 |
+
|
584 |
+
/**
|
585 |
+
* Check if the current image is the first image in the list
|
586 |
+
* @return bool TRUE if image is first
|
587 |
+
* @uses item_curr to check index of current image
|
588 |
+
*/
|
589 |
+
itemFirst: function() {
|
590 |
+
return ( this.item_curr == 0 );
|
591 |
+
},
|
592 |
+
|
593 |
+
/**
|
594 |
+
* Check if the current image is the last image in the list
|
595 |
+
* @return bool TRUE if image is last
|
596 |
+
* @uses item_curr to check index of current image
|
597 |
+
* @uses items to compare current image to total number of images
|
598 |
+
*/
|
599 |
+
itemLast: function() {
|
600 |
+
return ( this.item_curr == this.items.length - 1 );
|
601 |
+
},
|
602 |
+
|
603 |
+
/**
|
604 |
+
* Retrieve source URI in link
|
605 |
+
* @param obj el
|
606 |
+
* @return string Source file URI
|
607 |
+
*/
|
608 |
+
itemSource: function(el) {
|
609 |
+
var src = $(el).attr('href');
|
610 |
+
var attr = $(el).attr('rel') || '';
|
611 |
+
if ( attr.length ) {
|
612 |
+
//Attachment source
|
613 |
+
var mSrc = this.mediaProp(el, 'source');
|
614 |
+
//Set source using extended properties
|
615 |
+
if ( $.type(mSrc) === 'string' && mSrc.length )
|
616 |
+
src = mSrc;
|
617 |
+
}
|
618 |
+
return src;
|
619 |
+
},
|
620 |
+
|
621 |
+
/**
|
622 |
+
* Check if current link is part of a gallery
|
623 |
+
* @param obj item
|
624 |
+
* @param string gType Gallery type to check for
|
625 |
+
* @return bool Whether link is part of a gallery
|
626 |
+
*/
|
627 |
+
itemGallery: function(item, gType) {
|
628 |
+
var ret = false;
|
629 |
+
var galls = {
|
630 |
+
'wp': '.gallery-icon',
|
631 |
+
'ng': '.ngg-gallery-thumbnail'
|
632 |
+
};
|
633 |
+
|
634 |
+
|
635 |
+
if ( typeof gType == 'undefined' || !(gType in galls) ) {
|
636 |
+
gType = 'wp';
|
637 |
+
}
|
638 |
+
return ( $(item).parent(galls[gType]).length > 0 ) ? true : false ;
|
639 |
+
},
|
640 |
+
|
641 |
+
/* Media */
|
642 |
+
|
643 |
+
/**
|
644 |
+
* Retrieve ID of media item
|
645 |
+
* @param obj el Link element
|
646 |
+
* @return string|bool Media ID (Default: false - No ID)
|
647 |
+
*/
|
648 |
+
mediaId: function(el) {
|
649 |
+
var h = $(el).attr('href');
|
650 |
+
if ($.type(h) !== 'string')
|
651 |
+
h = false;
|
652 |
+
return h;
|
653 |
+
},
|
654 |
+
|
655 |
+
/**
|
656 |
+
* Retrieve Media properties
|
657 |
+
* @param obj el Link element
|
658 |
+
* @return obj Properties for Media item (Default: Empty)
|
659 |
+
*/
|
660 |
+
mediaProps: function(el) {
|
661 |
+
var props = {},
|
662 |
+
mId = this.mediaId(el);
|
663 |
+
if (mId && mId in this.media) {
|
664 |
+
props = this.media[mId];
|
665 |
+
}
|
666 |
+
return props;
|
667 |
+
},
|
668 |
+
|
669 |
+
/**
|
670 |
+
* Retrieve single property for media item
|
671 |
+
* @param obj el Image link DOM element
|
672 |
+
* @param string prop Property to retrieve
|
673 |
+
* @return mixed|null Item property (Default: NULL if property does not exist)
|
674 |
+
*/
|
675 |
+
mediaProp: function(el, prop) {
|
676 |
+
var props = this.mediaProps(el);
|
677 |
+
return (prop in props) ? props[prop] : null;
|
678 |
+
},
|
679 |
+
|
680 |
+
/* Content */
|
681 |
+
|
682 |
+
/**
|
683 |
+
* Retrieve specified label
|
684 |
+
* @param string id Label ID
|
685 |
+
* @param string def (optional) Default value if specified label is invalid
|
686 |
+
* @return string Label text
|
687 |
+
*/
|
688 |
+
getLabel: function(id, def) {
|
689 |
+
if ( typeof def == 'undefined' ) {
|
690 |
+
def = '';
|
691 |
+
}
|
692 |
+
return ( id in this.content.labels ) ? this.content.labels[id] : def;
|
693 |
+
},
|
694 |
+
|
695 |
+
/**
|
696 |
+
* Build caption for displayed item
|
697 |
+
* @param obj item DOM link element
|
698 |
+
* @return string Image caption
|
699 |
+
*/
|
700 |
+
getCaption: function(item) {
|
701 |
+
item = $(item);
|
702 |
+
var caption = '';
|
703 |
+
if ( this.content.caption_enabled ) {
|
704 |
+
var sels = {
|
705 |
+
'capt': '.wp-caption-text',
|
706 |
+
'gIcon': '.gallery-icon'
|
707 |
+
};
|
708 |
+
var els = {
|
709 |
+
'link': item,
|
710 |
+
'origin': item,
|
711 |
+
'sibs': null,
|
712 |
+
'img': null
|
713 |
+
};
|
714 |
+
//WP Caption
|
715 |
+
if ( this.itemGallery(els.link, 'wp') ) {
|
716 |
+
els.origin = $(els.link).parent();
|
717 |
+
}
|
718 |
+
if ( (els.sibs = $(els.origin).siblings(sels.capt)) && $(els.sibs).length > 0 ) {
|
719 |
+
caption = $.trim($(els.sibs).first().text());
|
720 |
+
}
|
721 |
+
|
722 |
+
//Fall back to image properties
|
723 |
+
if ( !caption ) {
|
724 |
+
els.img = $(els.link).find('img').first();
|
725 |
+
if ( $(els.img).length ) {
|
726 |
+
//Image title / alt
|
727 |
+
caption = $(els.img).attr('title') || $(els.img).attr('alt');
|
728 |
+
caption = $.trim(caption);
|
729 |
+
}
|
730 |
+
}
|
731 |
+
|
732 |
+
//Media properties
|
733 |
+
if ( !caption ) {
|
734 |
+
caption = this.mediaProp(els.link, 'title') || '';
|
735 |
+
caption = $.trim(caption);
|
736 |
+
}
|
737 |
+
|
738 |
+
//Fall back Link Text
|
739 |
+
if ( !caption ) {
|
740 |
+
var c = '';
|
741 |
+
if ( ( c = $.trim($(els.link).text()) ) && c.length) {
|
742 |
+
caption = c;
|
743 |
+
} else if (this.options.captionSrc) {
|
744 |
+
//Fall back to Link href
|
745 |
+
caption = $(els.link).attr('href');
|
746 |
+
var trimChars = ['/', '#', '.'];
|
747 |
+
//Trim invalid characters
|
748 |
+
while ( caption.length && $.inArray(caption.charAt(0), trimChars) != -1 )
|
749 |
+
caption = caption.substr(1);
|
750 |
+
while ( caption.length && $.inArray(caption.charAt(caption.length - 1), trimChars) != -1 )
|
751 |
+
caption = caption.substr(0, caption.length - 1);
|
752 |
+
|
753 |
+
//Strip to base file name
|
754 |
+
var idx = caption.lastIndexOf('/');
|
755 |
+
if ( -1 != idx )
|
756 |
+
caption = caption.substr(idx + 1);
|
757 |
+
//Strip extension
|
758 |
+
idx = caption.lastIndexOf('.');
|
759 |
+
if ( -1 != idx ) {
|
760 |
+
caption = caption.slice(0, idx);
|
761 |
+
}
|
762 |
+
}
|
763 |
+
caption = $.trim(caption);
|
764 |
+
}
|
765 |
+
}
|
766 |
+
return caption;
|
767 |
+
},
|
768 |
+
|
769 |
+
/**
|
770 |
+
* Retrieve item description
|
771 |
+
* @param obj item
|
772 |
+
* @return string Item description (Default: empty string)
|
773 |
+
*/
|
774 |
+
getDescription: function(item) {
|
775 |
+
var desc = '';
|
776 |
+
if ( this.content.desc_enabled ) {
|
777 |
+
//Retrieve description
|
778 |
+
if ( this.itemGallery(item, 'ng') ) {
|
779 |
+
desc = $(item).attr('title');
|
780 |
+
} else {
|
781 |
+
desc = this.mediaProp(item, 'desc');
|
782 |
+
}
|
783 |
+
|
784 |
+
if (!desc)
|
785 |
+
desc = '';
|
786 |
+
}
|
787 |
+
return desc;
|
788 |
+
},
|
789 |
+
|
790 |
+
/**
|
791 |
+
* Display item details
|
792 |
+
*/
|
793 |
+
contentUpdate: function() {
|
794 |
+
//Caption
|
795 |
+
if (this.content.caption_enabled) {
|
796 |
+
this.get('dataCaption').text(this.itemProp(this.item_curr, 'title'));
|
797 |
+
this.get('dataCaption').show();
|
798 |
+
} else {
|
799 |
+
this.get('dataCaption').hide();
|
800 |
+
}
|
801 |
+
|
802 |
+
//Description
|
803 |
+
this.get('dataDescription').html(this.itemProp(this.item_curr, 'desc'));
|
804 |
+
|
805 |
+
//Handle grouped items
|
806 |
+
if ( this.hasItems() ) {
|
807 |
+
var num_display = this.getLabel('numDisplayPrefix') + ' ' + (this.item_curr + 1) + ' ' + this.getLabel('numDisplaySeparator') + ' ' + this.items.length;
|
808 |
+
this.get('dataNumber')
|
809 |
+
.text(num_display)
|
810 |
+
.show();
|
811 |
+
}
|
812 |
+
|
813 |
+
//Resize content area
|
814 |
+
this.get('details').width(this.get('container').width());
|
815 |
+
this.navUpdate();
|
816 |
+
var t = this;
|
817 |
+
this.get('details').animate({height: 'show', opacity: 'show'}, 650);
|
818 |
+
},
|
819 |
+
|
820 |
+
/* Layout */
|
821 |
+
|
822 |
+
/**
|
823 |
+
* Build layout from template
|
824 |
+
* @uses options.layout
|
825 |
+
* @return string Layout markup (HTML)
|
826 |
+
*/
|
827 |
+
getLayout: function() {
|
828 |
+
var l = this.layout.template;
|
829 |
+
|
830 |
+
//Expand placeholders
|
831 |
+
var ph, phs, phr;
|
832 |
+
for ( ph in this.layout.placeholders ) {
|
833 |
+
phs = '{' + ph + '}';
|
834 |
+
//Continue to next placeholder if current one is not in layout
|
835 |
+
if (l.indexOf(phs) == -1)
|
836 |
+
continue;
|
837 |
+
phr = new RegExp(phs, "g");
|
838 |
+
l = l.replace(phr, this.layout.placeholders[ph]);
|
839 |
+
}
|
840 |
+
|
841 |
+
//Return final layout
|
842 |
+
return l;
|
843 |
+
|
844 |
+
},
|
845 |
+
|
846 |
+
/* Grouping */
|
847 |
+
|
848 |
+
/**
|
849 |
+
* Sets group based on current item
|
850 |
+
* @param obj item DOM element to get group from
|
851 |
+
*/
|
852 |
+
setGroup: function(item) {
|
853 |
+
this.group = this.getGroup(item);
|
854 |
+
},
|
855 |
+
|
856 |
+
/**
|
857 |
+
* Extract group name from
|
858 |
+
* @param obj item Element to extract group name from
|
859 |
+
* @return string Group name
|
860 |
+
*/
|
861 |
+
getGroup: function(item) {
|
862 |
+
//Return global group property if no item specified
|
863 |
+
if ( typeof item == 'undefined' || 0 == $(item).length )
|
864 |
+
return this.group;
|
865 |
+
//Get item's group
|
866 |
+
var g = '';
|
867 |
+
var attr = $(item).attr('rel') || '';
|
868 |
+
if ( attr != '' ) {
|
869 |
+
var gTmp = '',
|
870 |
+
gSt = '[',
|
871 |
+
gEnd = ']',
|
872 |
+
search = this.addPrefix('group') + gSt,
|
873 |
+
idx,
|
874 |
+
prefix = ' ';
|
875 |
+
//Find group indicator
|
876 |
+
idx = attr.indexOf(search);
|
877 |
+
//Prefix with space to find whole word
|
878 |
+
if ( prefix != search.charAt(0) && idx > 0 ) {
|
879 |
+
search = prefix + search;
|
880 |
+
idx = attr.indexOf(search);
|
881 |
+
}
|
882 |
+
//Continue processing if value is found
|
883 |
+
if ( idx != -1 ) {
|
884 |
+
//Extract group name
|
885 |
+
gTmp = $.trim(attr.substring(idx).replace(search, ''));
|
886 |
+
//Check if group defined
|
887 |
+
if (gTmp.length > 1 && gTmp.indexOf(gEnd) > 0) {
|
888 |
+
//Extract group name
|
889 |
+
g = gTmp.substring(0, gTmp.indexOf(gEnd));
|
890 |
+
}
|
891 |
+
}
|
892 |
+
}
|
893 |
+
return g;
|
894 |
+
},
|
895 |
+
|
896 |
+
/**
|
897 |
+
* Check if item is part of current group
|
898 |
+
* @param obj item Item to check
|
899 |
+
* @return bool TRUE if item is in current group, FALSE otherwise
|
900 |
+
*/
|
901 |
+
inGroup: function(item) {
|
902 |
+
return ( this.hasGroup() && ( this.getGroup(item) == this.getGroup() ) ) ? true : false;
|
903 |
+
},
|
904 |
+
|
905 |
+
/**
|
906 |
+
* Check if group is set
|
907 |
+
* @return bool TRUE if group is set, FALSE otherwise
|
908 |
+
*/
|
909 |
+
hasGroup: function() {
|
910 |
+
return ( $.type(this.group) == 'string' && this.group.length > 0 ) ? true : false;
|
911 |
+
},
|
912 |
+
|
913 |
+
/* Slideshow */
|
914 |
+
|
915 |
+
/**
|
916 |
+
* Checks if slideshow is currently activated
|
917 |
+
* @return bool TRUE if slideshow is active, false otherwise
|
918 |
+
* @uses slideshow.active to check slideshow activation status
|
919 |
+
*/
|
920 |
+
slideshowActive: function() {
|
921 |
+
return this.slideshow.active;
|
922 |
+
},
|
923 |
+
|
924 |
+
/**
|
925 |
+
* Start the slideshow
|
926 |
+
*/
|
927 |
+
slideshowStart: function() {
|
928 |
+
this.slideshow.active = true;
|
929 |
+
var t = this;
|
930 |
+
clearInterval(this.slideshow.timer);
|
931 |
+
this.slideshow.timer = setInterval(function() { t.navNext(); t.slideshowPause(); }, this.slideshow.duration * 1000);
|
932 |
+
this.get('navSlideControl').text(this.getLabel('stopSlideshow'));
|
933 |
+
},
|
934 |
+
|
935 |
+
/**
|
936 |
+
* Stop the slideshow
|
937 |
+
*/
|
938 |
+
slideshowStop: function() {
|
939 |
+
this.slideshow.active = false;
|
940 |
+
if ( this.slideshow.timer ) {
|
941 |
+
clearInterval(this.slideshow.timer);
|
942 |
+
}
|
943 |
+
this.get('navSlideControl').text(this.getLabel('startSlideshow'));
|
944 |
+
},
|
945 |
+
|
946 |
+
/**
|
947 |
+
* Toggles the slideshow status
|
948 |
+
*/
|
949 |
+
slideshowToggle: function() {
|
950 |
+
if ( this.slideshowActive() ) {
|
951 |
+
this.slideshowStop();
|
952 |
+
} else {
|
953 |
+
this.slideshowStart();
|
954 |
+
}
|
955 |
+
},
|
956 |
+
|
957 |
+
/**
|
958 |
+
* Pauses the slideshow
|
959 |
+
* Stops the slideshow but does not change the slideshow's activation status
|
960 |
+
*/
|
961 |
+
slideshowPause: function() {
|
962 |
+
if ( this.slideshow.timer ) {
|
963 |
+
clearInterval(this.slideshow.timer);
|
964 |
+
}
|
965 |
+
},
|
966 |
+
|
967 |
+
/* Navigation */
|
968 |
+
|
969 |
+
/**
|
970 |
+
* Display appropriate previous and next hover navigation.
|
971 |
+
*/
|
972 |
+
navUpdate: function() {
|
973 |
+
if ( this.hasItems() ) {
|
974 |
+
this.get('navPrev').show();
|
975 |
+
this.get('navNext').show();
|
976 |
+
if ( this.slideshow.enabled ) {
|
977 |
+
this.get('navSlideControl').show();
|
978 |
+
if ( this.slideshowActive() ) {
|
979 |
+
this.slideshowStart();
|
980 |
+
} else {
|
981 |
+
this.slideshowStop();
|
982 |
+
}
|
983 |
+
} else {
|
984 |
+
this.get('navSlideControl').hide();
|
985 |
+
}
|
986 |
+
} else {
|
987 |
+
// Hide navigation controls when only one image exists
|
988 |
+
this.get('dataNumber').hide();
|
989 |
+
this.get('navPrev').hide();
|
990 |
+
this.get('navNext').hide();
|
991 |
+
this.get('navSlideControl').hide();
|
992 |
+
}
|
993 |
+
this.keyboardEnable();
|
994 |
+
},
|
995 |
+
|
996 |
+
/**
|
997 |
+
* Show the next image in the list
|
998 |
+
*/
|
999 |
+
navNext : function() {
|
1000 |
+
if ( this.hasItems() ) {
|
1001 |
+
if ( !this.slideshow.loop && this.itemLast() ) {
|
1002 |
+
return this.end();
|
1003 |
+
}
|
1004 |
+
if ( this.itemLast() ) {
|
1005 |
+
this.navFirst();
|
1006 |
+
} else {
|
1007 |
+
this.itemLoad(this.item_curr + 1);
|
1008 |
+
}
|
1009 |
+
}
|
1010 |
+
},
|
1011 |
+
|
1012 |
+
/**
|
1013 |
+
* Show the previous image in the list
|
1014 |
+
*/
|
1015 |
+
navPrev : function() {
|
1016 |
+
if ( this.hasItems() ) {
|
1017 |
+
if ( !this.slideshow.loop && this.itemFirst() ) {
|
1018 |
+
return this.end();
|
1019 |
+
}
|
1020 |
+
if ( this.itemFirst() ) {
|
1021 |
+
this.navLast();
|
1022 |
+
} else {
|
1023 |
+
this.itemLoad(this.item_curr - 1);
|
1024 |
+
}
|
1025 |
+
}
|
1026 |
+
},
|
1027 |
+
|
1028 |
+
/**
|
1029 |
+
* Show the first image in the list
|
1030 |
+
*/
|
1031 |
+
navFirst : function() {
|
1032 |
+
if ( this.hasItems() ) {
|
1033 |
+
this.itemLoad(0);
|
1034 |
+
}
|
1035 |
+
},
|
1036 |
+
|
1037 |
+
/**
|
1038 |
+
* Show the last image in the list
|
1039 |
+
*/
|
1040 |
+
navLast : function() {
|
1041 |
+
if ( this.hasItems() ) {
|
1042 |
+
this.itemLoad(this.items.length - 1);
|
1043 |
+
}
|
1044 |
+
},
|
1045 |
+
|
1046 |
+
/**
|
1047 |
+
* Enable image navigation via the keyboard
|
1048 |
+
*/
|
1049 |
+
keyboardEnable: function() {
|
1050 |
+
var t = this;
|
1051 |
+
$(document).keydown(function(e) {
|
1052 |
+
t.keyboardControl(e);
|
1053 |
+
});
|
1054 |
+
},
|
1055 |
+
|
1056 |
+
/**
|
1057 |
+
* Disable image navigation via the keyboard
|
1058 |
+
*/
|
1059 |
+
keyboardDisable: function() {
|
1060 |
+
$(document).unbind('keydown');
|
1061 |
+
},
|
1062 |
+
|
1063 |
+
/**
|
1064 |
+
* Handler for keyboard events
|
1065 |
+
* @param event e Keyboard event data
|
1066 |
+
*/
|
1067 |
+
keyboardControl: function(e) {
|
1068 |
+
var code = e.which;
|
1069 |
+
var key = String.fromCharCode(code).toLowerCase();
|
1070 |
+
|
1071 |
+
if ( code == 27 || key == 'x' ) {
|
1072 |
+
//Close
|
1073 |
+
this.end();
|
1074 |
+
} else if ( code == 39 || key =='n' ) {
|
1075 |
+
//Next
|
1076 |
+
this.navNext();
|
1077 |
+
} else if ( code == 37 || key == 'p' ) {
|
1078 |
+
//Previous
|
1079 |
+
this.navPrev();
|
1080 |
+
}
|
1081 |
+
},
|
1082 |
+
|
1083 |
+
/* Helpers */
|
1084 |
+
|
1085 |
+
/**
|
1086 |
+
* Generate separator text
|
1087 |
+
* @param string sep Separator text
|
1088 |
+
* @return string Separator text
|
1089 |
+
*/
|
1090 |
+
getSep: function(sep) {
|
1091 |
+
return ( typeof sep == 'undefined' ) ? '_' : sep;
|
1092 |
+
},
|
1093 |
+
|
1094 |
+
/**
|
1095 |
+
* Retrieve prefix
|
1096 |
+
* @return string Object prefix
|
1097 |
+
*/
|
1098 |
+
getPrefix: function() {
|
1099 |
+
return this.prefix;
|
1100 |
+
},
|
1101 |
+
|
1102 |
+
/**
|
1103 |
+
* Add prefix to text
|
1104 |
+
* @param string txt Text to add prefix to
|
1105 |
+
* @param string sep (optional) Separator text
|
1106 |
+
* @return string Prefixed text
|
1107 |
+
*/
|
1108 |
+
addPrefix: function(txt, sep) {
|
1109 |
+
return this.getPrefix() + this.getSep(sep) + txt;
|
1110 |
+
},
|
1111 |
+
|
1112 |
+
hasPrefix: function(txt) {
|
1113 |
+
return ( txt.indexOf(this.addPrefix('')) === 0 ) ? true : false;
|
1114 |
+
},
|
1115 |
+
|
1116 |
+
/**
|
1117 |
+
* Generate formatted ID for viewer-specific elements
|
1118 |
+
* @param string id Base ID of element
|
1119 |
+
* @return string Formatted ID
|
1120 |
+
*/
|
1121 |
+
getID: function(id) {
|
1122 |
+
return this.addPrefix(id);
|
1123 |
+
},
|
1124 |
+
|
1125 |
+
/**
|
1126 |
+
* Generate formatted selector for viewer-specific elements
|
1127 |
+
* Compares specified ID to placeholders first, then named elements
|
1128 |
+
* Multiple selectors can be included and separated by commas (',')
|
1129 |
+
* @param string id Base ID of element
|
1130 |
+
* @uses layout.placeholders to compare id to placeholder names
|
1131 |
+
* @return string Formatted selector
|
1132 |
+
*/
|
1133 |
+
getSel: function(id) {
|
1134 |
+
//Process multiple selectors
|
1135 |
+
var delim = ',', prefix = '#', sel;
|
1136 |
+
if (id.toString().indexOf(delim) != -1) {
|
1137 |
+
//Split
|
1138 |
+
var sels = id.toString().split(delim);
|
1139 |
+
//Build selector
|
1140 |
+
for (var x = 0; x < sels.length; x++) {
|
1141 |
+
sels[x] = this.getSel($.trim(sels[x]));
|
1142 |
+
}
|
1143 |
+
//Join
|
1144 |
+
sel = sels.join(delim);
|
1145 |
+
} else {
|
1146 |
+
//Single selector
|
1147 |
+
if ( id in this.layout.placeholders ) {
|
1148 |
+
var ph = $( this.layout.placeholders[id] );
|
1149 |
+
if (!ph.attr('id')) {
|
1150 |
+
//Class selector
|
1151 |
+
prefix = '.';
|
1152 |
+
}
|
1153 |
+
}
|
1154 |
+
sel = prefix + this.getID(id);
|
1155 |
+
}
|
1156 |
+
|
1157 |
+
return sel;
|
1158 |
+
},
|
1159 |
+
|
1160 |
+
/**
|
1161 |
+
* Retrieve viewer-specific element
|
1162 |
+
* @param string id Base ID of element
|
1163 |
+
* @uses getSel() to generate formatted selector for element
|
1164 |
+
* @return object jQuery object of selected element(s)
|
1165 |
+
*/
|
1166 |
+
get: function(id) {
|
1167 |
+
return $(this.getSel(id));
|
1168 |
+
},
|
1169 |
+
|
1170 |
+
/**
|
1171 |
+
* Checks if file exists using AJAX request
|
1172 |
+
* @param string url File URL
|
1173 |
+
* @param callback success Callback to run if file exists
|
1174 |
+
* @param callback failure Callback to run if file does not exist
|
1175 |
+
* @param obj args Arguments for callback
|
1176 |
+
*/
|
1177 |
+
fileExists: function(url, success, failure, args) {
|
1178 |
+
//Validate
|
1179 |
+
var t = this;
|
1180 |
+
if ( !$.isPlainObject(args) ) {
|
1181 |
+
args = null;
|
1182 |
+
}
|
1183 |
+
if ( !$.isFunction(failure) ) {
|
1184 |
+
failure = function() {
|
1185 |
+
t.end();
|
1186 |
+
};
|
1187 |
+
}
|
1188 |
+
if ( !$.isFunction(success) ) {
|
1189 |
+
success = failure;
|
1190 |
+
}
|
1191 |
+
|
1192 |
+
//Immediate success when validation disabled
|
1193 |
+
if ( !this.options.validateLinks ) {
|
1194 |
+
return success(args);
|
1195 |
+
}
|
1196 |
+
|
1197 |
+
//Validate link
|
1198 |
+
var statusFail = 400;
|
1199 |
+
var stateCheck = 4;
|
1200 |
+
var proceed = function(res) {
|
1201 |
+
if ( res.status < statusFail ) {
|
1202 |
+
success(args);
|
1203 |
+
} else {
|
1204 |
+
failure(args);
|
1205 |
+
}
|
1206 |
+
};
|
1207 |
+
|
1208 |
+
//Check if URL already processed
|
1209 |
+
if ( url in this.urls_checked ) {
|
1210 |
+
proceed(this.urls_checked[url]);
|
1211 |
+
} else {
|
1212 |
+
//Build AJAX request to check new file
|
1213 |
+
var req = new XMLHttpRequest();
|
1214 |
+
req.open('HEAD', url, true);
|
1215 |
+
req.onreadystatechange = function() {
|
1216 |
+
if ( stateCheck == this.readyState ) {
|
1217 |
+
t.addUrl(url, this);
|
1218 |
+
proceed(this);
|
1219 |
+
}
|
1220 |
+
};
|
1221 |
+
req.send();
|
1222 |
+
}
|
1223 |
+
},
|
1224 |
+
|
1225 |
+
addUrl: function(url, res) {
|
1226 |
+
if (!(url in this.urls_checked))
|
1227 |
+
this.urls_checked[url] = res;
|
1228 |
+
}
|
1229 |
+
};
|
1230 |
+
})(jQuery);
|
js/dev/lightbox.js
DELETED
@@ -1,719 +0,0 @@
|
|
1 |
-
// -----------------------------------------------------------------------------------
|
2 |
-
//
|
3 |
-
// Simple Lightbox
|
4 |
-
// by Archetyped - http://archetyped.com/tools/simple-lightbox/
|
5 |
-
// Updated: 2010-06-11
|
6 |
-
//
|
7 |
-
// Largely based on Lightbox Slideshow v1.1
|
8 |
-
// by Justin Barkhuff - http://www.justinbarkhuff.com/lab/lightbox_slideshow/
|
9 |
-
// 2007/08/15
|
10 |
-
//
|
11 |
-
// Largely based on Lightbox v2.02
|
12 |
-
// by Lokesh Dhakar - http://huddletogether.com/projects/lightbox2/
|
13 |
-
// 2006/03/31
|
14 |
-
//
|
15 |
-
// Licensed under the Creative Commons Attribution 2.5 License - http://creativecommons.org/licenses/by/2.5/
|
16 |
-
//
|
17 |
-
// The code inserts html at the bottom of the page that looks similar to this:
|
18 |
-
//
|
19 |
-
// <div id="overlay"></div>
|
20 |
-
// <div id="lightbox">
|
21 |
-
// <div id="outerImageContainer">
|
22 |
-
// <div id="imageContainer">
|
23 |
-
// <img id="lightboxImage" />
|
24 |
-
// <div id="hoverNav">
|
25 |
-
// <a href="javascript:void(0);" id="prevLinkImg">« prev</a>
|
26 |
-
// <a href="javascript:void(0);" id="nextLinkImg">next »</a>
|
27 |
-
// </div>
|
28 |
-
// <div id="loading">
|
29 |
-
// <a href="javascript:void(0);" id="loadingLink">loading</a>
|
30 |
-
// </div>
|
31 |
-
// </div>
|
32 |
-
// </div>
|
33 |
-
// <div id="imageDataContainer">
|
34 |
-
// <div id="imageData">
|
35 |
-
// <div id="imageDetails">
|
36 |
-
// <span id="caption"></span>
|
37 |
-
// <span id="numberDisplay"></span>
|
38 |
-
// <span id="detailsNav">
|
39 |
-
// <a id="prevLinkDetails" href="javascript:void(0);">« prev</a>
|
40 |
-
// <a id="nextLinkDetails" href="javascript:void(0);">next »</a>
|
41 |
-
// <a id="slideShowControl" href="javascript:void(0);">stop slideshow</a>
|
42 |
-
// </span>
|
43 |
-
// </div>
|
44 |
-
// <div id="close">
|
45 |
-
// <a id="closeLink" href="javascript:void(0);">close</a>
|
46 |
-
// </div>
|
47 |
-
// </div>
|
48 |
-
// </div>
|
49 |
-
// </div>
|
50 |
-
//
|
51 |
-
// -----------------------------------------------------------------------------------
|
52 |
-
|
53 |
-
//
|
54 |
-
// Lightbox Object
|
55 |
-
//
|
56 |
-
|
57 |
-
var Lightbox = {
|
58 |
-
activeImage : null,
|
59 |
-
badObjects : ['select','object','embed'],
|
60 |
-
container : null,
|
61 |
-
enableSlideshow : null,
|
62 |
-
groupName : null,
|
63 |
-
imageArray : [],
|
64 |
-
options : null,
|
65 |
-
overlayDuration : null,
|
66 |
-
overlayOpacity : null,
|
67 |
-
playSlides : null,
|
68 |
-
refTags : ['a','area'],
|
69 |
-
relAttribute : null,
|
70 |
-
resizeDuration : null,
|
71 |
-
slideShowTimer : null,
|
72 |
-
startImage : null,
|
73 |
-
|
74 |
-
//
|
75 |
-
// initialize()
|
76 |
-
// Constructor sets class properties and configuration options and
|
77 |
-
// inserts html at the bottom of the page which is used to display the shadow
|
78 |
-
// overlay and the image container.
|
79 |
-
//
|
80 |
-
initialize: function(options) {
|
81 |
-
if (!document.getElementsByTagName){ return; }
|
82 |
-
|
83 |
-
this.options = $H({
|
84 |
-
animate : true, // resizing animations
|
85 |
-
autoPlay : true, // should slideshow start automatically
|
86 |
-
borderSize : 10, // if you adjust the padding in the CSS, you will need to update this variable
|
87 |
-
containerID : document, // lightbox container object
|
88 |
-
enableSlideshow : true, // enable slideshow feature
|
89 |
-
googleAnalytics : false, // track individual image views using Google Analytics
|
90 |
-
imageDataLocation : 'south', // location of image caption information
|
91 |
-
initImage : '', // ID of image link to automatically launch when upon script initialization
|
92 |
-
loop : true, // whether to continuously loop slideshow images
|
93 |
-
overlayDuration : .2, // time to fade in shadow overlay
|
94 |
-
overlayOpacity : .8, // transparency of shadow overlay
|
95 |
-
prefix : '', // ID prefix for all dynamically created html elements
|
96 |
-
relAttribute : 'lightbox', // specifies the rel attribute value that triggers lightbox
|
97 |
-
resizeSpeed : 7, // controls the speed of the image resizing (1=slowest and 10=fastest)
|
98 |
-
showGroupName : false, // show group name of images in image details
|
99 |
-
slideTime : 4, // time to display images during slideshow
|
100 |
-
strings : { // allows for localization
|
101 |
-
closeLink : 'close',
|
102 |
-
loadingMsg : 'loading',
|
103 |
-
nextLink : 'next »',
|
104 |
-
prevLink : '« prev',
|
105 |
-
startSlideshow : 'start slideshow',
|
106 |
-
stopSlideshow : 'stop slideshow',
|
107 |
-
numDisplayPrefix : 'Image',
|
108 |
-
numDisplaySeparator : 'of'
|
109 |
-
}
|
110 |
-
}).merge(options);
|
111 |
-
|
112 |
-
if(this.options.animate){
|
113 |
-
this.overlayDuration = Math.max(this.options.overlayDuration,0);
|
114 |
-
this.options.resizeSpeed = Math.max(Math.min(this.options.resizeSpeed,10),1);
|
115 |
-
this.resizeDuration = (11 - this.options.resizeSpeed) * 0.15;
|
116 |
-
}else{
|
117 |
-
this.overlayDuration = 0;
|
118 |
-
this.resizeDuration = 0;
|
119 |
-
}
|
120 |
-
|
121 |
-
this.enableSlideshow = this.options.enableSlideshow;
|
122 |
-
this.overlayOpacity = Math.max(Math.min(this.options.overlayOpacity,1),0);
|
123 |
-
this.playSlides = this.options.autoPlay;
|
124 |
-
this.container = $(this.options.containerID);
|
125 |
-
this.relAttribute = this.options.relAttribute;
|
126 |
-
this.updateImageList();
|
127 |
-
|
128 |
-
var objBody = this.container != document ? this.container : document.getElementsByTagName('body').item(0);
|
129 |
-
|
130 |
-
var objOverlay = document.createElement('div');
|
131 |
-
objOverlay.setAttribute('id',this.getID('overlay'));
|
132 |
-
objOverlay.style.display = 'none';
|
133 |
-
objBody.appendChild(objOverlay);
|
134 |
-
Event.observe(objOverlay,'click',this.end.bindAsEventListener(this));
|
135 |
-
|
136 |
-
var objLightbox = document.createElement('div');
|
137 |
-
objLightbox.setAttribute('id',this.getID('lightbox'));
|
138 |
-
objLightbox.style.display = 'none';
|
139 |
-
objBody.appendChild(objLightbox);
|
140 |
-
|
141 |
-
var objImageDataContainer = document.createElement('div');
|
142 |
-
objImageDataContainer.setAttribute('id',this.getID('imageDataContainer'));
|
143 |
-
objImageDataContainer.className = this.getID('clearfix');
|
144 |
-
|
145 |
-
var objImageData = document.createElement('div');
|
146 |
-
objImageData.setAttribute('id',this.getID('imageData'));
|
147 |
-
objImageDataContainer.appendChild(objImageData);
|
148 |
-
|
149 |
-
var objImageDetails = document.createElement('div');
|
150 |
-
objImageDetails.setAttribute('id',this.getID('imageDetails'));
|
151 |
-
objImageData.appendChild(objImageDetails);
|
152 |
-
|
153 |
-
var objCaption = document.createElement('span');
|
154 |
-
objCaption.setAttribute('id',this.getID('caption'));
|
155 |
-
objImageDetails.appendChild(objCaption);
|
156 |
-
|
157 |
-
var objNumberDisplay = document.createElement('span');
|
158 |
-
objNumberDisplay.setAttribute('id',this.getID('numberDisplay'));
|
159 |
-
objImageDetails.appendChild(objNumberDisplay);
|
160 |
-
|
161 |
-
var objDetailsNav = document.createElement('span');
|
162 |
-
objDetailsNav.setAttribute('id',this.getID('detailsNav'));
|
163 |
-
objImageDetails.appendChild(objDetailsNav);
|
164 |
-
|
165 |
-
var objPrevLink = document.createElement('a');
|
166 |
-
objPrevLink.setAttribute('id',this.getID('prevLinkDetails'));
|
167 |
-
objPrevLink.setAttribute('href','javascript:void(0);');
|
168 |
-
objPrevLink.innerHTML = this.options.strings.prevLink;
|
169 |
-
objDetailsNav.appendChild(objPrevLink);
|
170 |
-
Event.observe(objPrevLink,'click',this.showPrev.bindAsEventListener(this));
|
171 |
-
|
172 |
-
var objNextLink = document.createElement('a');
|
173 |
-
objNextLink.setAttribute('id',this.getID('nextLinkDetails'));
|
174 |
-
objNextLink.setAttribute('href','javascript:void(0);');
|
175 |
-
objNextLink.innerHTML = this.options.strings.nextLink;
|
176 |
-
objDetailsNav.appendChild(objNextLink);
|
177 |
-
Event.observe(objNextLink,'click',this.showNext.bindAsEventListener(this));
|
178 |
-
|
179 |
-
var objSlideShowControl = document.createElement('a');
|
180 |
-
objSlideShowControl.setAttribute('id',this.getID('slideShowControl'));
|
181 |
-
objSlideShowControl.setAttribute('href','javascript:void(0);');
|
182 |
-
objDetailsNav.appendChild(objSlideShowControl);
|
183 |
-
Event.observe(objSlideShowControl,'click',this.toggleSlideShow.bindAsEventListener(this));
|
184 |
-
|
185 |
-
var objClose = document.createElement('div');
|
186 |
-
objClose.setAttribute('id',this.getID('close'));
|
187 |
-
objImageData.appendChild(objClose);
|
188 |
-
|
189 |
-
var objCloseLink = document.createElement('a');
|
190 |
-
objCloseLink.setAttribute('id',this.getID('closeLink'));
|
191 |
-
objCloseLink.setAttribute('href','javascript:void(0);');
|
192 |
-
objCloseLink.innerHTML = this.options.strings.closeLink;
|
193 |
-
objClose.appendChild(objCloseLink);
|
194 |
-
Event.observe(objCloseLink,'click',this.end.bindAsEventListener(this));
|
195 |
-
|
196 |
-
if(this.options.imageDataLocation == 'north'){
|
197 |
-
objLightbox.appendChild(objImageDataContainer);
|
198 |
-
}
|
199 |
-
|
200 |
-
var objOuterImageContainer = document.createElement('div');
|
201 |
-
objOuterImageContainer.setAttribute('id',this.getID('outerImageContainer'));
|
202 |
-
objLightbox.appendChild(objOuterImageContainer);
|
203 |
-
|
204 |
-
var objImageContainer = document.createElement('div');
|
205 |
-
objImageContainer.setAttribute('id',this.getID('imageContainer'));
|
206 |
-
objOuterImageContainer.appendChild(objImageContainer);
|
207 |
-
|
208 |
-
var objLightboxImage = document.createElement('img');
|
209 |
-
objLightboxImage.setAttribute('id',this.getID('lightboxImage'));
|
210 |
-
objImageContainer.appendChild(objLightboxImage);
|
211 |
-
|
212 |
-
var objHoverNav = document.createElement('div');
|
213 |
-
objHoverNav.setAttribute('id',this.getID('hoverNav'));
|
214 |
-
objImageContainer.appendChild(objHoverNav);
|
215 |
-
|
216 |
-
var objPrevLinkImg = document.createElement('a');
|
217 |
-
objPrevLinkImg.setAttribute('id',this.getID('prevLinkImg'));
|
218 |
-
objPrevLinkImg.setAttribute('href','javascript:void(0);');
|
219 |
-
objHoverNav.appendChild(objPrevLinkImg);
|
220 |
-
Event.observe(objPrevLinkImg,'click',this.showPrev.bindAsEventListener(this));
|
221 |
-
|
222 |
-
var objNextLinkImg = document.createElement('a');
|
223 |
-
objNextLinkImg.setAttribute('id',this.getID('nextLinkImg'));
|
224 |
-
objNextLinkImg.setAttribute('href','javascript:void(0);');
|
225 |
-
objHoverNav.appendChild(objNextLinkImg);
|
226 |
-
Event.observe(objNextLinkImg,'click',this.showNext.bindAsEventListener(this));
|
227 |
-
|
228 |
-
var objLoading = document.createElement('div');
|
229 |
-
objLoading.setAttribute('id',this.getID('loading'));
|
230 |
-
objImageContainer.appendChild(objLoading);
|
231 |
-
|
232 |
-
var objLoadingLink = document.createElement('a');
|
233 |
-
objLoadingLink.setAttribute('id',this.getID('loadingLink'));
|
234 |
-
objLoadingLink.setAttribute('href','javascript:void(0);');
|
235 |
-
objLoadingLink.innerHTML = this.options.strings.loadingMsg;
|
236 |
-
objLoading.appendChild(objLoadingLink);
|
237 |
-
Event.observe(objLoadingLink,'click',this.end.bindAsEventListener(this));
|
238 |
-
|
239 |
-
if(this.options.imageDataLocation != 'north'){
|
240 |
-
objLightbox.appendChild(objImageDataContainer);
|
241 |
-
}
|
242 |
-
|
243 |
-
if(this.options.initImage != ''){
|
244 |
-
this.start($(this.options.initImage));
|
245 |
-
}
|
246 |
-
},
|
247 |
-
|
248 |
-
//
|
249 |
-
// updateImageList()
|
250 |
-
// Loops through specific tags within 'container' looking for
|
251 |
-
// 'lightbox' references and applies onclick events to them.
|
252 |
-
//
|
253 |
-
updateImageList: function(){
|
254 |
-
var el, els, rel;
|
255 |
-
for(var i=0; i < this.refTags.length; i++){
|
256 |
-
els = this.container.getElementsByTagName(this.refTags[i]);
|
257 |
-
for(var j=0; j < els.length; j++){
|
258 |
-
el = els[j];
|
259 |
-
rel = String(el.getAttribute('rel'));
|
260 |
-
if (el.getAttribute('href') && (rel.toLowerCase().match(this.relAttribute))){
|
261 |
-
el.onclick = function(){Lightbox.start(this); return false;}
|
262 |
-
}
|
263 |
-
}
|
264 |
-
}
|
265 |
-
},
|
266 |
-
|
267 |
-
getCaption: function(imageLink) {
|
268 |
-
var caption = imageLink.title || '';
|
269 |
-
if ( caption == '' ) {
|
270 |
-
var inner = $(imageLink).getElementsBySelector('img').first();
|
271 |
-
if ( inner )
|
272 |
-
caption = inner.getAttribute('title') || inner.getAttribute('alt');
|
273 |
-
if ( !caption )
|
274 |
-
caption = imageLink.innerHTML.stripTags() || imageLink.href || '';
|
275 |
-
}
|
276 |
-
return caption;
|
277 |
-
},
|
278 |
-
|
279 |
-
//
|
280 |
-
// start()
|
281 |
-
// Display overlay and lightbox. If image is part of a set, add siblings to imageArray.
|
282 |
-
//
|
283 |
-
start: function(imageLink) {
|
284 |
-
|
285 |
-
this.hideBadObjects();
|
286 |
-
|
287 |
-
// stretch overlay to fill page and fade in
|
288 |
-
var pageSize = this.getPageSize();
|
289 |
-
$(this.getID('overlay')).setStyle({height:pageSize.pageHeight+'px'});
|
290 |
-
new Effect.Appear(this.getID('overlay'), { duration: this.overlayDuration, from: 0, to: this.overlayOpacity });
|
291 |
-
|
292 |
-
this.imageArray = [];
|
293 |
-
this.groupName = null;
|
294 |
-
|
295 |
-
var rel = imageLink.getAttribute('rel');
|
296 |
-
var imageTitle = '';
|
297 |
-
|
298 |
-
// if image is NOT part of a group..
|
299 |
-
if(rel == this.relAttribute){
|
300 |
-
// add single image to imageArray
|
301 |
-
imageTitle = this.getCaption(imageLink);
|
302 |
-
this.imageArray.push({'link':imageLink.getAttribute('href'), 'title':imageTitle});
|
303 |
-
this.startImage = 0;
|
304 |
-
} else {
|
305 |
-
// if image is part of a group..
|
306 |
-
var els = this.container.getElementsByTagName(imageLink.tagName);
|
307 |
-
// loop through anchors, find other images in group, and add them to imageArray
|
308 |
-
for (var i=0; i<els.length; i++){
|
309 |
-
var el = els[i];
|
310 |
-
if (el.getAttribute('href') && (el.getAttribute('rel') == rel)){
|
311 |
-
imageTitle = this.getCaption(el);
|
312 |
-
this.imageArray.push({'link':el.getAttribute('href'),'title':imageTitle});
|
313 |
-
if(el == imageLink){
|
314 |
-
this.startImage = this.imageArray.length-1;
|
315 |
-
}
|
316 |
-
}
|
317 |
-
}
|
318 |
-
// get group name
|
319 |
-
this.groupName = rel.substring(this.relAttribute.length+1,rel.length-1);
|
320 |
-
}
|
321 |
-
|
322 |
-
// calculate top offset for the lightbox and display
|
323 |
-
var pageScroll = this.getPageScroll();
|
324 |
-
var lightboxTop = pageScroll.y + (pageSize.winHeight / 15);
|
325 |
-
|
326 |
-
$(this.getID('lightbox')).setStyle({top:lightboxTop+'px'}).show();
|
327 |
-
this.changeImage(this.startImage);
|
328 |
-
},
|
329 |
-
|
330 |
-
//
|
331 |
-
// changeImage()
|
332 |
-
// Hide most elements and preload image in preparation for resizing image container.
|
333 |
-
//
|
334 |
-
changeImage: function(imageNum){
|
335 |
-
this.activeImage = imageNum;
|
336 |
-
|
337 |
-
this.disableKeyboardNav();
|
338 |
-
this.pauseSlideShow();
|
339 |
-
|
340 |
-
// hide elements during transition
|
341 |
-
$(this.getID('loading')).show();
|
342 |
-
$(this.getID('lightboxImage')).hide();
|
343 |
-
$(this.getID('hoverNav')).hide();
|
344 |
-
$(this.getID('imageDataContainer')).hide();
|
345 |
-
$(this.getID('numberDisplay')).hide();
|
346 |
-
$(this.getID('detailsNav')).hide();
|
347 |
-
|
348 |
-
var imgPreloader = new Image();
|
349 |
-
|
350 |
-
// once image is preloaded, resize image container
|
351 |
-
imgPreloader.onload=function(){
|
352 |
-
$(Lightbox.getID('lightboxImage')).src = imgPreloader.src;
|
353 |
-
Lightbox.resizeImageContainer(imgPreloader.width,imgPreloader.height);
|
354 |
-
}
|
355 |
-
imgPreloader.src = this.imageArray[this.activeImage].link;
|
356 |
-
|
357 |
-
if(this.options.googleAnalytics){
|
358 |
-
urchinTracker(this.imageArray[this.activeImage].link);
|
359 |
-
}
|
360 |
-
},
|
361 |
-
|
362 |
-
//
|
363 |
-
// resizeImageContainer()
|
364 |
-
//
|
365 |
-
resizeImageContainer: function(imgWidth,imgHeight) {
|
366 |
-
// get current height and width
|
367 |
-
var cDims = $(this.getID('outerImageContainer')).getDimensions();
|
368 |
-
|
369 |
-
// scalars based on change from old to new
|
370 |
-
var xScale = ((imgWidth + (this.options.borderSize * 2)) / cDims.width) * 100;
|
371 |
-
var yScale = ((imgHeight + (this.options.borderSize * 2)) / cDims.height) * 100;
|
372 |
-
|
373 |
-
// calculate size difference between new and old image, and resize if necessary
|
374 |
-
var wDiff = (cDims.width - this.options.borderSize * 2) - imgWidth;
|
375 |
-
var hDiff = (cDims.height - this.options.borderSize * 2) - imgHeight;
|
376 |
-
|
377 |
-
if(!( hDiff == 0)){ new Effect.Scale(this.getID('outerImageContainer'), yScale, {scaleX: false, duration: this.resizeDuration, queue: 'front'}); }
|
378 |
-
if(!( wDiff == 0)){ new Effect.Scale(this.getID('outerImageContainer'), xScale, {scaleY: false, delay: this.resizeDuration, duration: this.resizeDuration}); }
|
379 |
-
|
380 |
-
// if new and old image are same size and no scaling transition is necessary,
|
381 |
-
// do a quick pause to prevent image flicker.
|
382 |
-
if((hDiff == 0) && (wDiff == 0)){
|
383 |
-
if(navigator.appVersion.indexOf('MSIE')!=-1){ this.pause(250); } else { this.pause(100);}
|
384 |
-
}
|
385 |
-
|
386 |
-
$(this.getID('prevLinkImg')).setStyle({height:imgHeight+'px'});
|
387 |
-
$(this.getID('nextLinkImg')).setStyle({height:imgHeight+'px'});
|
388 |
-
$(this.getID('imageDataContainer')).setStyle({width:(imgWidth+(this.options.borderSize * 2))+'px'});
|
389 |
-
|
390 |
-
this.showImage();
|
391 |
-
},
|
392 |
-
|
393 |
-
//
|
394 |
-
// showImage()
|
395 |
-
// Display image and begin preloading neighbors.
|
396 |
-
//
|
397 |
-
showImage: function(){
|
398 |
-
$(this.getID('loading')).hide();
|
399 |
-
new Effect.Appear(this.getID('lightboxImage'), { duration: 0.5, queue: 'end', afterFinish: function(){ Lightbox.updateDetails(); } });
|
400 |
-
this.preloadNeighborImages();
|
401 |
-
},
|
402 |
-
|
403 |
-
//
|
404 |
-
// updateDetails()
|
405 |
-
// Display caption, image number, and bottom nav.
|
406 |
-
//
|
407 |
-
updateDetails: function() {
|
408 |
-
$(this.getID('caption')).show();
|
409 |
-
$(this.getID('caption')).update(this.imageArray[this.activeImage].title);
|
410 |
-
|
411 |
-
// if image is part of set display 'Image x of y'
|
412 |
-
if(this.imageArray.length > 1){
|
413 |
-
var num_display = this.options.strings.numDisplayPrefix + ' ' + eval(this.activeImage + 1) + ' ' + this.options.strings.numDisplaySeparator + ' ' + this.imageArray.length;
|
414 |
-
if(this.options.showGroupName && this.groupName != ''){
|
415 |
-
num_display += ' '+this.options.strings.numDisplaySeparator+' '+this.groupName;
|
416 |
-
}
|
417 |
-
$(this.getID('numberDisplay')).update(num_display).show();
|
418 |
-
if(!this.enableSlideshow){
|
419 |
-
$(this.getID('slideShowControl')).hide();
|
420 |
-
}
|
421 |
-
$(this.getID('detailsNav')).show();
|
422 |
-
}
|
423 |
-
|
424 |
-
new Effect.Parallel(
|
425 |
-
[ new Effect.SlideDown( this.getID('imageDataContainer'), { sync: true }),
|
426 |
-
new Effect.Appear(this.getID('imageDataContainer'), { sync: true }) ],
|
427 |
-
{ duration:.65, afterFinish: function() { Lightbox.updateNav();} }
|
428 |
-
);
|
429 |
-
},
|
430 |
-
|
431 |
-
//
|
432 |
-
// updateNav()
|
433 |
-
// Display appropriate previous and next hover navigation.
|
434 |
-
//
|
435 |
-
updateNav: function() {
|
436 |
-
if(this.imageArray.length > 1){
|
437 |
-
$(this.getID('hoverNav')).show();
|
438 |
-
if(this.enableSlideshow){
|
439 |
-
if(this.playSlides){
|
440 |
-
this.startSlideShow();
|
441 |
-
} else {
|
442 |
-
this.stopSlideShow();
|
443 |
-
}
|
444 |
-
}
|
445 |
-
}
|
446 |
-
this.enableKeyboardNav();
|
447 |
-
},
|
448 |
-
//
|
449 |
-
// startSlideShow()
|
450 |
-
// Starts the slide show
|
451 |
-
//
|
452 |
-
startSlideShow: function(){
|
453 |
-
this.playSlides = true;
|
454 |
-
this.slideShowTimer = new PeriodicalExecuter(function(pe){ Lightbox.showNext(); pe.stop(); },this.options.slideTime);
|
455 |
-
$(this.getID('slideShowControl')).update(this.options.strings.stopSlideshow);
|
456 |
-
},
|
457 |
-
|
458 |
-
//
|
459 |
-
// stopSlideShow()
|
460 |
-
// Stops the slide show
|
461 |
-
//
|
462 |
-
stopSlideShow: function(){
|
463 |
-
this.playSlides = false;
|
464 |
-
if(this.slideShowTimer){
|
465 |
-
this.slideShowTimer.stop();
|
466 |
-
}
|
467 |
-
$(this.getID('slideShowControl')).update(this.options.strings.startSlideshow);
|
468 |
-
},
|
469 |
-
|
470 |
-
//
|
471 |
-
// stopSlideShow()
|
472 |
-
// Stops the slide show
|
473 |
-
//
|
474 |
-
toggleSlideShow: function(){
|
475 |
-
if(this.playSlides){
|
476 |
-
this.stopSlideShow();
|
477 |
-
}else{
|
478 |
-
this.startSlideShow();
|
479 |
-
}
|
480 |
-
},
|
481 |
-
|
482 |
-
//
|
483 |
-
// pauseSlideShow()
|
484 |
-
// Pauses the slide show (doesn't change the value of this.playSlides)
|
485 |
-
//
|
486 |
-
pauseSlideShow: function(){
|
487 |
-
if(this.slideShowTimer){
|
488 |
-
this.slideShowTimer.stop();
|
489 |
-
}
|
490 |
-
},
|
491 |
-
|
492 |
-
//
|
493 |
-
// showNext()
|
494 |
-
// Display the next image in a group
|
495 |
-
//
|
496 |
-
showNext : function(){
|
497 |
-
if(this.imageArray.length > 1){
|
498 |
-
if(!this.options.loop && ((this.activeImage == this.imageArray.length - 1 && this.startImage == 0) || (this.activeImage+1 == this.startImage))){
|
499 |
-
return this.end();
|
500 |
-
}
|
501 |
-
if(this.activeImage == this.imageArray.length - 1){
|
502 |
-
this.changeImage(0);
|
503 |
-
}else{
|
504 |
-
this.changeImage(this.activeImage+1);
|
505 |
-
}
|
506 |
-
}
|
507 |
-
},
|
508 |
-
|
509 |
-
//
|
510 |
-
// showPrev()
|
511 |
-
// Display the next image in a group
|
512 |
-
//
|
513 |
-
showPrev : function(){
|
514 |
-
if(this.imageArray.length > 1){
|
515 |
-
if(this.activeImage == 0){
|
516 |
-
this.changeImage(this.imageArray.length - 1);
|
517 |
-
}else{
|
518 |
-
this.changeImage(this.activeImage-1);
|
519 |
-
}
|
520 |
-
}
|
521 |
-
},
|
522 |
-
|
523 |
-
//
|
524 |
-
// showFirst()
|
525 |
-
// Display the first image in a group
|
526 |
-
//
|
527 |
-
showFirst : function(){
|
528 |
-
if(this.imageArray.length > 1){
|
529 |
-
this.changeImage(0);
|
530 |
-
}
|
531 |
-
},
|
532 |
-
|
533 |
-
//
|
534 |
-
// showFirst()
|
535 |
-
// Display the first image in a group
|
536 |
-
//
|
537 |
-
showLast : function(){
|
538 |
-
if(this.imageArray.length > 1){
|
539 |
-
this.changeImage(this.imageArray.length - 1);
|
540 |
-
}
|
541 |
-
},
|
542 |
-
|
543 |
-
//
|
544 |
-
// enableKeyboardNav()
|
545 |
-
//
|
546 |
-
enableKeyboardNav: function() {
|
547 |
-
document.onkeydown = this.keyboardAction;
|
548 |
-
},
|
549 |
-
|
550 |
-
//
|
551 |
-
// disableKeyboardNav()
|
552 |
-
//
|
553 |
-
disableKeyboardNav: function() {
|
554 |
-
document.onkeydown = '';
|
555 |
-
},
|
556 |
-
|
557 |
-
//
|
558 |
-
// keyboardAction()
|
559 |
-
//
|
560 |
-
keyboardAction: function(e) {
|
561 |
-
if (e == null) { // ie
|
562 |
-
keycode = event.keyCode;
|
563 |
-
} else { // mozilla
|
564 |
-
keycode = e.which;
|
565 |
-
}
|
566 |
-
|
567 |
-
key = String.fromCharCode(keycode).toLowerCase();
|
568 |
-
|
569 |
-
if(key == 'x' || key == 'o' || key == 'c'){ // close lightbox
|
570 |
-
Lightbox.end();
|
571 |
-
} else if(key == 'p' || key == '%'){ // display previous image
|
572 |
-
Lightbox.showPrev();
|
573 |
-
} else if(key == 'n' || key =='\''){ // display next image
|
574 |
-
Lightbox.showNext();
|
575 |
-
} else if(key == 'f'){ // display first image
|
576 |
-
Lightbox.showFirst();
|
577 |
-
} else if(key == 'l'){ // display last image
|
578 |
-
Lightbox.showLast();
|
579 |
-
} else if(key == 's'){ // toggle slideshow
|
580 |
-
if(Lightbox.imageArray.length > 0 && Lightbox.options.enableSlideshow){
|
581 |
-
Lightbox.toggleSlideShow();
|
582 |
-
}
|
583 |
-
}
|
584 |
-
},
|
585 |
-
|
586 |
-
//
|
587 |
-
// preloadNeighborImages()
|
588 |
-
// Preload previous and next images.
|
589 |
-
//
|
590 |
-
preloadNeighborImages: function(){
|
591 |
-
var nextImageID = this.imageArray.length - 1 == this.activeImage ? 0 : this.activeImage + 1;
|
592 |
-
nextImage = new Image();
|
593 |
-
nextImage.src = this.imageArray[nextImageID].link
|
594 |
-
|
595 |
-
var prevImageID = this.activeImage == 0 ? this.imageArray.length - 1 : this.activeImage - 1;
|
596 |
-
prevImage = new Image();
|
597 |
-
prevImage.src = this.imageArray[prevImageID].link;
|
598 |
-
},
|
599 |
-
|
600 |
-
//
|
601 |
-
// end()
|
602 |
-
//
|
603 |
-
end: function() {
|
604 |
-
this.disableKeyboardNav();
|
605 |
-
this.pauseSlideShow();
|
606 |
-
$(this.getID('lightbox')).hide();
|
607 |
-
new Effect.Fade(this.getID('overlay'), { duration:this.overlayDuration });
|
608 |
-
this.showBadObjects();
|
609 |
-
},
|
610 |
-
|
611 |
-
//
|
612 |
-
// showBadObjects()
|
613 |
-
//
|
614 |
-
showBadObjects: function (){
|
615 |
-
var els;
|
616 |
-
var tags = Lightbox.badObjects;
|
617 |
-
for(var i=0; i<tags.length; i++){
|
618 |
-
els = document.getElementsByTagName(tags[i]);
|
619 |
-
for(var j=0; j<els.length; j++){
|
620 |
-
$(els[j]).setStyle({visibility:'visible'});
|
621 |
-
}
|
622 |
-
}
|
623 |
-
},
|
624 |
-
|
625 |
-
//
|
626 |
-
// hideBadObjects()
|
627 |
-
//
|
628 |
-
hideBadObjects: function (){
|
629 |
-
var els;
|
630 |
-
var tags = Lightbox.badObjects;
|
631 |
-
for(var i=0; i<tags.length; i++){
|
632 |
-
els = document.getElementsByTagName(tags[i]);
|
633 |
-
for(var j=0; j<els.length; j++){
|
634 |
-
$(els[j]).setStyle({visibility:'hidden'});
|
635 |
-
}
|
636 |
-
}
|
637 |
-
},
|
638 |
-
|
639 |
-
//
|
640 |
-
// pause(numberMillis)
|
641 |
-
// Pauses code execution for specified time. Uses busy code, not good.
|
642 |
-
// Code from http://www.faqts.com/knowledge_base/view.phtml/aid/1602
|
643 |
-
//
|
644 |
-
pause: function(numberMillis) {
|
645 |
-
var now = new Date();
|
646 |
-
var exitTime = now.getTime() + numberMillis;
|
647 |
-
while(true){
|
648 |
-
now = new Date();
|
649 |
-
if (now.getTime() > exitTime)
|
650 |
-
return;
|
651 |
-
}
|
652 |
-
},
|
653 |
-
|
654 |
-
//
|
655 |
-
// getPageScroll()
|
656 |
-
// Returns array with x,y page scroll values.
|
657 |
-
// Core code from - quirksmode.org
|
658 |
-
//
|
659 |
-
getPageScroll: function(){
|
660 |
-
var x,y;
|
661 |
-
if (self.pageYOffset) {
|
662 |
-
x = self.pageXOffset;
|
663 |
-
y = self.pageYOffset;
|
664 |
-
} else if (document.documentElement && document.documentElement.scrollTop){ // Explorer 6 Strict
|
665 |
-
x = document.documentElement.scrollLeft;
|
666 |
-
y = document.documentElement.scrollTop;
|
667 |
-
} else if (document.body) {// all other Explorers
|
668 |
-
x = document.body.scrollLeft;
|
669 |
-
y = document.body.scrollTop;
|
670 |
-
}
|
671 |
-
return {x:x,y:y};
|
672 |
-
},
|
673 |
-
|
674 |
-
//
|
675 |
-
// getPageSize()
|
676 |
-
// Returns array with page width, height and window width, height
|
677 |
-
// Core code from - quirksmode.org
|
678 |
-
// Edit for Firefox by pHaez
|
679 |
-
//
|
680 |
-
getPageSize: function(){
|
681 |
-
var scrollX,scrollY,windowX,windowY,pageX,pageY;
|
682 |
-
if (window.innerHeight && window.scrollMaxY) {
|
683 |
-
scrollX = document.body.scrollWidth;
|
684 |
-
scrollY = window.innerHeight + window.scrollMaxY;
|
685 |
-
} else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
|
686 |
-
scrollX = document.body.scrollWidth;
|
687 |
-
scrollY = document.body.scrollHeight;
|
688 |
-
} else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
|
689 |
-
scrollX = document.body.offsetWidth;
|
690 |
-
scrollY = document.body.offsetHeight;
|
691 |
-
}
|
692 |
-
|
693 |
-
if (self.innerHeight) { // all except Explorer
|
694 |
-
windowX = self.innerWidth;
|
695 |
-
windowY = self.innerHeight;
|
696 |
-
} else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
|
697 |
-
windowX = document.documentElement.clientWidth;
|
698 |
-
windowY = document.documentElement.clientHeight;
|
699 |
-
} else if (document.body) { // other Explorers
|
700 |
-
windowX = document.body.clientWidth;
|
701 |
-
windowY = document.body.clientHeight;
|
702 |
-
}
|
703 |
-
|
704 |
-
pageY = (scrollY < windowY) ? windowY : scrollY; // for small pages with total height less then height of the viewport
|
705 |
-
pageX = (scrollX < windowX) ? windowX : scrollX; // for small pages with total width less then width of the viewport
|
706 |
-
|
707 |
-
return {pageWidth:pageX,pageHeight:pageY,winWidth:windowX,winHeight:windowY};
|
708 |
-
},
|
709 |
-
|
710 |
-
//
|
711 |
-
// getID()
|
712 |
-
// Returns formatted Lightbox element ID
|
713 |
-
//
|
714 |
-
getID: function(id){
|
715 |
-
return this.options.prefix+id;
|
716 |
-
}
|
717 |
-
}
|
718 |
-
|
719 |
-
// -----------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
js/dev/prototype.js
DELETED
@@ -1,3271 +0,0 @@
|
|
1 |
-
/* Prototype JavaScript framework, version 1.5.1
|
2 |
-
* (c) 2005-2007 Sam Stephenson
|
3 |
-
*
|
4 |
-
* Prototype is freely distributable under the terms of an MIT-style license.
|
5 |
-
* For details, see the Prototype web site: http://www.prototypejs.org/
|
6 |
-
*
|
7 |
-
/*--------------------------------------------------------------------------*/
|
8 |
-
|
9 |
-
var Prototype = {
|
10 |
-
Version: '1.5.1',
|
11 |
-
|
12 |
-
Browser: {
|
13 |
-
IE: !!(window.attachEvent && !window.opera),
|
14 |
-
Opera: !!window.opera,
|
15 |
-
WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
|
16 |
-
Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1
|
17 |
-
},
|
18 |
-
|
19 |
-
BrowserFeatures: {
|
20 |
-
XPath: !!document.evaluate,
|
21 |
-
ElementExtensions: !!window.HTMLElement,
|
22 |
-
SpecificElementExtensions:
|
23 |
-
(document.createElement('div').__proto__ !==
|
24 |
-
document.createElement('form').__proto__)
|
25 |
-
},
|
26 |
-
|
27 |
-
ScriptFragment: '<script[^>]*>([\u0001-\uFFFF]*?)</script>',
|
28 |
-
JSONFilter: /^\/\*-secure-\s*(.*)\s*\*\/\s*$/,
|
29 |
-
|
30 |
-
emptyFunction: function() { },
|
31 |
-
K: function(x) { return x }
|
32 |
-
}
|
33 |
-
|
34 |
-
var Class = {
|
35 |
-
create: function() {
|
36 |
-
return function() {
|
37 |
-
this.initialize.apply(this, arguments);
|
38 |
-
}
|
39 |
-
}
|
40 |
-
}
|
41 |
-
|
42 |
-
var Abstract = new Object();
|
43 |
-
|
44 |
-
Object.extend = function(destination, source) {
|
45 |
-
for (var property in source) {
|
46 |
-
destination[property] = source[property];
|
47 |
-
}
|
48 |
-
return destination;
|
49 |
-
}
|
50 |
-
|
51 |
-
Object.extend(Object, {
|
52 |
-
inspect: function(object) {
|
53 |
-
try {
|
54 |
-
if (object === undefined) return 'undefined';
|
55 |
-
if (object === null) return 'null';
|
56 |
-
return object.inspect ? object.inspect() : object.toString();
|
57 |
-
} catch (e) {
|
58 |
-
if (e instanceof RangeError) return '...';
|
59 |
-
throw e;
|
60 |
-
}
|
61 |
-
},
|
62 |
-
|
63 |
-
toJSON: function(object) {
|
64 |
-
var type = typeof object;
|
65 |
-
switch(type) {
|
66 |
-
case 'undefined':
|
67 |
-
case 'function':
|
68 |
-
case 'unknown': return;
|
69 |
-
case 'boolean': return object.toString();
|
70 |
-
}
|
71 |
-
if (object === null) return 'null';
|
72 |
-
if (object.toJSON) return object.toJSON();
|
73 |
-
if (object.ownerDocument === document) return;
|
74 |
-
var results = [];
|
75 |
-
for (var property in object) {
|
76 |
-
var value = Object.toJSON(object[property]);
|
77 |
-
if (value !== undefined)
|
78 |
-
results.push(property.toJSON() + ': ' + value);
|
79 |
-
}
|
80 |
-
return '{' + results.join(', ') + '}';
|
81 |
-
},
|
82 |
-
|
83 |
-
keys: function(object) {
|
84 |
-
var keys = [];
|
85 |
-
for (var property in object)
|
86 |
-
keys.push(property);
|
87 |
-
return keys;
|
88 |
-
},
|
89 |
-
|
90 |
-
values: function(object) {
|
91 |
-
var values = [];
|
92 |
-
for (var property in object)
|
93 |
-
values.push(object[property]);
|
94 |
-
return values;
|
95 |
-
},
|
96 |
-
|
97 |
-
clone: function(object) {
|
98 |
-
return Object.extend({}, object);
|
99 |
-
}
|
100 |
-
});
|
101 |
-
|
102 |
-
Function.prototype.bind = function() {
|
103 |
-
var __method = this, args = $A(arguments), object = args.shift();
|
104 |
-
return function() {
|
105 |
-
return __method.apply(object, args.concat($A(arguments)));
|
106 |
-
}
|
107 |
-
}
|
108 |
-
|
109 |
-
Function.prototype.bindAsEventListener = function(object) {
|
110 |
-
var __method = this, args = $A(arguments), object = args.shift();
|
111 |
-
return function(event) {
|
112 |
-
return __method.apply(object, [event || window.event].concat(args));
|
113 |
-
}
|
114 |
-
}
|
115 |
-
|
116 |
-
Object.extend(Number.prototype, {
|
117 |
-
toColorPart: function() {
|
118 |
-
return this.toPaddedString(2, 16);
|
119 |
-
},
|
120 |
-
|
121 |
-
succ: function() {
|
122 |
-
return this + 1;
|
123 |
-
},
|
124 |
-
|
125 |
-
times: function(iterator) {
|
126 |
-
$R(0, this, true).each(iterator);
|
127 |
-
return this;
|
128 |
-
},
|
129 |
-
|
130 |
-
toPaddedString: function(length, radix) {
|
131 |
-
var string = this.toString(radix || 10);
|
132 |
-
return '0'.times(length - string.length) + string;
|
133 |
-
},
|
134 |
-
|
135 |
-
toJSON: function() {
|
136 |
-
return isFinite(this) ? this.toString() : 'null';
|
137 |
-
}
|
138 |
-
});
|
139 |
-
|
140 |
-
Date.prototype.toJSON = function() {
|
141 |
-
return '"' + this.getFullYear() + '-' +
|
142 |
-
(this.getMonth() + 1).toPaddedString(2) + '-' +
|
143 |
-
this.getDate().toPaddedString(2) + 'T' +
|
144 |
-
this.getHours().toPaddedString(2) + ':' +
|
145 |
-
this.getMinutes().toPaddedString(2) + ':' +
|
146 |
-
this.getSeconds().toPaddedString(2) + '"';
|
147 |
-
};
|
148 |
-
|
149 |
-
var Try = {
|
150 |
-
these: function() {
|
151 |
-
var returnValue;
|
152 |
-
|
153 |
-
for (var i = 0, length = arguments.length; i < length; i++) {
|
154 |
-
var lambda = arguments[i];
|
155 |
-
try {
|
156 |
-
returnValue = lambda();
|
157 |
-
break;
|
158 |
-
} catch (e) {}
|
159 |
-
}
|
160 |
-
|
161 |
-
return returnValue;
|
162 |
-
}
|
163 |
-
}
|
164 |
-
|
165 |
-
/*--------------------------------------------------------------------------*/
|
166 |
-
|
167 |
-
var PeriodicalExecuter = Class.create();
|
168 |
-
PeriodicalExecuter.prototype = {
|
169 |
-
initialize: function(callback, frequency) {
|
170 |
-
this.callback = callback;
|
171 |
-
this.frequency = frequency;
|
172 |
-
this.currentlyExecuting = false;
|
173 |
-
|
174 |
-
this.registerCallback();
|
175 |
-
},
|
176 |
-
|
177 |
-
registerCallback: function() {
|
178 |
-
this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
|
179 |
-
},
|
180 |
-
|
181 |
-
stop: function() {
|
182 |
-
if (!this.timer) return;
|
183 |
-
clearInterval(this.timer);
|
184 |
-
this.timer = null;
|
185 |
-
},
|
186 |
-
|
187 |
-
onTimerEvent: function() {
|
188 |
-
if (!this.currentlyExecuting) {
|
189 |
-
try {
|
190 |
-
this.currentlyExecuting = true;
|
191 |
-
this.callback(this);
|
192 |
-
} finally {
|
193 |
-
this.currentlyExecuting = false;
|
194 |
-
}
|
195 |
-
}
|
196 |
-
}
|
197 |
-
}
|
198 |
-
Object.extend(String, {
|
199 |
-
interpret: function(value) {
|
200 |
-
return value == null ? '' : String(value);
|
201 |
-
},
|
202 |
-
specialChar: {
|
203 |
-
'\b': '\\b',
|
204 |
-
'\t': '\\t',
|
205 |
-
'\n': '\\n',
|
206 |
-
'\f': '\\f',
|
207 |
-
'\r': '\\r',
|
208 |
-
'\\': '\\\\'
|
209 |
-
}
|
210 |
-
});
|
211 |
-
|
212 |
-
Object.extend(String.prototype, {
|
213 |
-
gsub: function(pattern, replacement) {
|
214 |
-
var result = '', source = this, match;
|
215 |
-
replacement = arguments.callee.prepareReplacement(replacement);
|
216 |
-
|
217 |
-
while (source.length > 0) {
|
218 |
-
if (match = source.match(pattern)) {
|
219 |
-
result += source.slice(0, match.index);
|
220 |
-
result += String.interpret(replacement(match));
|
221 |
-
source = source.slice(match.index + match[0].length);
|
222 |
-
} else {
|
223 |
-
result += source, source = '';
|
224 |
-
}
|
225 |
-
}
|
226 |
-
return result;
|
227 |
-
},
|
228 |
-
|
229 |
-
sub: function(pattern, replacement, count) {
|
230 |
-
replacement = this.gsub.prepareReplacement(replacement);
|
231 |
-
count = count === undefined ? 1 : count;
|
232 |
-
|
233 |
-
return this.gsub(pattern, function(match) {
|
234 |
-
if (--count < 0) return match[0];
|
235 |
-
return replacement(match);
|
236 |
-
});
|
237 |
-
},
|
238 |
-
|
239 |
-
scan: function(pattern, iterator) {
|
240 |
-
this.gsub(pattern, iterator);
|
241 |
-
return this;
|
242 |
-
},
|
243 |
-
|
244 |
-
truncate: function(length, truncation) {
|
245 |
-
length = length || 30;
|
246 |
-
truncation = truncation === undefined ? '...' : truncation;
|
247 |
-
return this.length > length ?
|
248 |
-
this.slice(0, length - truncation.length) + truncation : this;
|
249 |
-
},
|
250 |
-
|
251 |
-
strip: function() {
|
252 |
-
return this.replace(/^\s+/, '').replace(/\s+$/, '');
|
253 |
-
},
|
254 |
-
|
255 |
-
stripTags: function() {
|
256 |
-
return this.replace(/<\/?[^>]+>/gi, '');
|
257 |
-
},
|
258 |
-
|
259 |
-
stripScripts: function() {
|
260 |
-
return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
|
261 |
-
},
|
262 |
-
|
263 |
-
extractScripts: function() {
|
264 |
-
var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
|
265 |
-
var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
|
266 |
-
return (this.match(matchAll) || []).map(function(scriptTag) {
|
267 |
-
return (scriptTag.match(matchOne) || ['', ''])[1];
|
268 |
-
});
|
269 |
-
},
|
270 |
-
|
271 |
-
evalScripts: function() {
|
272 |
-
return this.extractScripts().map(function(script) { return eval(script) });
|
273 |
-
},
|
274 |
-
|
275 |
-
escapeHTML: function() {
|
276 |
-
var self = arguments.callee;
|
277 |
-
self.text.data = this;
|
278 |
-
return self.div.innerHTML;
|
279 |
-
},
|
280 |
-
|
281 |
-
unescapeHTML: function() {
|
282 |
-
var div = document.createElement('div');
|
283 |
-
div.innerHTML = this.stripTags();
|
284 |
-
return div.childNodes[0] ? (div.childNodes.length > 1 ?
|
285 |
-
$A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :
|
286 |
-
div.childNodes[0].nodeValue) : '';
|
287 |
-
},
|
288 |
-
|
289 |
-
toQueryParams: function(separator) {
|
290 |
-
var match = this.strip().match(/([^?#]*)(#.*)?$/);
|
291 |
-
if (!match) return {};
|
292 |
-
|
293 |
-
return match[1].split(separator || '&').inject({}, function(hash, pair) {
|
294 |
-
if ((pair = pair.split('='))[0]) {
|
295 |
-
var key = decodeURIComponent(pair.shift());
|
296 |
-
var value = pair.length > 1 ? pair.join('=') : pair[0];
|
297 |
-
if (value != undefined) value = decodeURIComponent(value);
|
298 |
-
|
299 |
-
if (key in hash) {
|
300 |
-
if (hash[key].constructor != Array) hash[key] = [hash[key]];
|
301 |
-
hash[key].push(value);
|
302 |
-
}
|
303 |
-
else hash[key] = value;
|
304 |
-
}
|
305 |
-
return hash;
|
306 |
-
});
|
307 |
-
},
|
308 |
-
|
309 |
-
toArray: function() {
|
310 |
-
return this.split('');
|
311 |
-
},
|
312 |
-
|
313 |
-
succ: function() {
|
314 |
-
return this.slice(0, this.length - 1) +
|
315 |
-
String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
|
316 |
-
},
|
317 |
-
|
318 |
-
times: function(count) {
|
319 |
-
var result = '';
|
320 |
-
for (var i = 0; i < count; i++) result += this;
|
321 |
-
return result;
|
322 |
-
},
|
323 |
-
|
324 |
-
camelize: function() {
|
325 |
-
var parts = this.split('-'), len = parts.length;
|
326 |
-
if (len == 1) return parts[0];
|
327 |
-
|
328 |
-
var camelized = this.charAt(0) == '-'
|
329 |
-
? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
|
330 |
-
: parts[0];
|
331 |
-
|
332 |
-
for (var i = 1; i < len; i++)
|
333 |
-
camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
|
334 |
-
|
335 |
-
return camelized;
|
336 |
-
},
|
337 |
-
|
338 |
-
capitalize: function() {
|
339 |
-
return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
|
340 |
-
},
|
341 |
-
|
342 |
-
underscore: function() {
|
343 |
-
return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
|
344 |
-
},
|
345 |
-
|
346 |
-
dasherize: function() {
|
347 |
-
return this.gsub(/_/,'-');
|
348 |
-
},
|
349 |
-
|
350 |
-
inspect: function(useDoubleQuotes) {
|
351 |
-
var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
|
352 |
-
var character = String.specialChar[match[0]];
|
353 |
-
return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
|
354 |
-
});
|
355 |
-
if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
|
356 |
-
return "'" + escapedString.replace(/'/g, '\\\'') + "'";
|
357 |
-
},
|
358 |
-
|
359 |
-
toJSON: function() {
|
360 |
-
return this.inspect(true);
|
361 |
-
},
|
362 |
-
|
363 |
-
unfilterJSON: function(filter) {
|
364 |
-
return this.sub(filter || Prototype.JSONFilter, '#{1}');
|
365 |
-
},
|
366 |
-
|
367 |
-
evalJSON: function(sanitize) {
|
368 |
-
var json = this.unfilterJSON();
|
369 |
-
try {
|
370 |
-
if (!sanitize || (/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.test(json)))
|
371 |
-
return eval('(' + json + ')');
|
372 |
-
} catch (e) { }
|
373 |
-
throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
|
374 |
-
},
|
375 |
-
|
376 |
-
include: function(pattern) {
|
377 |
-
return this.indexOf(pattern) > -1;
|
378 |
-
},
|
379 |
-
|
380 |
-
startsWith: function(pattern) {
|
381 |
-
return this.indexOf(pattern) === 0;
|
382 |
-
},
|
383 |
-
|
384 |
-
endsWith: function(pattern) {
|
385 |
-
var d = this.length - pattern.length;
|
386 |
-
return d >= 0 && this.lastIndexOf(pattern) === d;
|
387 |
-
},
|
388 |
-
|
389 |
-
empty: function() {
|
390 |
-
return this == '';
|
391 |
-
},
|
392 |
-
|
393 |
-
blank: function() {
|
394 |
-
return /^\s*$/.test(this);
|
395 |
-
}
|
396 |
-
});
|
397 |
-
|
398 |
-
if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
|
399 |
-
escapeHTML: function() {
|
400 |
-
return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
401 |
-
},
|
402 |
-
unescapeHTML: function() {
|
403 |
-
return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
404 |
-
}
|
405 |
-
});
|
406 |
-
|
407 |
-
String.prototype.gsub.prepareReplacement = function(replacement) {
|
408 |
-
if (typeof replacement == 'function') return replacement;
|
409 |
-
var template = new Template(replacement);
|
410 |
-
return function(match) { return template.evaluate(match) };
|
411 |
-
}
|
412 |
-
|
413 |
-
String.prototype.parseQuery = String.prototype.toQueryParams;
|
414 |
-
|
415 |
-
Object.extend(String.prototype.escapeHTML, {
|
416 |
-
div: document.createElement('div'),
|
417 |
-
text: document.createTextNode('')
|
418 |
-
});
|
419 |
-
|
420 |
-
with (String.prototype.escapeHTML) div.appendChild(text);
|
421 |
-
|
422 |
-
var Template = Class.create();
|
423 |
-
Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
|
424 |
-
Template.prototype = {
|
425 |
-
initialize: function(template, pattern) {
|
426 |
-
this.template = template.toString();
|
427 |
-
this.pattern = pattern || Template.Pattern;
|
428 |
-
},
|
429 |
-
|
430 |
-
evaluate: function(object) {
|
431 |
-
return this.template.gsub(this.pattern, function(match) {
|
432 |
-
var before = match[1];
|
433 |
-
if (before == '\\') return match[2];
|
434 |
-
return before + String.interpret(object[match[3]]);
|
435 |
-
});
|
436 |
-
}
|
437 |
-
}
|
438 |
-
|
439 |
-
var $break = {}, $continue = new Error('"throw $continue" is deprecated, use "return" instead');
|
440 |
-
|
441 |
-
var Enumerable = {
|
442 |
-
each: function(iterator) {
|
443 |
-
var index = 0;
|
444 |
-
try {
|
445 |
-
this._each(function(value) {
|
446 |
-
iterator(value, index++);
|
447 |
-
});
|
448 |
-
} catch (e) {
|
449 |
-
if (e != $break) throw e;
|
450 |
-
}
|
451 |
-
return this;
|
452 |
-
},
|
453 |
-
|
454 |
-
eachSlice: function(number, iterator) {
|
455 |
-
var index = -number, slices = [], array = this.toArray();
|
456 |
-
while ((index += number) < array.length)
|
457 |
-
slices.push(array.slice(index, index+number));
|
458 |
-
return slices.map(iterator);
|
459 |
-
},
|
460 |
-
|
461 |
-
all: function(iterator) {
|
462 |
-
var result = true;
|
463 |
-
this.each(function(value, index) {
|
464 |
-
result = result && !!(iterator || Prototype.K)(value, index);
|
465 |
-
if (!result) throw $break;
|
466 |
-
});
|
467 |
-
return result;
|
468 |
-
},
|
469 |
-
|
470 |
-
any: function(iterator) {
|
471 |
-
var result = false;
|
472 |
-
this.each(function(value, index) {
|
473 |
-
if (result = !!(iterator || Prototype.K)(value, index))
|
474 |
-
throw $break;
|
475 |
-
});
|
476 |
-
return result;
|
477 |
-
},
|
478 |
-
|
479 |
-
collect: function(iterator) {
|
480 |
-
var results = [];
|
481 |
-
this.each(function(value, index) {
|
482 |
-
results.push((iterator || Prototype.K)(value, index));
|
483 |
-
});
|
484 |
-
return results;
|
485 |
-
},
|
486 |
-
|
487 |
-
detect: function(iterator) {
|
488 |
-
var result;
|
489 |
-
this.each(function(value, index) {
|
490 |
-
if (iterator(value, index)) {
|
491 |
-
result = value;
|
492 |
-
throw $break;
|
493 |
-
}
|
494 |
-
});
|
495 |
-
return result;
|
496 |
-
},
|
497 |
-
|
498 |
-
findAll: function(iterator) {
|
499 |
-
var results = [];
|
500 |
-
this.each(function(value, index) {
|
501 |
-
if (iterator(value, index))
|
502 |
-
results.push(value);
|
503 |
-
});
|
504 |
-
return results;
|
505 |
-
},
|
506 |
-
|
507 |
-
grep: function(pattern, iterator) {
|
508 |
-
var results = [];
|
509 |
-
this.each(function(value, index) {
|
510 |
-
var stringValue = value.toString();
|
511 |
-
if (stringValue.match(pattern))
|
512 |
-
results.push((iterator || Prototype.K)(value, index));
|
513 |
-
})
|
514 |
-
return results;
|
515 |
-
},
|
516 |
-
|
517 |
-
include: function(object) {
|
518 |
-
var found = false;
|
519 |
-
this.each(function(value) {
|
520 |
-
if (value == object) {
|
521 |
-
found = true;
|
522 |
-
throw $break;
|
523 |
-
}
|
524 |
-
});
|
525 |
-
return found;
|
526 |
-
},
|
527 |
-
|
528 |
-
inGroupsOf: function(number, fillWith) {
|
529 |
-
fillWith = fillWith === undefined ? null : fillWith;
|
530 |
-
return this.eachSlice(number, function(slice) {
|
531 |
-
while(slice.length < number) slice.push(fillWith);
|
532 |
-
return slice;
|
533 |
-
});
|
534 |
-
},
|
535 |
-
|
536 |
-
inject: function(memo, iterator) {
|
537 |
-
this.each(function(value, index) {
|
538 |
-
memo = iterator(memo, value, index);
|
539 |
-
});
|
540 |
-
return memo;
|
541 |
-
},
|
542 |
-
|
543 |
-
invoke: function(method) {
|
544 |
-
var args = $A(arguments).slice(1);
|
545 |
-
return this.map(function(value) {
|
546 |
-
return value[method].apply(value, args);
|
547 |
-
});
|
548 |
-
},
|
549 |
-
|
550 |
-
max: function(iterator) {
|
551 |
-
var result;
|
552 |
-
this.each(function(value, index) {
|
553 |
-
value = (iterator || Prototype.K)(value, index);
|
554 |
-
if (result == undefined || value >= result)
|
555 |
-
result = value;
|
556 |
-
});
|
557 |
-
return result;
|
558 |
-
},
|
559 |
-
|
560 |
-
min: function(iterator) {
|
561 |
-
var result;
|
562 |
-
this.each(function(value, index) {
|
563 |
-
value = (iterator || Prototype.K)(value, index);
|
564 |
-
if (result == undefined || value < result)
|
565 |
-
result = value;
|
566 |
-
});
|
567 |
-
return result;
|
568 |
-
},
|
569 |
-
|
570 |
-
partition: function(iterator) {
|
571 |
-
var trues = [], falses = [];
|
572 |
-
this.each(function(value, index) {
|
573 |
-
((iterator || Prototype.K)(value, index) ?
|
574 |
-
trues : falses).push(value);
|
575 |
-
});
|
576 |
-
return [trues, falses];
|
577 |
-
},
|
578 |
-
|
579 |
-
pluck: function(property) {
|
580 |
-
var results = [];
|
581 |
-
this.each(function(value, index) {
|
582 |
-
results.push(value[property]);
|
583 |
-
});
|
584 |
-
return results;
|
585 |
-
},
|
586 |
-
|
587 |
-
reject: function(iterator) {
|
588 |
-
var results = [];
|
589 |
-
this.each(function(value, index) {
|
590 |
-
if (!iterator(value, index))
|
591 |
-
results.push(value);
|
592 |
-
});
|
593 |
-
return results;
|
594 |
-
},
|
595 |
-
|
596 |
-
sortBy: function(iterator) {
|
597 |
-
return this.map(function(value, index) {
|
598 |
-
return {value: value, criteria: iterator(value, index)};
|
599 |
-
}).sort(function(left, right) {
|
600 |
-
var a = left.criteria, b = right.criteria;
|
601 |
-
return a < b ? -1 : a > b ? 1 : 0;
|
602 |
-
}).pluck('value');
|
603 |
-
},
|
604 |
-
|
605 |
-
toArray: function() {
|
606 |
-
return this.map();
|
607 |
-
},
|
608 |
-
|
609 |
-
zip: function() {
|
610 |
-
var iterator = Prototype.K, args = $A(arguments);
|
611 |
-
if (typeof args.last() == 'function')
|
612 |
-
iterator = args.pop();
|
613 |
-
|
614 |
-
var collections = [this].concat(args).map($A);
|
615 |
-
return this.map(function(value, index) {
|
616 |
-
return iterator(collections.pluck(index));
|
617 |
-
});
|
618 |
-
},
|
619 |
-
|
620 |
-
size: function() {
|
621 |
-
return this.toArray().length;
|
622 |
-
},
|
623 |
-
|
624 |
-
inspect: function() {
|
625 |
-
return '#<Enumerable:' + this.toArray().inspect() + '>';
|
626 |
-
}
|
627 |
-
}
|
628 |
-
|
629 |
-
Object.extend(Enumerable, {
|
630 |
-
map: Enumerable.collect,
|
631 |
-
find: Enumerable.detect,
|
632 |
-
select: Enumerable.findAll,
|
633 |
-
member: Enumerable.include,
|
634 |
-
entries: Enumerable.toArray
|
635 |
-
});
|
636 |
-
var $A = Array.from = function(iterable) {
|
637 |
-
if (!iterable) return [];
|
638 |
-
if (iterable.toArray) {
|
639 |
-
return iterable.toArray();
|
640 |
-
} else {
|
641 |
-
var results = [];
|
642 |
-
for (var i = 0, length = iterable.length; i < length; i++)
|
643 |
-
results.push(iterable[i]);
|
644 |
-
return results;
|
645 |
-
}
|
646 |
-
}
|
647 |
-
|
648 |
-
if (Prototype.Browser.WebKit) {
|
649 |
-
$A = Array.from = function(iterable) {
|
650 |
-
if (!iterable) return [];
|
651 |
-
if (!(typeof iterable == 'function' && iterable == '[object NodeList]') &&
|
652 |
-
iterable.toArray) {
|
653 |
-
return iterable.toArray();
|
654 |
-
} else {
|
655 |
-
var results = [];
|
656 |
-
for (var i = 0, length = iterable.length; i < length; i++)
|
657 |
-
results.push(iterable[i]);
|
658 |
-
return results;
|
659 |
-
}
|
660 |
-
}
|
661 |
-
}
|
662 |
-
|
663 |
-
Object.extend(Array.prototype, Enumerable);
|
664 |
-
|
665 |
-
if (!Array.prototype._reverse)
|
666 |
-
Array.prototype._reverse = Array.prototype.reverse;
|
667 |
-
|
668 |
-
Object.extend(Array.prototype, {
|
669 |
-
_each: function(iterator) {
|
670 |
-
for (var i = 0, length = this.length; i < length; i++)
|
671 |
-
iterator(this[i]);
|
672 |
-
},
|
673 |
-
|
674 |
-
clear: function() {
|
675 |
-
this.length = 0;
|
676 |
-
return this;
|
677 |
-
},
|
678 |
-
|
679 |
-
first: function() {
|
680 |
-
return this[0];
|
681 |
-
},
|
682 |
-
|
683 |
-
last: function() {
|
684 |
-
return this[this.length - 1];
|
685 |
-
},
|
686 |
-
|
687 |
-
compact: function() {
|
688 |
-
return this.select(function(value) {
|
689 |
-
return value != null;
|
690 |
-
});
|
691 |
-
},
|
692 |
-
|
693 |
-
flatten: function() {
|
694 |
-
return this.inject([], function(array, value) {
|
695 |
-
return array.concat(value && value.constructor == Array ?
|
696 |
-
value.flatten() : [value]);
|
697 |
-
});
|
698 |
-
},
|
699 |
-
|
700 |
-
without: function() {
|
701 |
-
var values = $A(arguments);
|
702 |
-
return this.select(function(value) {
|
703 |
-
return !values.include(value);
|
704 |
-
});
|
705 |
-
},
|
706 |
-
|
707 |
-
indexOf: function(object) {
|
708 |
-
for (var i = 0, length = this.length; i < length; i++)
|
709 |
-
if (this[i] == object) return i;
|
710 |
-
return -1;
|
711 |
-
},
|
712 |
-
|
713 |
-
reverse: function(inline) {
|
714 |
-
return (inline !== false ? this : this.toArray())._reverse();
|
715 |
-
},
|
716 |
-
|
717 |
-
reduce: function() {
|
718 |
-
return this.length > 1 ? this : this[0];
|
719 |
-
},
|
720 |
-
|
721 |
-
uniq: function(sorted) {
|
722 |
-
return this.inject([], function(array, value, index) {
|
723 |
-
if (0 == index || (sorted ? array.last() != value : !array.include(value)))
|
724 |
-
array.push(value);
|
725 |
-
return array;
|
726 |
-
});
|
727 |
-
},
|
728 |
-
|
729 |
-
clone: function() {
|
730 |
-
return [].concat(this);
|
731 |
-
},
|
732 |
-
|
733 |
-
size: function() {
|
734 |
-
return this.length;
|
735 |
-
},
|
736 |
-
|
737 |
-
inspect: function() {
|
738 |
-
return '[' + this.map(Object.inspect).join(', ') + ']';
|
739 |
-
},
|
740 |
-
|
741 |
-
toJSON: function() {
|
742 |
-
var results = [];
|
743 |
-
this.each(function(object) {
|
744 |
-
var value = Object.toJSON(object);
|
745 |
-
if (value !== undefined) results.push(value);
|
746 |
-
});
|
747 |
-
return '[' + results.join(', ') + ']';
|
748 |
-
}
|
749 |
-
});
|
750 |
-
|
751 |
-
Array.prototype.toArray = Array.prototype.clone;
|
752 |
-
|
753 |
-
function $w(string) {
|
754 |
-
string = string.strip();
|
755 |
-
return string ? string.split(/\s+/) : [];
|
756 |
-
}
|
757 |
-
|
758 |
-
if (Prototype.Browser.Opera){
|
759 |
-
Array.prototype.concat = function() {
|
760 |
-
var array = [];
|
761 |
-
for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
|
762 |
-
for (var i = 0, length = arguments.length; i < length; i++) {
|
763 |
-
if (arguments[i].constructor == Array) {
|
764 |
-
for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
|
765 |
-
array.push(arguments[i][j]);
|
766 |
-
} else {
|
767 |
-
array.push(arguments[i]);
|
768 |
-
}
|
769 |
-
}
|
770 |
-
return array;
|
771 |
-
}
|
772 |
-
}
|
773 |
-
var Hash = function(object) {
|
774 |
-
if (object instanceof Hash) this.merge(object);
|
775 |
-
else Object.extend(this, object || {});
|
776 |
-
};
|
777 |
-
|
778 |
-
Object.extend(Hash, {
|
779 |
-
toQueryString: function(obj) {
|
780 |
-
var parts = [];
|
781 |
-
parts.add = arguments.callee.addPair;
|
782 |
-
|
783 |
-
this.prototype._each.call(obj, function(pair) {
|
784 |
-
if (!pair.key) return;
|
785 |
-
var value = pair.value;
|
786 |
-
|
787 |
-
if (value && typeof value == 'object') {
|
788 |
-
if (value.constructor == Array) value.each(function(value) {
|
789 |
-
parts.add(pair.key, value);
|
790 |
-
});
|
791 |
-
return;
|
792 |
-
}
|
793 |
-
parts.add(pair.key, value);
|
794 |
-
});
|
795 |
-
|
796 |
-
return parts.join('&');
|
797 |
-
},
|
798 |
-
|
799 |
-
toJSON: function(object) {
|
800 |
-
var results = [];
|
801 |
-
this.prototype._each.call(object, function(pair) {
|
802 |
-
var value = Object.toJSON(pair.value);
|
803 |
-
if (value !== undefined) results.push(pair.key.toJSON() + ': ' + value);
|
804 |
-
});
|
805 |
-
return '{' + results.join(', ') + '}';
|
806 |
-
}
|
807 |
-
});
|
808 |
-
|
809 |
-
Hash.toQueryString.addPair = function(key, value, prefix) {
|
810 |
-
key = encodeURIComponent(key);
|
811 |
-
if (value === undefined) this.push(key);
|
812 |
-
else this.push(key + '=' + (value == null ? '' : encodeURIComponent(value)));
|
813 |
-
}
|
814 |
-
|
815 |
-
Object.extend(Hash.prototype, Enumerable);
|
816 |
-
Object.extend(Hash.prototype, {
|
817 |
-
_each: function(iterator) {
|
818 |
-
for (var key in this) {
|
819 |
-
var value = this[key];
|
820 |
-
if (value && value == Hash.prototype[key]) continue;
|
821 |
-
|
822 |
-
var pair = [key, value];
|
823 |
-
pair.key = key;
|
824 |
-
pair.value = value;
|
825 |
-
iterator(pair);
|
826 |
-
}
|
827 |
-
},
|
828 |
-
|
829 |
-
keys: function() {
|
830 |
-
return this.pluck('key');
|
831 |
-
},
|
832 |
-
|
833 |
-
values: function() {
|
834 |
-
return this.pluck('value');
|
835 |
-
},
|
836 |
-
|
837 |
-
merge: function(hash) {
|
838 |
-
return $H(hash).inject(this, function(mergedHash, pair) {
|
839 |
-
mergedHash[pair.key] = pair.value;
|
840 |
-
return mergedHash;
|
841 |
-
});
|
842 |
-
},
|
843 |
-
|
844 |
-
remove: function() {
|
845 |
-
var result;
|
846 |
-
for(var i = 0, length = arguments.length; i < length; i++) {
|
847 |
-
var value = this[arguments[i]];
|
848 |
-
if (value !== undefined){
|
849 |
-
if (result === undefined) result = value;
|
850 |
-
else {
|
851 |
-
if (result.constructor != Array) result = [result];
|
852 |
-
result.push(value)
|
853 |
-
}
|
854 |
-
}
|
855 |
-
delete this[arguments[i]];
|
856 |
-
}
|
857 |
-
return result;
|
858 |
-
},
|
859 |
-
|
860 |
-
toQueryString: function() {
|
861 |
-
return Hash.toQueryString(this);
|
862 |
-
},
|
863 |
-
|
864 |
-
inspect: function() {
|
865 |
-
return '#<Hash:{' + this.map(function(pair) {
|
866 |
-
return pair.map(Object.inspect).join(': ');
|
867 |
-
}).join(', ') + '}>';
|
868 |
-
},
|
869 |
-
|
870 |
-
toJSON: function() {
|
871 |
-
return Hash.toJSON(this);
|
872 |
-
}
|
873 |
-
});
|
874 |
-
|
875 |
-
function $H(object) {
|
876 |
-
if (object instanceof Hash) return object;
|
877 |
-
return new Hash(object);
|
878 |
-
};
|
879 |
-
|
880 |
-
// Safari iterates over shadowed properties
|
881 |
-
if (function() {
|
882 |
-
var i = 0, Test = function(value) { this.key = value };
|
883 |
-
Test.prototype.key = 'foo';
|
884 |
-
for (var property in new Test('bar')) i++;
|
885 |
-
return i > 1;
|
886 |
-
}()) Hash.prototype._each = function(iterator) {
|
887 |
-
var cache = [];
|
888 |
-
for (var key in this) {
|
889 |
-
var value = this[key];
|
890 |
-
if ((value && value == Hash.prototype[key]) || cache.include(key)) continue;
|
891 |
-
cache.push(key);
|
892 |
-
var pair = [key, value];
|
893 |
-
pair.key = key;
|
894 |
-
pair.value = value;
|
895 |
-
iterator(pair);
|
896 |
-
}
|
897 |
-
};
|
898 |
-
ObjectRange = Class.create();
|
899 |
-
Object.extend(ObjectRange.prototype, Enumerable);
|
900 |
-
Object.extend(ObjectRange.prototype, {
|
901 |
-
initialize: function(start, end, exclusive) {
|
902 |
-
this.start = start;
|
903 |
-
this.end = end;
|
904 |
-
this.exclusive = exclusive;
|
905 |
-
},
|
906 |
-
|
907 |
-
_each: function(iterator) {
|
908 |
-
var value = this.start;
|
909 |
-
while (this.include(value)) {
|
910 |
-
iterator(value);
|
911 |
-
value = value.succ();
|
912 |
-
}
|
913 |
-
},
|
914 |
-
|
915 |
-
include: function(value) {
|
916 |
-
if (value < this.start)
|
917 |
-
return false;
|
918 |
-
if (this.exclusive)
|
919 |
-
return value < this.end;
|
920 |
-
return value <= this.end;
|
921 |
-
}
|
922 |
-
});
|
923 |
-
|
924 |
-
var $R = function(start, end, exclusive) {
|
925 |
-
return new ObjectRange(start, end, exclusive);
|
926 |
-
}
|
927 |
-
|
928 |
-
var Ajax = {
|
929 |
-
getTransport: function() {
|
930 |
-
return Try.these(
|
931 |
-
function() {return new XMLHttpRequest()},
|
932 |
-
function() {return new ActiveXObject('Msxml2.XMLHTTP')},
|
933 |
-
function() {return new ActiveXObject('Microsoft.XMLHTTP')}
|
934 |
-
) || false;
|
935 |
-
},
|
936 |
-
|
937 |
-
activeRequestCount: 0
|
938 |
-
}
|
939 |
-
|
940 |
-
Ajax.Responders = {
|
941 |
-
responders: [],
|
942 |
-
|
943 |
-
_each: function(iterator) {
|
944 |
-
this.responders._each(iterator);
|
945 |
-
},
|
946 |
-
|
947 |
-
register: function(responder) {
|
948 |
-
if (!this.include(responder))
|
949 |
-
this.responders.push(responder);
|
950 |
-
},
|
951 |
-
|
952 |
-
unregister: function(responder) {
|
953 |
-
this.responders = this.responders.without(responder);
|
954 |
-
},
|
955 |
-
|
956 |
-
dispatch: function(callback, request, transport, json) {
|
957 |
-
this.each(function(responder) {
|
958 |
-
if (typeof responder[callback] == 'function') {
|
959 |
-
try {
|
960 |
-
responder[callback].apply(responder, [request, transport, json]);
|
961 |
-
} catch (e) {}
|
962 |
-
}
|
963 |
-
});
|
964 |
-
}
|
965 |
-
};
|
966 |
-
|
967 |
-
Object.extend(Ajax.Responders, Enumerable);
|
968 |
-
|
969 |
-
Ajax.Responders.register({
|
970 |
-
onCreate: function() {
|
971 |
-
Ajax.activeRequestCount++;
|
972 |
-
},
|
973 |
-
onComplete: function() {
|
974 |
-
Ajax.activeRequestCount--;
|
975 |
-
}
|
976 |
-
});
|
977 |
-
|
978 |
-
Ajax.Base = function() {};
|
979 |
-
Ajax.Base.prototype = {
|
980 |
-
setOptions: function(options) {
|
981 |
-
this.options = {
|
982 |
-
method: 'post',
|
983 |
-
asynchronous: true,
|
984 |
-
contentType: 'application/x-www-form-urlencoded',
|
985 |
-
encoding: 'UTF-8',
|
986 |
-
parameters: ''
|
987 |
-
}
|
988 |
-
Object.extend(this.options, options || {});
|
989 |
-
|
990 |
-
this.options.method = this.options.method.toLowerCase();
|
991 |
-
if (typeof this.options.parameters == 'string')
|
992 |
-
this.options.parameters = this.options.parameters.toQueryParams();
|
993 |
-
}
|
994 |
-
}
|
995 |
-
|
996 |
-
Ajax.Request = Class.create();
|
997 |
-
Ajax.Request.Events =
|
998 |
-
['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
|
999 |
-
|
1000 |
-
Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
|
1001 |
-
_complete: false,
|
1002 |
-
|
1003 |
-
initialize: function(url, options) {
|
1004 |
-
this.transport = Ajax.getTransport();
|
1005 |
-
this.setOptions(options);
|
1006 |
-
this.request(url);
|
1007 |
-
},
|
1008 |
-
|
1009 |
-
request: function(url) {
|
1010 |
-
this.url = url;
|
1011 |
-
this.method = this.options.method;
|
1012 |
-
var params = Object.clone(this.options.parameters);
|
1013 |
-
|
1014 |
-
if (!['get', 'post'].include(this.method)) {
|
1015 |
-
// simulate other verbs over post
|
1016 |
-
params['_method'] = this.method;
|
1017 |
-
this.method = 'post';
|
1018 |
-
}
|
1019 |
-
|
1020 |
-
this.parameters = params;
|
1021 |
-
|
1022 |
-
if (params = Hash.toQueryString(params)) {
|
1023 |
-
// when GET, append parameters to URL
|
1024 |
-
if (this.method == 'get')
|
1025 |
-
this.url += (this.url.include('?') ? '&' : '?') + params;
|
1026 |
-
else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
|
1027 |
-
params += '&_=';
|
1028 |
-
}
|
1029 |
-
|
1030 |
-
try {
|
1031 |
-
if (this.options.onCreate) this.options.onCreate(this.transport);
|
1032 |
-
Ajax.Responders.dispatch('onCreate', this, this.transport);
|
1033 |
-
|
1034 |
-
this.transport.open(this.method.toUpperCase(), this.url,
|
1035 |
-
this.options.asynchronous);
|
1036 |
-
|
1037 |
-
if (this.options.asynchronous)
|
1038 |
-
setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);
|
1039 |
-
|
1040 |
-
this.transport.onreadystatechange = this.onStateChange.bind(this);
|
1041 |
-
this.setRequestHeaders();
|
1042 |
-
|
1043 |
-
this.body = this.method == 'post' ? (this.options.postBody || params) : null;
|
1044 |
-
this.transport.send(this.body);
|
1045 |
-
|
1046 |
-
/* Force Firefox to handle ready state 4 for synchronous requests */
|
1047 |
-
if (!this.options.asynchronous && this.transport.overrideMimeType)
|
1048 |
-
this.onStateChange();
|
1049 |
-
|
1050 |
-
}
|
1051 |
-
catch (e) {
|
1052 |
-
this.dispatchException(e);
|
1053 |
-
}
|
1054 |
-
},
|
1055 |
-
|
1056 |
-
onStateChange: function() {
|
1057 |
-
var readyState = this.transport.readyState;
|
1058 |
-
if (readyState > 1 && !((readyState == 4) && this._complete))
|
1059 |
-
this.respondToReadyState(this.transport.readyState);
|
1060 |
-
},
|
1061 |
-
|
1062 |
-
setRequestHeaders: function() {
|
1063 |
-
var headers = {
|
1064 |
-
'X-Requested-With': 'XMLHttpRequest',
|
1065 |
-
'X-Prototype-Version': Prototype.Version,
|
1066 |
-
'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
|
1067 |
-
};
|
1068 |
-
|
1069 |
-
if (this.method == 'post') {
|
1070 |
-
headers['Content-type'] = this.options.contentType +
|
1071 |
-
(this.options.encoding ? '; charset=' + this.options.encoding : '');
|
1072 |
-
|
1073 |
-
/* Force "Connection: close" for older Mozilla browsers to work
|
1074 |
-
* around a bug where XMLHttpRequest sends an incorrect
|
1075 |
-
* Content-length header. See Mozilla Bugzilla #246651.
|
1076 |
-
*/
|
1077 |
-
if (this.transport.overrideMimeType &&
|
1078 |
-
(navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
|
1079 |
-
headers['Connection'] = 'close';
|
1080 |
-
}
|
1081 |
-
|
1082 |
-
// user-defined headers
|
1083 |
-
if (typeof this.options.requestHeaders == 'object') {
|
1084 |
-
var extras = this.options.requestHeaders;
|
1085 |
-
|
1086 |
-
if (typeof extras.push == 'function')
|
1087 |
-
for (var i = 0, length = extras.length; i < length; i += 2)
|
1088 |
-
headers[extras[i]] = extras[i+1];
|
1089 |
-
else
|
1090 |
-
$H(extras).each(function(pair) { headers[pair.key] = pair.value });
|
1091 |
-
}
|
1092 |
-
|
1093 |
-
for (var name in headers)
|
1094 |
-
this.transport.setRequestHeader(name, headers[name]);
|
1095 |
-
},
|
1096 |
-
|
1097 |
-
success: function() {
|
1098 |
-
return !this.transport.status
|
1099 |
-
|| (this.transport.status >= 200 && this.transport.status < 300);
|
1100 |
-
},
|
1101 |
-
|
1102 |
-
respondToReadyState: function(readyState) {
|
1103 |
-
var state = Ajax.Request.Events[readyState];
|
1104 |
-
var transport = this.transport, json = this.evalJSON();
|
1105 |
-
|
1106 |
-
if (state == 'Complete') {
|
1107 |
-
try {
|
1108 |
-
this._complete = true;
|
1109 |
-
(this.options['on' + this.transport.status]
|
1110 |
-
|| this.options['on' + (this.success() ? 'Success' : 'Failure')]
|
1111 |
-
|| Prototype.emptyFunction)(transport, json);
|
1112 |
-
} catch (e) {
|
1113 |
-
this.dispatchException(e);
|
1114 |
-
}
|
1115 |
-
|
1116 |
-
var contentType = this.getHeader('Content-type');
|
1117 |
-
if (contentType && contentType.strip().
|
1118 |
-
match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
|
1119 |
-
this.evalResponse();
|
1120 |
-
}
|
1121 |
-
|
1122 |
-
try {
|
1123 |
-
(this.options['on' + state] || Prototype.emptyFunction)(transport, json);
|
1124 |
-
Ajax.Responders.dispatch('on' + state, this, transport, json);
|
1125 |
-
} catch (e) {
|
1126 |
-
this.dispatchException(e);
|
1127 |
-
}
|
1128 |
-
|
1129 |
-
if (state == 'Complete') {
|
1130 |
-
// avoid memory leak in MSIE: clean up
|
1131 |
-
this.transport.onreadystatechange = Prototype.emptyFunction;
|
1132 |
-
}
|
1133 |
-
},
|
1134 |
-
|
1135 |
-
getHeader: function(name) {
|
1136 |
-
try {
|
1137 |
-
return this.transport.getResponseHeader(name);
|
1138 |
-
} catch (e) { return null }
|
1139 |
-
},
|
1140 |
-
|
1141 |
-
evalJSON: function() {
|
1142 |
-
try {
|
1143 |
-
var json = this.getHeader('X-JSON');
|
1144 |
-
return json ? json.evalJSON() : null;
|
1145 |
-
} catch (e) { return null }
|
1146 |
-
},
|
1147 |
-
|
1148 |
-
evalResponse: function() {
|
1149 |
-
try {
|
1150 |
-
return eval((this.transport.responseText || '').unfilterJSON());
|
1151 |
-
} catch (e) {
|
1152 |
-
this.dispatchException(e);
|
1153 |
-
}
|
1154 |
-
},
|
1155 |
-
|
1156 |
-
dispatchException: function(exception) {
|
1157 |
-
(this.options.onException || Prototype.emptyFunction)(this, exception);
|
1158 |
-
Ajax.Responders.dispatch('onException', this, exception);
|
1159 |
-
}
|
1160 |
-
});
|
1161 |
-
|
1162 |
-
Ajax.Updater = Class.create();
|
1163 |
-
|
1164 |
-
Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
|
1165 |
-
initialize: function(container, url, options) {
|
1166 |
-
this.container = {
|
1167 |
-
success: (container.success || container),
|
1168 |
-
failure: (container.failure || (container.success ? null : container))
|
1169 |
-
}
|
1170 |
-
|
1171 |
-
this.transport = Ajax.getTransport();
|
1172 |
-
this.setOptions(options);
|
1173 |
-
|
1174 |
-
var onComplete = this.options.onComplete || Prototype.emptyFunction;
|
1175 |
-
this.options.onComplete = (function(transport, param) {
|
1176 |
-
this.updateContent();
|
1177 |
-
onComplete(transport, param);
|
1178 |
-
}).bind(this);
|
1179 |
-
|
1180 |
-
this.request(url);
|
1181 |
-
},
|
1182 |
-
|
1183 |
-
updateContent: function() {
|
1184 |
-
var receiver = this.container[this.success() ? 'success' : 'failure'];
|
1185 |
-
var response = this.transport.responseText;
|
1186 |
-
|
1187 |
-
if (!this.options.evalScripts) response = response.stripScripts();
|
1188 |
-
|
1189 |
-
if (receiver = $(receiver)) {
|
1190 |
-
if (this.options.insertion)
|
1191 |
-
new this.options.insertion(receiver, response);
|
1192 |
-
else
|
1193 |
-
receiver.update(response);
|
1194 |
-
}
|
1195 |
-
|
1196 |
-
if (this.success()) {
|
1197 |
-
if (this.onComplete)
|
1198 |
-
setTimeout(this.onComplete.bind(this), 10);
|
1199 |
-
}
|
1200 |
-
}
|
1201 |
-
});
|
1202 |
-
|
1203 |
-
Ajax.PeriodicalUpdater = Class.create();
|
1204 |
-
Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
|
1205 |
-
initialize: function(container, url, options) {
|
1206 |
-
this.setOptions(options);
|
1207 |
-
this.onComplete = this.options.onComplete;
|
1208 |
-
|
1209 |
-
this.frequency = (this.options.frequency || 2);
|
1210 |
-
this.decay = (this.options.decay || 1);
|
1211 |
-
|
1212 |
-
this.updater = {};
|
1213 |
-
this.container = container;
|
1214 |
-
this.url = url;
|
1215 |
-
|
1216 |
-
this.start();
|
1217 |
-
},
|
1218 |
-
|
1219 |
-
start: function() {
|
1220 |
-
this.options.onComplete = this.updateComplete.bind(this);
|
1221 |
-
this.onTimerEvent();
|
1222 |
-
},
|
1223 |
-
|
1224 |
-
stop: function() {
|
1225 |
-
this.updater.options.onComplete = undefined;
|
1226 |
-
clearTimeout(this.timer);
|
1227 |
-
(this.onComplete || Prototype.emptyFunction).apply(this, arguments);
|
1228 |
-
},
|
1229 |
-
|
1230 |
-
updateComplete: function(request) {
|
1231 |
-
if (this.options.decay) {
|
1232 |
-
this.decay = (request.responseText == this.lastText ?
|
1233 |
-
this.decay * this.options.decay : 1);
|
1234 |
-
|
1235 |
-
this.lastText = request.responseText;
|
1236 |
-
}
|
1237 |
-
this.timer = setTimeout(this.onTimerEvent.bind(this),
|
1238 |
-
this.decay * this.frequency * 1000);
|
1239 |
-
},
|
1240 |
-
|
1241 |
-
onTimerEvent: function() {
|
1242 |
-
this.updater = new Ajax.Updater(this.container, this.url, this.options);
|
1243 |
-
}
|
1244 |
-
});
|
1245 |
-
function $(element) {
|
1246 |
-
if (arguments.length > 1) {
|
1247 |
-
for (var i = 0, elements = [], length = arguments.length; i < length; i++)
|
1248 |
-
elements.push($(arguments[i]));
|
1249 |
-
return elements;
|
1250 |
-
}
|
1251 |
-
if (typeof element == 'string')
|
1252 |
-
element = document.getElementById(element);
|
1253 |
-
return Element.extend(element);
|
1254 |
-
}
|
1255 |
-
|
1256 |
-
if (Prototype.BrowserFeatures.XPath) {
|
1257 |
-
document._getElementsByXPath = function(expression, parentElement) {
|
1258 |
-
var results = [];
|
1259 |
-
var query = document.evaluate(expression, $(parentElement) || document,
|
1260 |
-
null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
|
1261 |
-
for (var i = 0, length = query.snapshotLength; i < length; i++)
|
1262 |
-
results.push(query.snapshotItem(i));
|
1263 |
-
return results;
|
1264 |
-
};
|
1265 |
-
|
1266 |
-
document.getElementsByClassName = function(className, parentElement) {
|
1267 |
-
var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
|
1268 |
-
return document._getElementsByXPath(q, parentElement);
|
1269 |
-
}
|
1270 |
-
|
1271 |
-
} else document.getElementsByClassName = function(className, parentElement) {
|
1272 |
-
var children = ($(parentElement) || document.body).getElementsByTagName('*');
|
1273 |
-
var elements = [], child;
|
1274 |
-
for (var i = 0, length = children.length; i < length; i++) {
|
1275 |
-
child = children[i];
|
1276 |
-
if (Element.hasClassName(child, className))
|
1277 |
-
elements.push(Element.extend(child));
|
1278 |
-
}
|
1279 |
-
return elements;
|
1280 |
-
};
|
1281 |
-
|
1282 |
-
/*--------------------------------------------------------------------------*/
|
1283 |
-
|
1284 |
-
if (!window.Element) var Element = {};
|
1285 |
-
|
1286 |
-
Element.extend = function(element) {
|
1287 |
-
var F = Prototype.BrowserFeatures;
|
1288 |
-
if (!element || !element.tagName || element.nodeType == 3 ||
|
1289 |
-
element._extended || F.SpecificElementExtensions || element == window)
|
1290 |
-
return element;
|
1291 |
-
|
1292 |
-
var methods = {}, tagName = element.tagName, cache = Element.extend.cache,
|
1293 |
-
T = Element.Methods.ByTag;
|
1294 |
-
|
1295 |
-
// extend methods for all tags (Safari doesn't need this)
|
1296 |
-
if (!F.ElementExtensions) {
|
1297 |
-
Object.extend(methods, Element.Methods),
|
1298 |
-
Object.extend(methods, Element.Methods.Simulated);
|
1299 |
-
}
|
1300 |
-
|
1301 |
-
// extend methods for specific tags
|
1302 |
-
if (T[tagName]) Object.extend(methods, T[tagName]);
|
1303 |
-
|
1304 |
-
for (var property in methods) {
|
1305 |
-
var value = methods[property];
|
1306 |
-
if (typeof value == 'function' && !(property in element))
|
1307 |
-
element[property] = cache.findOrStore(value);
|
1308 |
-
}
|
1309 |
-
|
1310 |
-
element._extended = Prototype.emptyFunction;
|
1311 |
-
return element;
|
1312 |
-
};
|
1313 |
-
|
1314 |
-
Element.extend.cache = {
|
1315 |
-
findOrStore: function(value) {
|
1316 |
-
return this[value] = this[value] || function() {
|
1317 |
-
return value.apply(null, [this].concat($A(arguments)));
|
1318 |
-
}
|
1319 |
-
}
|
1320 |
-
};
|
1321 |
-
|
1322 |
-
Element.Methods = {
|
1323 |
-
visible: function(element) {
|
1324 |
-
return $(element).style.display != 'none';
|
1325 |
-
},
|
1326 |
-
|
1327 |
-
toggle: function(element) {
|
1328 |
-
element = $(element);
|
1329 |
-
Element[Element.visible(element) ? 'hide' : 'show'](element);
|
1330 |
-
return element;
|
1331 |
-
},
|
1332 |
-
|
1333 |
-
hide: function(element) {
|
1334 |
-
$(element).style.display = 'none';
|
1335 |
-
return element;
|
1336 |
-
},
|
1337 |
-
|
1338 |
-
show: function(element) {
|
1339 |
-
$(element).style.display = '';
|
1340 |
-
return element;
|
1341 |
-
},
|
1342 |
-
|
1343 |
-
remove: function(element) {
|
1344 |
-
element = $(element);
|
1345 |
-
element.parentNode.removeChild(element);
|
1346 |
-
return element;
|
1347 |
-
},
|
1348 |
-
|
1349 |
-
update: function(element, html) {
|
1350 |
-
html = typeof html == 'undefined' ? '' : html.toString();
|
1351 |
-
$(element).innerHTML = html.stripScripts();
|
1352 |
-
setTimeout(function() {html.evalScripts()}, 10);
|
1353 |
-
return element;
|
1354 |
-
},
|
1355 |
-
|
1356 |
-
replace: function(element, html) {
|
1357 |
-
element = $(element);
|
1358 |
-
html = typeof html == 'undefined' ? '' : html.toString();
|
1359 |
-
if (element.outerHTML) {
|
1360 |
-
element.outerHTML = html.stripScripts();
|
1361 |
-
} else {
|
1362 |
-
var range = element.ownerDocument.createRange();
|
1363 |
-
range.selectNodeContents(element);
|
1364 |
-
element.parentNode.replaceChild(
|
1365 |
-
range.createContextualFragment(html.stripScripts()), element);
|
1366 |
-
}
|
1367 |
-
setTimeout(function() {html.evalScripts()}, 10);
|
1368 |
-
return element;
|
1369 |
-
},
|
1370 |
-
|
1371 |
-
inspect: function(element) {
|
1372 |
-
element = $(element);
|
1373 |
-
var result = '<' + element.tagName.toLowerCase();
|
1374 |
-
$H({'id': 'id', 'className': 'class'}).each(function(pair) {
|
1375 |
-
var property = pair.first(), attribute = pair.last();
|
1376 |
-
var value = (element[property] || '').toString();
|
1377 |
-
if (value) result += ' ' + attribute + '=' + value.inspect(true);
|
1378 |
-
});
|
1379 |
-
return result + '>';
|
1380 |
-
},
|
1381 |
-
|
1382 |
-
recursivelyCollect: function(element, property) {
|
1383 |
-
element = $(element);
|
1384 |
-
var elements = [];
|
1385 |
-
while (element = element[property])
|
1386 |
-
if (element.nodeType == 1)
|
1387 |
-
elements.push(Element.extend(element));
|
1388 |
-
return elements;
|
1389 |
-
},
|
1390 |
-
|
1391 |
-
ancestors: function(element) {
|
1392 |
-
return $(element).recursivelyCollect('parentNode');
|
1393 |
-
},
|
1394 |
-
|
1395 |
-
descendants: function(element) {
|
1396 |
-
return $A($(element).getElementsByTagName('*')).each(Element.extend);
|
1397 |
-
},
|
1398 |
-
|
1399 |
-
firstDescendant: function(element) {
|
1400 |
-
element = $(element).firstChild;
|
1401 |
-
while (element && element.nodeType != 1) element = element.nextSibling;
|
1402 |
-
return $(element);
|
1403 |
-
},
|
1404 |
-
|
1405 |
-
immediateDescendants: function(element) {
|
1406 |
-
if (!(element = $(element).firstChild)) return [];
|
1407 |
-
while (element && element.nodeType != 1) element = element.nextSibling;
|
1408 |
-
if (element) return [element].concat($(element).nextSiblings());
|
1409 |
-
return [];
|
1410 |
-
},
|
1411 |
-
|
1412 |
-
previousSiblings: function(element) {
|
1413 |
-
return $(element).recursivelyCollect('previousSibling');
|
1414 |
-
},
|
1415 |
-
|
1416 |
-
nextSiblings: function(element) {
|
1417 |
-
return $(element).recursivelyCollect('nextSibling');
|
1418 |
-
},
|
1419 |
-
|
1420 |
-
siblings: function(element) {
|
1421 |
-
element = $(element);
|
1422 |
-
return element.previousSiblings().reverse().concat(element.nextSiblings());
|
1423 |
-
},
|
1424 |
-
|
1425 |
-
match: function(element, selector) {
|
1426 |
-
if (typeof selector == 'string')
|
1427 |
-
selector = new Selector(selector);
|
1428 |
-
return selector.match($(element));
|
1429 |
-
},
|
1430 |
-
|
1431 |
-
up: function(element, expression, index) {
|
1432 |
-
element = $(element);
|
1433 |
-
if (arguments.length == 1) return $(element.parentNode);
|
1434 |
-
var ancestors = element.ancestors();
|
1435 |
-
return expression ? Selector.findElement(ancestors, expression, index) :
|
1436 |
-
ancestors[index || 0];
|
1437 |
-
},
|
1438 |
-
|
1439 |
-
down: function(element, expression, index) {
|
1440 |
-
element = $(element);
|
1441 |
-
if (arguments.length == 1) return element.firstDescendant();
|
1442 |
-
var descendants = element.descendants();
|
1443 |
-
return expression ? Selector.findElement(descendants, expression, index) :
|
1444 |
-
descendants[index || 0];
|
1445 |
-
},
|
1446 |
-
|
1447 |
-
previous: function(element, expression, index) {
|
1448 |
-
element = $(element);
|
1449 |
-
if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
|
1450 |
-
var previousSiblings = element.previousSiblings();
|
1451 |
-
return expression ? Selector.findElement(previousSiblings, expression, index) :
|
1452 |
-
previousSiblings[index || 0];
|
1453 |
-
},
|
1454 |
-
|
1455 |
-
next: function(element, expression, index) {
|
1456 |
-
element = $(element);
|
1457 |
-
if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
|
1458 |
-
var nextSiblings = element.nextSiblings();
|
1459 |
-
return expression ? Selector.findElement(nextSiblings, expression, index) :
|
1460 |
-
nextSiblings[index || 0];
|
1461 |
-
},
|
1462 |
-
|
1463 |
-
getElementsBySelector: function() {
|
1464 |
-
var args = $A(arguments), element = $(args.shift());
|
1465 |
-
return Selector.findChildElements(element, args);
|
1466 |
-
},
|
1467 |
-
|
1468 |
-
getElementsByClassName: function(element, className) {
|
1469 |
-
return document.getElementsByClassName(className, element);
|
1470 |
-
},
|
1471 |
-
|
1472 |
-
readAttribute: function(element, name) {
|
1473 |
-
element = $(element);
|
1474 |
-
if (Prototype.Browser.IE) {
|
1475 |
-
if (!element.attributes) return null;
|
1476 |
-
var t = Element._attributeTranslations;
|
1477 |
-
if (t.values[name]) return t.values[name](element, name);
|
1478 |
-
if (t.names[name]) name = t.names[name];
|
1479 |
-
var attribute = element.attributes[name];
|
1480 |
-
return attribute ? attribute.nodeValue : null;
|
1481 |
-
}
|
1482 |
-
return element.getAttribute(name);
|
1483 |
-
},
|
1484 |
-
|
1485 |
-
getHeight: function(element) {
|
1486 |
-
return $(element).getDimensions().height;
|
1487 |
-
},
|
1488 |
-
|
1489 |
-
getWidth: function(element) {
|
1490 |
-
return $(element).getDimensions().width;
|
1491 |
-
},
|
1492 |
-
|
1493 |
-
classNames: function(element) {
|
1494 |
-
return new Element.ClassNames(element);
|
1495 |
-
},
|
1496 |
-
|
1497 |
-
hasClassName: function(element, className) {
|
1498 |
-
if (!(element = $(element))) return;
|
1499 |
-
var elementClassName = element.className;
|
1500 |
-
if (elementClassName.length == 0) return false;
|
1501 |
-
if (elementClassName == className ||
|
1502 |
-
elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
|
1503 |
-
return true;
|
1504 |
-
return false;
|
1505 |
-
},
|
1506 |
-
|
1507 |
-
addClassName: function(element, className) {
|
1508 |
-
if (!(element = $(element))) return;
|
1509 |
-
Element.classNames(element).add(className);
|
1510 |
-
return element;
|
1511 |
-
},
|
1512 |
-
|
1513 |
-
removeClassName: function(element, className) {
|
1514 |
-
if (!(element = $(element))) return;
|
1515 |
-
Element.classNames(element).remove(className);
|
1516 |
-
return element;
|
1517 |
-
},
|
1518 |
-
|
1519 |
-
toggleClassName: function(element, className) {
|
1520 |
-
if (!(element = $(element))) return;
|
1521 |
-
Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className);
|
1522 |
-
return element;
|
1523 |
-
},
|
1524 |
-
|
1525 |
-
observe: function() {
|
1526 |
-
Event.observe.apply(Event, arguments);
|
1527 |
-
return $A(arguments).first();
|
1528 |
-
},
|
1529 |
-
|
1530 |
-
stopObserving: function() {
|
1531 |
-
Event.stopObserving.apply(Event, arguments);
|
1532 |
-
return $A(arguments).first();
|
1533 |
-
},
|
1534 |
-
|
1535 |
-
// removes whitespace-only text node children
|
1536 |
-
cleanWhitespace: function(element) {
|
1537 |
-
element = $(element);
|
1538 |
-
var node = element.firstChild;
|
1539 |
-
while (node) {
|
1540 |
-
var nextNode = node.nextSibling;
|
1541 |
-
if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
|
1542 |
-
element.removeChild(node);
|
1543 |
-
node = nextNode;
|
1544 |
-
}
|
1545 |
-
return element;
|
1546 |
-
},
|
1547 |
-
|
1548 |
-
empty: function(element) {
|
1549 |
-
return $(element).innerHTML.blank();
|
1550 |
-
},
|
1551 |
-
|
1552 |
-
descendantOf: function(element, ancestor) {
|
1553 |
-
element = $(element), ancestor = $(ancestor);
|
1554 |
-
while (element = element.parentNode)
|
1555 |
-
if (element == ancestor) return true;
|
1556 |
-
return false;
|
1557 |
-
},
|
1558 |
-
|
1559 |
-
scrollTo: function(element) {
|
1560 |
-
element = $(element);
|
1561 |
-
var pos = Position.cumulativeOffset(element);
|
1562 |
-
window.scrollTo(pos[0], pos[1]);
|
1563 |
-
return element;
|
1564 |
-
},
|
1565 |
-
|
1566 |
-
getStyle: function(element, style) {
|
1567 |
-
element = $(element);
|
1568 |
-
style = style == 'float' ? 'cssFloat' : style.camelize();
|
1569 |
-
var value = element.style[style];
|
1570 |
-
if (!value) {
|
1571 |
-
var css = document.defaultView.getComputedStyle(element, null);
|
1572 |
-
value = css ? css[style] : null;
|
1573 |
-
}
|
1574 |
-
if (style == 'opacity') return value ? parseFloat(value) : 1.0;
|
1575 |
-
return value == 'auto' ? null : value;
|
1576 |
-
},
|
1577 |
-
|
1578 |
-
getOpacity: function(element) {
|
1579 |
-
return $(element).getStyle('opacity');
|
1580 |
-
},
|
1581 |
-
|
1582 |
-
setStyle: function(element, styles, camelized) {
|
1583 |
-
element = $(element);
|
1584 |
-
var elementStyle = element.style;
|
1585 |
-
|
1586 |
-
for (var property in styles)
|
1587 |
-
if (property == 'opacity') element.setOpacity(styles[property])
|
1588 |
-
else
|
1589 |
-
elementStyle[(property == 'float' || property == 'cssFloat') ?
|
1590 |
-
(elementStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat') :
|
1591 |
-
(camelized ? property : property.camelize())] = styles[property];
|
1592 |
-
|
1593 |
-
return element;
|
1594 |
-
},
|
1595 |
-
|
1596 |
-
setOpacity: function(element, value) {
|
1597 |
-
element = $(element);
|
1598 |
-
element.style.opacity = (value == 1 || value === '') ? '' :
|
1599 |
-
(value < 0.00001) ? 0 : value;
|
1600 |
-
return element;
|
1601 |
-
},
|
1602 |
-
|
1603 |
-
getDimensions: function(element) {
|
1604 |
-
element = $(element);
|
1605 |
-
var display = $(element).getStyle('display');
|
1606 |
-
if (display != 'none' && display != null) // Safari bug
|
1607 |
-
return {width: element.offsetWidth, height: element.offsetHeight};
|
1608 |
-
|
1609 |
-
// All *Width and *Height properties give 0 on elements with display none,
|
1610 |
-
// so enable the element temporarily
|
1611 |
-
var els = element.style;
|
1612 |
-
var originalVisibility = els.visibility;
|
1613 |
-
var originalPosition = els.position;
|
1614 |
-
var originalDisplay = els.display;
|
1615 |
-
els.visibility = 'hidden';
|
1616 |
-
els.position = 'absolute';
|
1617 |
-
els.display = 'block';
|
1618 |
-
var originalWidth = element.clientWidth;
|
1619 |
-
var originalHeight = element.clientHeight;
|
1620 |
-
els.display = originalDisplay;
|
1621 |
-
els.position = originalPosition;
|
1622 |
-
els.visibility = originalVisibility;
|
1623 |
-
return {width: originalWidth, height: originalHeight};
|
1624 |
-
},
|
1625 |
-
|
1626 |
-
makePositioned: function(element) {
|
1627 |
-
element = $(element);
|
1628 |
-
var pos = Element.getStyle(element, 'position');
|
1629 |
-
if (pos == 'static' || !pos) {
|
1630 |
-
element._madePositioned = true;
|
1631 |
-
element.style.position = 'relative';
|
1632 |
-
// Opera returns the offset relative to the positioning context, when an
|
1633 |
-
// element is position relative but top and left have not been defined
|
1634 |
-
if (window.opera) {
|
1635 |
-
element.style.top = 0;
|
1636 |
-
element.style.left = 0;
|
1637 |
-
}
|
1638 |
-
}
|
1639 |
-
return element;
|
1640 |
-
},
|
1641 |
-
|
1642 |
-
undoPositioned: function(element) {
|
1643 |
-
element = $(element);
|
1644 |
-
if (element._madePositioned) {
|
1645 |
-
element._madePositioned = undefined;
|
1646 |
-
element.style.position =
|
1647 |
-
element.style.top =
|
1648 |
-
element.style.left =
|
1649 |
-
element.style.bottom =
|
1650 |
-
element.style.right = '';
|
1651 |
-
}
|
1652 |
-
return element;
|
1653 |
-
},
|
1654 |
-
|
1655 |
-
makeClipping: function(element) {
|
1656 |
-
element = $(element);
|
1657 |
-
if (element._overflow) return element;
|
1658 |
-
element._overflow = element.style.overflow || 'auto';
|
1659 |
-
if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
|
1660 |
-
element.style.overflow = 'hidden';
|
1661 |
-
return element;
|
1662 |
-
},
|
1663 |
-
|
1664 |
-
undoClipping: function(element) {
|
1665 |
-
element = $(element);
|
1666 |
-
if (!element._overflow) return element;
|
1667 |
-
element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
|
1668 |
-
element._overflow = null;
|
1669 |
-
return element;
|
1670 |
-
}
|
1671 |
-
};
|
1672 |
-
|
1673 |
-
Object.extend(Element.Methods, {
|
1674 |
-
childOf: Element.Methods.descendantOf,
|
1675 |
-
childElements: Element.Methods.immediateDescendants
|
1676 |
-
});
|
1677 |
-
|
1678 |
-
if (Prototype.Browser.Opera) {
|
1679 |
-
Element.Methods._getStyle = Element.Methods.getStyle;
|
1680 |
-
Element.Methods.getStyle = function(element, style) {
|
1681 |
-
switch(style) {
|
1682 |
-
case 'left':
|
1683 |
-
case 'top':
|
1684 |
-
case 'right':
|
1685 |
-
case 'bottom':
|
1686 |
-
if (Element._getStyle(element, 'position') == 'static') return null;
|
1687 |
-
default: return Element._getStyle(element, style);
|
1688 |
-
}
|
1689 |
-
};
|
1690 |
-
}
|
1691 |
-
else if (Prototype.Browser.IE) {
|
1692 |
-
Element.Methods.getStyle = function(element, style) {
|
1693 |
-
element = $(element);
|
1694 |
-
style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
|
1695 |
-
var value = element.style[style];
|
1696 |
-
if (!value && element.currentStyle) value = element.currentStyle[style];
|
1697 |
-
|
1698 |
-
if (style == 'opacity') {
|
1699 |
-
if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
|
1700 |
-
if (value[1]) return parseFloat(value[1]) / 100;
|
1701 |
-
return 1.0;
|
1702 |
-
}
|
1703 |
-
|
1704 |
-
if (value == 'auto') {
|
1705 |
-
if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
|
1706 |
-
return element['offset'+style.capitalize()] + 'px';
|
1707 |
-
return null;
|
1708 |
-
}
|
1709 |
-
return value;
|
1710 |
-
};
|
1711 |
-
|
1712 |
-
Element.Methods.setOpacity = function(element, value) {
|
1713 |
-
element = $(element);
|
1714 |
-
var filter = element.getStyle('filter'), style = element.style;
|
1715 |
-
if (value == 1 || value === '') {
|
1716 |
-
style.filter = filter.replace(/alpha\([^\)]*\)/gi,'');
|
1717 |
-
return element;
|
1718 |
-
} else if (value < 0.00001) value = 0;
|
1719 |
-
style.filter = filter.replace(/alpha\([^\)]*\)/gi, '') +
|
1720 |
-
'alpha(opacity=' + (value * 100) + ')';
|
1721 |
-
return element;
|
1722 |
-
};
|
1723 |
-
|
1724 |
-
// IE is missing .innerHTML support for TABLE-related elements
|
1725 |
-
Element.Methods.update = function(element, html) {
|
1726 |
-
element = $(element);
|
1727 |
-
html = typeof html == 'undefined' ? '' : html.toString();
|
1728 |
-
var tagName = element.tagName.toUpperCase();
|
1729 |
-
if (['THEAD','TBODY','TR','TD'].include(tagName)) {
|
1730 |
-
var div = document.createElement('div');
|
1731 |
-
switch (tagName) {
|
1732 |
-
case 'THEAD':
|
1733 |
-
case 'TBODY':
|
1734 |
-
div.innerHTML = '<table><tbody>' + html.stripScripts() + '</tbody></table>';
|
1735 |
-
depth = 2;
|
1736 |
-
break;
|
1737 |
-
case 'TR':
|
1738 |
-
div.innerHTML = '<table><tbody><tr>' + html.stripScripts() + '</tr></tbody></table>';
|
1739 |
-
depth = 3;
|
1740 |
-
break;
|
1741 |
-
case 'TD':
|
1742 |
-
div.innerHTML = '<table><tbody><tr><td>' + html.stripScripts() + '</td></tr></tbody></table>';
|
1743 |
-
depth = 4;
|
1744 |
-
}
|
1745 |
-
$A(element.childNodes).each(function(node) { element.removeChild(node) });
|
1746 |
-
depth.times(function() { div = div.firstChild });
|
1747 |
-
$A(div.childNodes).each(function(node) { element.appendChild(node) });
|
1748 |
-
} else {
|
1749 |
-
element.innerHTML = html.stripScripts();
|
1750 |
-
}
|
1751 |
-
setTimeout(function() { html.evalScripts() }, 10);
|
1752 |
-
return element;
|
1753 |
-
}
|
1754 |
-
}
|
1755 |
-
else if (Prototype.Browser.Gecko) {
|
1756 |
-
Element.Methods.setOpacity = function(element, value) {
|
1757 |
-
element = $(element);
|
1758 |
-
element.style.opacity = (value == 1) ? 0.999999 :
|
1759 |
-
(value === '') ? '' : (value < 0.00001) ? 0 : value;
|
1760 |
-
return element;
|
1761 |
-
};
|
1762 |
-
}
|
1763 |
-
|
1764 |
-
Element._attributeTranslations = {
|
1765 |
-
names: {
|
1766 |
-
colspan: "colSpan",
|
1767 |
-
rowspan: "rowSpan",
|
1768 |
-
valign: "vAlign",
|
1769 |
-
datetime: "dateTime",
|
1770 |
-
accesskey: "accessKey",
|
1771 |
-
tabindex: "tabIndex",
|
1772 |
-
enctype: "encType",
|
1773 |
-
maxlength: "maxLength",
|
1774 |
-
readonly: "readOnly",
|
1775 |
-
longdesc: "longDesc"
|
1776 |
-
},
|
1777 |
-
values: {
|
1778 |
-
_getAttr: function(element, attribute) {
|
1779 |
-
return element.getAttribute(attribute, 2);
|
1780 |
-
},
|
1781 |
-
_flag: function(element, attribute) {
|
1782 |
-
return $(element).hasAttribute(attribute) ? attribute : null;
|
1783 |
-
},
|
1784 |
-
style: function(element) {
|
1785 |
-
return element.style.cssText.toLowerCase();
|
1786 |
-
},
|
1787 |
-
title: function(element) {
|
1788 |
-
var node = element.getAttributeNode('title');
|
1789 |
-
return node.specified ? node.nodeValue : null;
|
1790 |
-
}
|
1791 |
-
}
|
1792 |
-
};
|
1793 |
-
|
1794 |
-
(function() {
|
1795 |
-
Object.extend(this, {
|
1796 |
-
href: this._getAttr,
|
1797 |
-
src: this._getAttr,
|
1798 |
-
type: this._getAttr,
|
1799 |
-
disabled: this._flag,
|
1800 |
-
checked: this._flag,
|
1801 |
-
readonly: this._flag,
|
1802 |
-
multiple: this._flag
|
1803 |
-
});
|
1804 |
-
}).call(Element._attributeTranslations.values);
|
1805 |
-
|
1806 |
-
Element.Methods.Simulated = {
|
1807 |
-
hasAttribute: function(element, attribute) {
|
1808 |
-
var t = Element._attributeTranslations, node;
|
1809 |
-
attribute = t.names[attribute] || attribute;
|
1810 |
-
node = $(element).getAttributeNode(attribute);
|
1811 |
-
return node && node.specified;
|
1812 |
-
}
|
1813 |
-
};
|
1814 |
-
|
1815 |
-
Element.Methods.ByTag = {};
|
1816 |
-
|
1817 |
-
Object.extend(Element, Element.Methods);
|
1818 |
-
|
1819 |
-
if (!Prototype.BrowserFeatures.ElementExtensions &&
|
1820 |
-
document.createElement('div').__proto__) {
|
1821 |
-
window.HTMLElement = {};
|
1822 |
-
window.HTMLElement.prototype = document.createElement('div').__proto__;
|
1823 |
-
Prototype.BrowserFeatures.ElementExtensions = true;
|
1824 |
-
}
|
1825 |
-
|
1826 |
-
Element.hasAttribute = function(element, attribute) {
|
1827 |
-
if (element.hasAttribute) return element.hasAttribute(attribute);
|
1828 |
-
return Element.Methods.Simulated.hasAttribute(element, attribute);
|
1829 |
-
};
|
1830 |
-
|
1831 |
-
Element.addMethods = function(methods) {
|
1832 |
-
var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;
|
1833 |
-
|
1834 |
-
if (!methods) {
|
1835 |
-
Object.extend(Form, Form.Methods);
|
1836 |
-
Object.extend(Form.Element, Form.Element.Methods);
|
1837 |
-
Object.extend(Element.Methods.ByTag, {
|
1838 |
-
"FORM": Object.clone(Form.Methods),
|
1839 |
-
"INPUT": Object.clone(Form.Element.Methods),
|
1840 |
-
"SELECT": Object.clone(Form.Element.Methods),
|
1841 |
-
"TEXTAREA": Object.clone(Form.Element.Methods)
|
1842 |
-
});
|
1843 |
-
}
|
1844 |
-
|
1845 |
-
if (arguments.length == 2) {
|
1846 |
-
var tagName = methods;
|
1847 |
-
methods = arguments[1];
|
1848 |
-
}
|
1849 |
-
|
1850 |
-
if (!tagName) Object.extend(Element.Methods, methods || {});
|
1851 |
-
else {
|
1852 |
-
if (tagName.constructor == Array) tagName.each(extend);
|
1853 |
-
else extend(tagName);
|
1854 |
-
}
|
1855 |
-
|
1856 |
-
function extend(tagName) {
|
1857 |
-
tagName = tagName.toUpperCase();
|
1858 |
-
if (!Element.Methods.ByTag[tagName])
|
1859 |
-
Element.Methods.ByTag[tagName] = {};
|
1860 |
-
Object.extend(Element.Methods.ByTag[tagName], methods);
|
1861 |
-
}
|
1862 |
-
|
1863 |
-
function copy(methods, destination, onlyIfAbsent) {
|
1864 |
-
onlyIfAbsent = onlyIfAbsent || false;
|
1865 |
-
var cache = Element.extend.cache;
|
1866 |
-
for (var property in methods) {
|
1867 |
-
var value = methods[property];
|
1868 |
-
if (!onlyIfAbsent || !(property in destination))
|
1869 |
-
destination[property] = cache.findOrStore(value);
|
1870 |
-
}
|
1871 |
-
}
|
1872 |
-
|
1873 |
-
function findDOMClass(tagName) {
|
1874 |
-
var klass;
|
1875 |
-
var trans = {
|
1876 |
-
"OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
|
1877 |
-
"FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
|
1878 |
-
"DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
|
1879 |
-
"H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
|
1880 |
-
"INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
|
1881 |
-
"TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
|
1882 |
-
"TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
|
1883 |
-
"TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
|
1884 |
-
"FrameSet", "IFRAME": "IFrame"
|
1885 |
-
};
|
1886 |
-
if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
|
1887 |
-
if (window[klass]) return window[klass];
|
1888 |
-
klass = 'HTML' + tagName + 'Element';
|
1889 |
-
if (window[klass]) return window[klass];
|
1890 |
-
klass = 'HTML' + tagName.capitalize() + 'Element';
|
1891 |
-
if (window[klass]) return window[klass];
|
1892 |
-
|
1893 |
-
window[klass] = {};
|
1894 |
-
window[klass].prototype = document.createElement(tagName).__proto__;
|
1895 |
-
return window[klass];
|
1896 |
-
}
|
1897 |
-
|
1898 |
-
if (F.ElementExtensions) {
|
1899 |
-
copy(Element.Methods, HTMLElement.prototype);
|
1900 |
-
copy(Element.Methods.Simulated, HTMLElement.prototype, true);
|
1901 |
-
}
|
1902 |
-
|
1903 |
-
if (F.SpecificElementExtensions) {
|
1904 |
-
for (var tag in Element.Methods.ByTag) {
|
1905 |
-
var klass = findDOMClass(tag);
|
1906 |
-
if (typeof klass == "undefined") continue;
|
1907 |
-
copy(T[tag], klass.prototype);
|
1908 |
-
}
|
1909 |
-
}
|
1910 |
-
|
1911 |
-
Object.extend(Element, Element.Methods);
|
1912 |
-
delete Element.ByTag;
|
1913 |
-
};
|
1914 |
-
|
1915 |
-
var Toggle = { display: Element.toggle };
|
1916 |
-
|
1917 |
-
/*--------------------------------------------------------------------------*/
|
1918 |
-
|
1919 |
-
Abstract.Insertion = function(adjacency) {
|
1920 |
-
this.adjacency = adjacency;
|
1921 |
-
}
|
1922 |
-
|
1923 |
-
Abstract.Insertion.prototype = {
|
1924 |
-
initialize: function(element, content) {
|
1925 |
-
this.element = $(element);
|
1926 |
-
this.content = content.stripScripts();
|
1927 |
-
|
1928 |
-
if (this.adjacency && this.element.insertAdjacentHTML) {
|
1929 |
-
try {
|
1930 |
-
this.element.insertAdjacentHTML(this.adjacency, this.content);
|
1931 |
-
} catch (e) {
|
1932 |
-
var tagName = this.element.tagName.toUpperCase();
|
1933 |
-
if (['TBODY', 'TR'].include(tagName)) {
|
1934 |
-
this.insertContent(this.contentFromAnonymousTable());
|
1935 |
-
} else {
|
1936 |
-
throw e;
|
1937 |
-
}
|
1938 |
-
}
|
1939 |
-
} else {
|
1940 |
-
this.range = this.element.ownerDocument.createRange();
|
1941 |
-
if (this.initializeRange) this.initializeRange();
|
1942 |
-
this.insertContent([this.range.createContextualFragment(this.content)]);
|
1943 |
-
}
|
1944 |
-
|
1945 |
-
setTimeout(function() {content.evalScripts()}, 10);
|
1946 |
-
},
|
1947 |
-
|
1948 |
-
contentFromAnonymousTable: function() {
|
1949 |
-
var div = document.createElement('div');
|
1950 |
-
div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
|
1951 |
-
return $A(div.childNodes[0].childNodes[0].childNodes);
|
1952 |
-
}
|
1953 |
-
}
|
1954 |
-
|
1955 |
-
var Insertion = new Object();
|
1956 |
-
|
1957 |
-
Insertion.Before = Class.create();
|
1958 |
-
Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
|
1959 |
-
initializeRange: function() {
|
1960 |
-
this.range.setStartBefore(this.element);
|
1961 |
-
},
|
1962 |
-
|
1963 |
-
insertContent: function(fragments) {
|
1964 |
-
fragments.each((function(fragment) {
|
1965 |
-
this.element.parentNode.insertBefore(fragment, this.element);
|
1966 |
-
}).bind(this));
|
1967 |
-
}
|
1968 |
-
});
|
1969 |
-
|
1970 |
-
Insertion.Top = Class.create();
|
1971 |
-
Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
|
1972 |
-
initializeRange: function() {
|
1973 |
-
this.range.selectNodeContents(this.element);
|
1974 |
-
this.range.collapse(true);
|
1975 |
-
},
|
1976 |
-
|
1977 |
-
insertContent: function(fragments) {
|
1978 |
-
fragments.reverse(false).each((function(fragment) {
|
1979 |
-
this.element.insertBefore(fragment, this.element.firstChild);
|
1980 |
-
}).bind(this));
|
1981 |
-
}
|
1982 |
-
});
|
1983 |
-
|
1984 |
-
Insertion.Bottom = Class.create();
|
1985 |
-
Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
|
1986 |
-
initializeRange: function() {
|
1987 |
-
this.range.selectNodeContents(this.element);
|
1988 |
-
this.range.collapse(this.element);
|
1989 |
-
},
|
1990 |
-
|
1991 |
-
insertContent: function(fragments) {
|
1992 |
-
fragments.each((function(fragment) {
|
1993 |
-
this.element.appendChild(fragment);
|
1994 |
-
}).bind(this));
|
1995 |
-
}
|
1996 |
-
});
|
1997 |
-
|
1998 |
-
Insertion.After = Class.create();
|
1999 |
-
Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
|
2000 |
-
initializeRange: function() {
|
2001 |
-
this.range.setStartAfter(this.element);
|
2002 |
-
},
|
2003 |
-
|
2004 |
-
insertContent: function(fragments) {
|
2005 |
-
fragments.each((function(fragment) {
|
2006 |
-
this.element.parentNode.insertBefore(fragment,
|
2007 |
-
this.element.nextSibling);
|
2008 |
-
}).bind(this));
|
2009 |
-
}
|
2010 |
-
});
|
2011 |
-
|
2012 |
-
/*--------------------------------------------------------------------------*/
|
2013 |
-
|
2014 |
-
Element.ClassNames = Class.create();
|
2015 |
-
Element.ClassNames.prototype = {
|
2016 |
-
initialize: function(element) {
|
2017 |
-
this.element = $(element);
|
2018 |
-
},
|
2019 |
-
|
2020 |
-
_each: function(iterator) {
|
2021 |
-
this.element.className.split(/\s+/).select(function(name) {
|
2022 |
-
return name.length > 0;
|
2023 |
-
})._each(iterator);
|
2024 |
-
},
|
2025 |
-
|
2026 |
-
set: function(className) {
|
2027 |
-
this.element.className = className;
|
2028 |
-
},
|
2029 |
-
|
2030 |
-
add: function(classNameToAdd) {
|
2031 |
-
if (this.include(classNameToAdd)) return;
|
2032 |
-
this.set($A(this).concat(classNameToAdd).join(' '));
|
2033 |
-
},
|
2034 |
-
|
2035 |
-
remove: function(classNameToRemove) {
|
2036 |
-
if (!this.include(classNameToRemove)) return;
|
2037 |
-
this.set($A(this).without(classNameToRemove).join(' '));
|
2038 |
-
},
|
2039 |
-
|
2040 |
-
toString: function() {
|
2041 |
-
return $A(this).join(' ');
|
2042 |
-
}
|
2043 |
-
};
|
2044 |
-
|
2045 |
-
Object.extend(Element.ClassNames.prototype, Enumerable);
|
2046 |
-
/* Portions of the Selector class are derived from Jack Slocum’s DomQuery,
|
2047 |
-
* part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
|
2048 |
-
* license. Please see http://www.yui-ext.com/ for more information. */
|
2049 |
-
|
2050 |
-
var Selector = Class.create();
|
2051 |
-
|
2052 |
-
Selector.prototype = {
|
2053 |
-
initialize: function(expression) {
|
2054 |
-
this.expression = expression.strip();
|
2055 |
-
this.compileMatcher();
|
2056 |
-
},
|
2057 |
-
|
2058 |
-
compileMatcher: function() {
|
2059 |
-
// Selectors with namespaced attributes can't use the XPath version
|
2060 |
-
if (Prototype.BrowserFeatures.XPath && !(/\[[\w-]*?:/).test(this.expression))
|
2061 |
-
return this.compileXPathMatcher();
|
2062 |
-
|
2063 |
-
var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
|
2064 |
-
c = Selector.criteria, le, p, m;
|
2065 |
-
|
2066 |
-
if (Selector._cache[e]) {
|
2067 |
-
this.matcher = Selector._cache[e]; return;
|
2068 |
-
}
|
2069 |
-
this.matcher = ["this.matcher = function(root) {",
|
2070 |
-
"var r = root, h = Selector.handlers, c = false, n;"];
|
2071 |
-
|
2072 |
-
while (e && le != e && (/\S/).test(e)) {
|
2073 |
-
le = e;
|
2074 |
-
for (var i in ps) {
|
2075 |
-
p = ps[i];
|
2076 |
-
if (m = e.match(p)) {
|
2077 |
-
this.matcher.push(typeof c[i] == 'function' ? c[i](m) :
|
2078 |
-
new Template(c[i]).evaluate(m));
|
2079 |
-
e = e.replace(m[0], '');
|
2080 |
-
break;
|
2081 |
-
}
|
2082 |
-
}
|
2083 |
-
}
|
2084 |
-
|
2085 |
-
this.matcher.push("return h.unique(n);\n}");
|
2086 |
-
eval(this.matcher.join('\n'));
|
2087 |
-
Selector._cache[this.expression] = this.matcher;
|
2088 |
-
},
|
2089 |
-
|
2090 |
-
compileXPathMatcher: function() {
|
2091 |
-
var e = this.expression, ps = Selector.patterns,
|
2092 |
-
x = Selector.xpath, le, m;
|
2093 |
-
|
2094 |
-
if (Selector._cache[e]) {
|
2095 |
-
this.xpath = Selector._cache[e]; return;
|
2096 |
-
}
|
2097 |
-
|
2098 |
-
this.matcher = ['.//*'];
|
2099 |
-
while (e && le != e && (/\S/).test(e)) {
|
2100 |
-
le = e;
|
2101 |
-
for (var i in ps) {
|
2102 |
-
if (m = e.match(ps[i])) {
|
2103 |
-
this.matcher.push(typeof x[i] == 'function' ? x[i](m) :
|
2104 |
-
new Template(x[i]).evaluate(m));
|
2105 |
-
e = e.replace(m[0], '');
|
2106 |
-
break;
|
2107 |
-
}
|
2108 |
-
}
|
2109 |
-
}
|
2110 |
-
|
2111 |
-
this.xpath = this.matcher.join('');
|
2112 |
-
Selector._cache[this.expression] = this.xpath;
|
2113 |
-
},
|
2114 |
-
|
2115 |
-
findElements: function(root) {
|
2116 |
-
root = root || document;
|
2117 |
-
if (this.xpath) return document._getElementsByXPath(this.xpath, root);
|
2118 |
-
return this.matcher(root);
|
2119 |
-
},
|
2120 |
-
|
2121 |
-
match: function(element) {
|
2122 |
-
return this.findElements(document).include(element);
|
2123 |
-
},
|
2124 |
-
|
2125 |
-
toString: function() {
|
2126 |
-
return this.expression;
|
2127 |
-
},
|
2128 |
-
|
2129 |
-
inspect: function() {
|
2130 |
-
return "#<Selector:" + this.expression.inspect() + ">";
|
2131 |
-
}
|
2132 |
-
};
|
2133 |
-
|
2134 |
-
Object.extend(Selector, {
|
2135 |
-
_cache: {},
|
2136 |
-
|
2137 |
-
xpath: {
|
2138 |
-
descendant: "//*",
|
2139 |
-
child: "/*",
|
2140 |
-
adjacent: "/following-sibling::*[1]",
|
2141 |
-
laterSibling: '/following-sibling::*',
|
2142 |
-
tagName: function(m) {
|
2143 |
-
if (m[1] == '*') return '';
|
2144 |
-
return "[local-name()='" + m[1].toLowerCase() +
|
2145 |
-
"' or local-name()='" + m[1].toUpperCase() + "']";
|
2146 |
-
},
|
2147 |
-
className: "[contains(concat(' ', @class, ' '), ' #{1} ')]",
|
2148 |
-
id: "[@id='#{1}']",
|
2149 |
-
attrPresence: "[@#{1}]",
|
2150 |
-
attr: function(m) {
|
2151 |
-
m[3] = m[5] || m[6];
|
2152 |
-
return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
|
2153 |
-
},
|
2154 |
-
pseudo: function(m) {
|
2155 |
-
var h = Selector.xpath.pseudos[m[1]];
|
2156 |
-
if (!h) return '';
|
2157 |
-
if (typeof h === 'function') return h(m);
|
2158 |
-
return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
|
2159 |
-
},
|
2160 |
-
operators: {
|
2161 |
-
'=': "[@#{1}='#{3}']",
|
2162 |
-
'!=': "[@#{1}!='#{3}']",
|
2163 |
-
'^=': "[starts-with(@#{1}, '#{3}')]",
|
2164 |
-
'$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']",
|
2165 |
-
'*=': "[contains(@#{1}, '#{3}')]",
|
2166 |
-
'~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]",
|
2167 |
-
'|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]"
|
2168 |
-
},
|
2169 |
-
pseudos: {
|
2170 |
-
'first-child': '[not(preceding-sibling::*)]',
|
2171 |
-
'last-child': '[not(following-sibling::*)]',
|
2172 |
-
'only-child': '[not(preceding-sibling::* or following-sibling::*)]',
|
2173 |
-
'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",
|
2174 |
-
'checked': "[@checked]",
|
2175 |
-
'disabled': "[@disabled]",
|
2176 |
-
'enabled': "[not(@disabled)]",
|
2177 |
-
'not': function(m) {
|
2178 |
-
var e = m[6], p = Selector.patterns,
|
2179 |
-
x = Selector.xpath, le, m, v;
|
2180 |
-
|
2181 |
-
var exclusion = [];
|
2182 |
-
while (e && le != e && (/\S/).test(e)) {
|
2183 |
-
le = e;
|
2184 |
-
for (var i in p) {
|
2185 |
-
if (m = e.match(p[i])) {
|
2186 |
-
v = typeof x[i] == 'function' ? x[i](m) : new Template(x[i]).evaluate(m);
|
2187 |
-
exclusion.push("(" + v.substring(1, v.length - 1) + ")");
|
2188 |
-
e = e.replace(m[0], '');
|
2189 |
-
break;
|
2190 |
-
}
|
2191 |
-
}
|
2192 |
-
}
|
2193 |
-
return "[not(" + exclusion.join(" and ") + ")]";
|
2194 |
-
},
|
2195 |
-
'nth-child': function(m) {
|
2196 |
-
return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
|
2197 |
-
},
|
2198 |
-
'nth-last-child': function(m) {
|
2199 |
-
return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);
|
2200 |
-
},
|
2201 |
-
'nth-of-type': function(m) {
|
2202 |
-
return Selector.xpath.pseudos.nth("position() ", m);
|
2203 |
-
},
|
2204 |
-
'nth-last-of-type': function(m) {
|
2205 |
-
return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);
|
2206 |
-
},
|
2207 |
-
'first-of-type': function(m) {
|
2208 |
-
m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);
|
2209 |
-
},
|
2210 |
-
'last-of-type': function(m) {
|
2211 |
-
m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);
|
2212 |
-
},
|
2213 |
-
'only-of-type': function(m) {
|
2214 |
-
var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);
|
2215 |
-
},
|
2216 |
-
nth: function(fragment, m) {
|
2217 |
-
var mm, formula = m[6], predicate;
|
2218 |
-
if (formula == 'even') formula = '2n+0';
|
2219 |
-
if (formula == 'odd') formula = '2n+1';
|
2220 |
-
if (mm = formula.match(/^(\d+)$/)) // digit only
|
2221 |
-
return '[' + fragment + "= " + mm[1] + ']';
|
2222 |
-
if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
|
2223 |
-
if (mm[1] == "-") mm[1] = -1;
|
2224 |
-
var a = mm[1] ? Number(mm[1]) : 1;
|
2225 |
-
var b = mm[2] ? Number(mm[2]) : 0;
|
2226 |
-
predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +
|
2227 |
-
"((#{fragment} - #{b}) div #{a} >= 0)]";
|
2228 |
-
return new Template(predicate).evaluate({
|
2229 |
-
fragment: fragment, a: a, b: b });
|
2230 |
-
}
|
2231 |
-
}
|
2232 |
-
}
|
2233 |
-
},
|
2234 |
-
|
2235 |
-
criteria: {
|
2236 |
-
tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;',
|
2237 |
-
className: 'n = h.className(n, r, "#{1}", c); c = false;',
|
2238 |
-
id: 'n = h.id(n, r, "#{1}", c); c = false;',
|
2239 |
-
attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;',
|
2240 |
-
attr: function(m) {
|
2241 |
-
m[3] = (m[5] || m[6]);
|
2242 |
-
return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m);
|
2243 |
-
},
|
2244 |
-
pseudo: function(m) {
|
2245 |
-
if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
|
2246 |
-
return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
|
2247 |
-
},
|
2248 |
-
descendant: 'c = "descendant";',
|
2249 |
-
child: 'c = "child";',
|
2250 |
-
adjacent: 'c = "adjacent";',
|
2251 |
-
laterSibling: 'c = "laterSibling";'
|
2252 |
-
},
|
2253 |
-
|
2254 |
-
patterns: {
|
2255 |
-
// combinators must be listed first
|
2256 |
-
// (and descendant needs to be last combinator)
|
2257 |
-
laterSibling: /^\s*~\s*/,
|
2258 |
-
child: /^\s*>\s*/,
|
2259 |
-
adjacent: /^\s*\+\s*/,
|
2260 |
-
descendant: /^\s/,
|
2261 |
-
|
2262 |
-
// selectors follow
|
2263 |
-
tagName: /^\s*(\*|[\w\-]+)(\b|$)?/,
|
2264 |
-
id: /^#([\w\-\*]+)(\b|$)/,
|
2265 |
-
className: /^\.([\w\-\*]+)(\b|$)/,
|
2266 |
-
pseudo: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|\s|(?=:))/,
|
2267 |
-
attrPresence: /^\[([\w]+)\]/,
|
2268 |
-
attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\]]*?)\4|([^'"][^\]]*?)))?\]/
|
2269 |
-
},
|
2270 |
-
|
2271 |
-
handlers: {
|
2272 |
-
// UTILITY FUNCTIONS
|
2273 |
-
// joins two collections
|
2274 |
-
concat: function(a, b) {
|
2275 |
-
for (var i = 0, node; node = b[i]; i++)
|
2276 |
-
a.push(node);
|
2277 |
-
return a;
|
2278 |
-
},
|
2279 |
-
|
2280 |
-
// marks an array of nodes for counting
|
2281 |
-
mark: function(nodes) {
|
2282 |
-
for (var i = 0, node; node = nodes[i]; i++)
|
2283 |
-
node._counted = true;
|
2284 |
-
return nodes;
|
2285 |
-
},
|
2286 |
-
|
2287 |
-
unmark: function(nodes) {
|
2288 |
-
for (var i = 0, node; node = nodes[i]; i++)
|
2289 |
-
node._counted = undefined;
|
2290 |
-
return nodes;
|
2291 |
-
},
|
2292 |
-
|
2293 |
-
// mark each child node with its position (for nth calls)
|
2294 |
-
// "ofType" flag indicates whether we're indexing for nth-of-type
|
2295 |
-
// rather than nth-child
|
2296 |
-
index: function(parentNode, reverse, ofType) {
|
2297 |
-
parentNode._counted = true;
|
2298 |
-
if (reverse) {
|
2299 |
-
for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
|
2300 |
-
node = nodes[i];
|
2301 |
-
if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
|
2302 |
-
}
|
2303 |
-
} else {
|
2304 |
-
for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
|
2305 |
-
if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
|
2306 |
-
}
|
2307 |
-
},
|
2308 |
-
|
2309 |
-
// filters out duplicates and extends all nodes
|
2310 |
-
unique: function(nodes) {
|
2311 |
-
if (nodes.length == 0) return nodes;
|
2312 |
-
var results = [], n;
|
2313 |
-
for (var i = 0, l = nodes.length; i < l; i++)
|
2314 |
-
if (!(n = nodes[i])._counted) {
|
2315 |
-
n._counted = true;
|
2316 |
-
results.push(Element.extend(n));
|
2317 |
-
}
|
2318 |
-
return Selector.handlers.unmark(results);
|
2319 |
-
},
|
2320 |
-
|
2321 |
-
// COMBINATOR FUNCTIONS
|
2322 |
-
descendant: function(nodes) {
|
2323 |
-
var h = Selector.handlers;
|
2324 |
-
for (var i = 0, results = [], node; node = nodes[i]; i++)
|
2325 |
-
h.concat(results, node.getElementsByTagName('*'));
|
2326 |
-
return results;
|
2327 |
-
},
|
2328 |
-
|
2329 |
-
child: function(nodes) {
|
2330 |
-
var h = Selector.handlers;
|
2331 |
-
for (var i = 0, results = [], node; node = nodes[i]; i++) {
|
2332 |
-
for (var j = 0, children = [], child; child = node.childNodes[j]; j++)
|
2333 |
-
if (child.nodeType == 1 && child.tagName != '!') results.push(child);
|
2334 |
-
}
|
2335 |
-
return results;
|
2336 |
-
},
|
2337 |
-
|
2338 |
-
adjacent: function(nodes) {
|
2339 |
-
for (var i = 0, results = [], node; node = nodes[i]; i++) {
|
2340 |
-
var next = this.nextElementSibling(node);
|
2341 |
-
if (next) results.push(next);
|
2342 |
-
}
|
2343 |
-
return results;
|
2344 |
-
},
|
2345 |
-
|
2346 |
-
laterSibling: function(nodes) {
|
2347 |
-
var h = Selector.handlers;
|
2348 |
-
for (var i = 0, results = [], node; node = nodes[i]; i++)
|
2349 |
-
h.concat(results, Element.nextSiblings(node));
|
2350 |
-
return results;
|
2351 |
-
},
|
2352 |
-
|
2353 |
-
nextElementSibling: function(node) {
|
2354 |
-
while (node = node.nextSibling)
|
2355 |
-
if (node.nodeType == 1) return node;
|
2356 |
-
return null;
|
2357 |
-
},
|
2358 |
-
|
2359 |
-
previousElementSibling: function(node) {
|
2360 |
-
while (node = node.previousSibling)
|
2361 |
-
if (node.nodeType == 1) return node;
|
2362 |
-
return null;
|
2363 |
-
},
|
2364 |
-
|
2365 |
-
// TOKEN FUNCTIONS
|
2366 |
-
tagName: function(nodes, root, tagName, combinator) {
|
2367 |
-
tagName = tagName.toUpperCase();
|
2368 |
-
var results = [], h = Selector.handlers;
|
2369 |
-
if (nodes) {
|
2370 |
-
if (combinator) {
|
2371 |
-
// fastlane for ordinary descendant combinators
|
2372 |
-
if (combinator == "descendant") {
|
2373 |
-
for (var i = 0, node; node = nodes[i]; i++)
|
2374 |
-
h.concat(results, node.getElementsByTagName(tagName));
|
2375 |
-
return results;
|
2376 |
-
} else nodes = this[combinator](nodes);
|
2377 |
-
if (tagName == "*") return nodes;
|
2378 |
-
}
|
2379 |
-
for (var i = 0, node; node = nodes[i]; i++)
|
2380 |
-
if (node.tagName.toUpperCase() == tagName) results.push(node);
|
2381 |
-
return results;
|
2382 |
-
} else return root.getElementsByTagName(tagName);
|
2383 |
-
},
|
2384 |
-
|
2385 |
-
id: function(nodes, root, id, combinator) {
|
2386 |
-
var targetNode = $(id), h = Selector.handlers;
|
2387 |
-
if (!nodes && root == document) return targetNode ? [targetNode] : [];
|
2388 |
-
if (nodes) {
|
2389 |
-
if (combinator) {
|
2390 |
-
if (combinator == 'child') {
|
2391 |
-
for (var i = 0, node; node = nodes[i]; i++)
|
2392 |
-
if (targetNode.parentNode == node) return [targetNode];
|
2393 |
-
} else if (combinator == 'descendant') {
|
2394 |
-
for (var i = 0, node; node = nodes[i]; i++)
|
2395 |
-
if (Element.descendantOf(targetNode, node)) return [targetNode];
|
2396 |
-
} else if (combinator == 'adjacent') {
|
2397 |
-
for (var i = 0, node; node = nodes[i]; i++)
|
2398 |
-
if (Selector.handlers.previousElementSibling(targetNode) == node)
|
2399 |
-
return [targetNode];
|
2400 |
-
} else nodes = h[combinator](nodes);
|
2401 |
-
}
|
2402 |
-
for (var i = 0, node; node = nodes[i]; i++)
|
2403 |
-
if (node == targetNode) return [targetNode];
|
2404 |
-
return [];
|
2405 |
-
}
|
2406 |
-
return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
|
2407 |
-
},
|
2408 |
-
|
2409 |
-
className: function(nodes, root, className, combinator) {
|
2410 |
-
if (nodes && combinator) nodes = this[combinator](nodes);
|
2411 |
-
return Selector.handlers.byClassName(nodes, root, className);
|
2412 |
-
},
|
2413 |
-
|
2414 |
-
byClassName: function(nodes, root, className) {
|
2415 |
-
if (!nodes) nodes = Selector.handlers.descendant([root]);
|
2416 |
-
var needle = ' ' + className + ' ';
|
2417 |
-
for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {
|
2418 |
-
nodeClassName = node.className;
|
2419 |
-
if (nodeClassName.length == 0) continue;
|
2420 |
-
if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
|
2421 |
-
results.push(node);
|
2422 |
-
}
|
2423 |
-
return results;
|
2424 |
-
},
|
2425 |
-
|
2426 |
-
attrPresence: function(nodes, root, attr) {
|
2427 |
-
var results = [];
|
2428 |
-
for (var i = 0, node; node = nodes[i]; i++)
|
2429 |
-
if (Element.hasAttribute(node, attr)) results.push(node);
|
2430 |
-
return results;
|
2431 |
-
},
|
2432 |
-
|
2433 |
-
attr: function(nodes, root, attr, value, operator) {
|
2434 |
-
if (!nodes) nodes = root.getElementsByTagName("*");
|
2435 |
-
var handler = Selector.operators[operator], results = [];
|
2436 |
-
for (var i = 0, node; node = nodes[i]; i++) {
|
2437 |
-
var nodeValue = Element.readAttribute(node, attr);
|
2438 |
-
if (nodeValue === null) continue;
|
2439 |
-
if (handler(nodeValue, value)) results.push(node);
|
2440 |
-
}
|
2441 |
-
return results;
|
2442 |
-
},
|
2443 |
-
|
2444 |
-
pseudo: function(nodes, name, value, root, combinator) {
|
2445 |
-
if (nodes && combinator) nodes = this[combinator](nodes);
|
2446 |
-
if (!nodes) nodes = root.getElementsByTagName("*");
|
2447 |
-
return Selector.pseudos[name](nodes, value, root);
|
2448 |
-
}
|
2449 |
-
},
|
2450 |
-
|
2451 |
-
pseudos: {
|
2452 |
-
'first-child': function(nodes, value, root) {
|
2453 |
-
for (var i = 0, results = [], node; node = nodes[i]; i++) {
|
2454 |
-
if (Selector.handlers.previousElementSibling(node)) continue;
|
2455 |
-
results.push(node);
|
2456 |
-
}
|
2457 |
-
return results;
|
2458 |
-
},
|
2459 |
-
'last-child': function(nodes, value, root) {
|
2460 |
-
for (var i = 0, results = [], node; node = nodes[i]; i++) {
|
2461 |
-
if (Selector.handlers.nextElementSibling(node)) continue;
|
2462 |
-
results.push(node);
|
2463 |
-
}
|
2464 |
-
return results;
|
2465 |
-
},
|
2466 |
-
'only-child': function(nodes, value, root) {
|
2467 |
-
var h = Selector.handlers;
|
2468 |
-
for (var i = 0, results = [], node; node = nodes[i]; i++)
|
2469 |
-
if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
|
2470 |
-
results.push(node);
|
2471 |
-
return results;
|
2472 |
-
},
|
2473 |
-
'nth-child': function(nodes, formula, root) {
|
2474 |
-
return Selector.pseudos.nth(nodes, formula, root);
|
2475 |
-
},
|
2476 |
-
'nth-last-child': function(nodes, formula, root) {
|
2477 |
-
return Selector.pseudos.nth(nodes, formula, root, true);
|
2478 |
-
},
|
2479 |
-
'nth-of-type': function(nodes, formula, root) {
|
2480 |
-
return Selector.pseudos.nth(nodes, formula, root, false, true);
|
2481 |
-
},
|
2482 |
-
'nth-last-of-type': function(nodes, formula, root) {
|
2483 |
-
return Selector.pseudos.nth(nodes, formula, root, true, true);
|
2484 |
-
},
|
2485 |
-
'first-of-type': function(nodes, formula, root) {
|
2486 |
-
return Selector.pseudos.nth(nodes, "1", root, false, true);
|
2487 |
-
},
|
2488 |
-
'last-of-type': function(nodes, formula, root) {
|
2489 |
-
return Selector.pseudos.nth(nodes, "1", root, true, true);
|
2490 |
-
},
|
2491 |
-
'only-of-type': function(nodes, formula, root) {
|
2492 |
-
var p = Selector.pseudos;
|
2493 |
-
return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
|
2494 |
-
},
|
2495 |
-
|
2496 |
-
// handles the an+b logic
|
2497 |
-
getIndices: function(a, b, total) {
|
2498 |
-
if (a == 0) return b > 0 ? [b] : [];
|
2499 |
-
return $R(1, total).inject([], function(memo, i) {
|
2500 |
-
if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);
|
2501 |
-
return memo;
|
2502 |
-
});
|
2503 |
-
},
|
2504 |
-
|
2505 |
-
// handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type
|
2506 |
-
nth: function(nodes, formula, root, reverse, ofType) {
|
2507 |
-
if (nodes.length == 0) return [];
|
2508 |
-
if (formula == 'even') formula = '2n+0';
|
2509 |
-
if (formula == 'odd') formula = '2n+1';
|
2510 |
-
var h = Selector.handlers, results = [], indexed = [], m;
|
2511 |
-
h.mark(nodes);
|
2512 |
-
for (var i = 0, node; node = nodes[i]; i++) {
|
2513 |
-
if (!node.parentNode._counted) {
|
2514 |
-
h.index(node.parentNode, reverse, ofType);
|
2515 |
-
indexed.push(node.parentNode);
|
2516 |
-
}
|
2517 |
-
}
|
2518 |
-
if (formula.match(/^\d+$/)) { // just a number
|
2519 |
-
formula = Number(formula);
|
2520 |
-
for (var i = 0, node; node = nodes[i]; i++)
|
2521 |
-
if (node.nodeIndex == formula) results.push(node);
|
2522 |
-
} else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
|
2523 |
-
if (m[1] == "-") m[1] = -1;
|
2524 |
-
var a = m[1] ? Number(m[1]) : 1;
|
2525 |
-
var b = m[2] ? Number(m[2]) : 0;
|
2526 |
-
var indices = Selector.pseudos.getIndices(a, b, nodes.length);
|
2527 |
-
for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {
|
2528 |
-
for (var j = 0; j < l; j++)
|
2529 |
-
if (node.nodeIndex == indices[j]) results.push(node);
|
2530 |
-
}
|
2531 |
-
}
|
2532 |
-
h.unmark(nodes);
|
2533 |
-
h.unmark(indexed);
|
2534 |
-
return results;
|
2535 |
-
},
|
2536 |
-
|
2537 |
-
'empty': function(nodes, value, root) {
|
2538 |
-
for (var i = 0, results = [], node; node = nodes[i]; i++) {
|
2539 |
-
// IE treats comments as element nodes
|
2540 |
-
if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue;
|
2541 |
-
results.push(node);
|
2542 |
-
}
|
2543 |
-
return results;
|
2544 |
-
},
|
2545 |
-
|
2546 |
-
'not': function(nodes, selector, root) {
|
2547 |
-
var h = Selector.handlers, selectorType, m;
|
2548 |
-
var exclusions = new Selector(selector).findElements(root);
|
2549 |
-
h.mark(exclusions);
|
2550 |
-
for (var i = 0, results = [], node; node = nodes[i]; i++)
|
2551 |
-
if (!node._counted) results.push(node);
|
2552 |
-
h.unmark(exclusions);
|
2553 |
-
return results;
|
2554 |
-
},
|
2555 |
-
|
2556 |
-
'enabled': function(nodes, value, root) {
|
2557 |
-
for (var i = 0, results = [], node; node = nodes[i]; i++)
|
2558 |
-
if (!node.disabled) results.push(node);
|
2559 |
-
return results;
|
2560 |
-
},
|
2561 |
-
|
2562 |
-
'disabled': function(nodes, value, root) {
|
2563 |
-
for (var i = 0, results = [], node; node = nodes[i]; i++)
|
2564 |
-
if (node.disabled) results.push(node);
|
2565 |
-
return results;
|
2566 |
-
},
|
2567 |
-
|
2568 |
-
'checked': function(nodes, value, root) {
|
2569 |
-
for (var i = 0, results = [], node; node = nodes[i]; i++)
|
2570 |
-
if (node.checked) results.push(node);
|
2571 |
-
return results;
|
2572 |
-
}
|
2573 |
-
},
|
2574 |
-
|
2575 |
-
operators: {
|
2576 |
-
'=': function(nv, v) { return nv == v; },
|
2577 |
-
'!=': function(nv, v) { return nv != v; },
|
2578 |
-
'^=': function(nv, v) { return nv.startsWith(v); },
|
2579 |
-
'$=': function(nv, v) { return nv.endsWith(v); },
|
2580 |
-
'*=': function(nv, v) { return nv.include(v); },
|
2581 |
-
'~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
|
2582 |
-
'|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
|
2583 |
-
},
|
2584 |
-
|
2585 |
-
matchElements: function(elements, expression) {
|
2586 |
-
var matches = new Selector(expression).findElements(), h = Selector.handlers;
|
2587 |
-
h.mark(matches);
|
2588 |
-
for (var i = 0, results = [], element; element = elements[i]; i++)
|
2589 |
-
if (element._counted) results.push(element);
|
2590 |
-
h.unmark(matches);
|
2591 |
-
return results;
|
2592 |
-
},
|
2593 |
-
|
2594 |
-
findElement: function(elements, expression, index) {
|
2595 |
-
if (typeof expression == 'number') {
|
2596 |
-
index = expression; expression = false;
|
2597 |
-
}
|
2598 |
-
return Selector.matchElements(elements, expression || '*')[index || 0];
|
2599 |
-
},
|
2600 |
-
|
2601 |
-
findChildElements: function(element, expressions) {
|
2602 |
-
var exprs = expressions.join(','), expressions = [];
|
2603 |
-
exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
|
2604 |
-
expressions.push(m[1].strip());
|
2605 |
-
});
|
2606 |
-
var results = [], h = Selector.handlers;
|
2607 |
-
for (var i = 0, l = expressions.length, selector; i < l; i++) {
|
2608 |
-
selector = new Selector(expressions[i].strip());
|
2609 |
-
h.concat(results, selector.findElements(element));
|
2610 |
-
}
|
2611 |
-
return (l > 1) ? h.unique(results) : results;
|
2612 |
-
}
|
2613 |
-
});
|
2614 |
-
|
2615 |
-
function $$() {
|
2616 |
-
return Selector.findChildElements(document, $A(arguments));
|
2617 |
-
}
|
2618 |
-
var Form = {
|
2619 |
-
reset: function(form) {
|
2620 |
-
$(form).reset();
|
2621 |
-
return form;
|
2622 |
-
},
|
2623 |
-
|
2624 |
-
serializeElements: function(elements, getHash) {
|
2625 |
-
var data = elements.inject({}, function(result, element) {
|
2626 |
-
if (!element.disabled && element.name) {
|
2627 |
-
var key = element.name, value = $(element).getValue();
|
2628 |
-
if (value != null) {
|
2629 |
-
if (key in result) {
|
2630 |
-
if (result[key].constructor != Array) result[key] = [result[key]];
|
2631 |
-
result[key].push(value);
|
2632 |
-
}
|
2633 |
-
else result[key] = value;
|
2634 |
-
}
|
2635 |
-
}
|
2636 |
-
return result;
|
2637 |
-
});
|
2638 |
-
|
2639 |
-
return getHash ? data : Hash.toQueryString(data);
|
2640 |
-
}
|
2641 |
-
};
|
2642 |
-
|
2643 |
-
Form.Methods = {
|
2644 |
-
serialize: function(form, getHash) {
|
2645 |
-
return Form.serializeElements(Form.getElements(form), getHash);
|
2646 |
-
},
|
2647 |
-
|
2648 |
-
getElements: function(form) {
|
2649 |
-
return $A($(form).getElementsByTagName('*')).inject([],
|
2650 |
-
function(elements, child) {
|
2651 |
-
if (Form.Element.Serializers[child.tagName.toLowerCase()])
|
2652 |
-
elements.push(Element.extend(child));
|
2653 |
-
return elements;
|
2654 |
-
}
|
2655 |
-
);
|
2656 |
-
},
|
2657 |
-
|
2658 |
-
getInputs: function(form, typeName, name) {
|
2659 |
-
form = $(form);
|
2660 |
-
var inputs = form.getElementsByTagName('input');
|
2661 |
-
|
2662 |
-
if (!typeName && !name) return $A(inputs).map(Element.extend);
|
2663 |
-
|
2664 |
-
for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
|
2665 |
-
var input = inputs[i];
|
2666 |
-
if ((typeName && input.type != typeName) || (name && input.name != name))
|
2667 |
-
continue;
|
2668 |
-
matchingInputs.push(Element.extend(input));
|
2669 |
-
}
|
2670 |
-
|
2671 |
-
return matchingInputs;
|
2672 |
-
},
|
2673 |
-
|
2674 |
-
disable: function(form) {
|
2675 |
-
form = $(form);
|
2676 |
-
Form.getElements(form).invoke('disable');
|
2677 |
-
return form;
|
2678 |
-
},
|
2679 |
-
|
2680 |
-
enable: function(form) {
|
2681 |
-
form = $(form);
|
2682 |
-
Form.getElements(form).invoke('enable');
|
2683 |
-
return form;
|
2684 |
-
},
|
2685 |
-
|
2686 |
-
findFirstElement: function(form) {
|
2687 |
-
return $(form).getElements().find(function(element) {
|
2688 |
-
return element.type != 'hidden' && !element.disabled &&
|
2689 |
-
['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
|
2690 |
-
});
|
2691 |
-
},
|
2692 |
-
|
2693 |
-
focusFirstElement: function(form) {
|
2694 |
-
form = $(form);
|
2695 |
-
form.findFirstElement().activate();
|
2696 |
-
return form;
|
2697 |
-
},
|
2698 |
-
|
2699 |
-
request: function(form, options) {
|
2700 |
-
form = $(form), options = Object.clone(options || {});
|
2701 |
-
|
2702 |
-
var params = options.parameters;
|
2703 |
-
options.parameters = form.serialize(true);
|
2704 |
-
|
2705 |
-
if (params) {
|
2706 |
-
if (typeof params == 'string') params = params.toQueryParams();
|
2707 |
-
Object.extend(options.parameters, params);
|
2708 |
-
}
|
2709 |
-
|
2710 |
-
if (form.hasAttribute('method') && !options.method)
|
2711 |
-
options.method = form.method;
|
2712 |
-
|
2713 |
-
return new Ajax.Request(form.readAttribute('action'), options);
|
2714 |
-
}
|
2715 |
-
}
|
2716 |
-
|
2717 |
-
/*--------------------------------------------------------------------------*/
|
2718 |
-
|
2719 |
-
Form.Element = {
|
2720 |
-
focus: function(element) {
|
2721 |
-
$(element).focus();
|
2722 |
-
return element;
|
2723 |
-
},
|
2724 |
-
|
2725 |
-
select: function(element) {
|
2726 |
-
$(element).select();
|
2727 |
-
return element;
|
2728 |
-
}
|
2729 |
-
}
|
2730 |
-
|
2731 |
-
Form.Element.Methods = {
|
2732 |
-
serialize: function(element) {
|
2733 |
-
element = $(element);
|
2734 |
-
if (!element.disabled && element.name) {
|
2735 |
-
var value = element.getValue();
|
2736 |
-
if (value != undefined) {
|
2737 |
-
var pair = {};
|
2738 |
-
pair[element.name] = value;
|
2739 |
-
return Hash.toQueryString(pair);
|
2740 |
-
}
|
2741 |
-
}
|
2742 |
-
return '';
|
2743 |
-
},
|
2744 |
-
|
2745 |
-
getValue: function(element) {
|
2746 |
-
element = $(element);
|
2747 |
-
var method = element.tagName.toLowerCase();
|
2748 |
-
return Form.Element.Serializers[method](element);
|
2749 |
-
},
|
2750 |
-
|
2751 |
-
clear: function(element) {
|
2752 |
-
$(element).value = '';
|
2753 |
-
return element;
|
2754 |
-
},
|
2755 |
-
|
2756 |
-
present: function(element) {
|
2757 |
-
return $(element).value != '';
|
2758 |
-
},
|
2759 |
-
|
2760 |
-
activate: function(element) {
|
2761 |
-
element = $(element);
|
2762 |
-
try {
|
2763 |
-
element.focus();
|
2764 |
-
if (element.select && (element.tagName.toLowerCase() != 'input' ||
|
2765 |
-
!['button', 'reset', 'submit'].include(element.type)))
|
2766 |
-
element.select();
|
2767 |
-
} catch (e) {}
|
2768 |
-
return element;
|
2769 |
-
},
|
2770 |
-
|
2771 |
-
disable: function(element) {
|
2772 |
-
element = $(element);
|
2773 |
-
element.blur();
|
2774 |
-
element.disabled = true;
|
2775 |
-
return element;
|
2776 |
-
},
|
2777 |
-
|
2778 |
-
enable: function(element) {
|
2779 |
-
element = $(element);
|
2780 |
-
element.disabled = false;
|
2781 |
-
return element;
|
2782 |
-
}
|
2783 |
-
}
|
2784 |
-
|
2785 |
-
/*--------------------------------------------------------------------------*/
|
2786 |
-
|
2787 |
-
var Field = Form.Element;
|
2788 |
-
var $F = Form.Element.Methods.getValue;
|
2789 |
-
|
2790 |
-
/*--------------------------------------------------------------------------*/
|
2791 |
-
|
2792 |
-
Form.Element.Serializers = {
|
2793 |
-
input: function(element) {
|
2794 |
-
switch (element.type.toLowerCase()) {
|
2795 |
-
case 'checkbox':
|
2796 |
-
case 'radio':
|
2797 |
-
return Form.Element.Serializers.inputSelector(element);
|
2798 |
-
default:
|
2799 |
-
return Form.Element.Serializers.textarea(element);
|
2800 |
-
}
|
2801 |
-
},
|
2802 |
-
|
2803 |
-
inputSelector: function(element) {
|
2804 |
-
return element.checked ? element.value : null;
|
2805 |
-
},
|
2806 |
-
|
2807 |
-
textarea: function(element) {
|
2808 |
-
return element.value;
|
2809 |
-
},
|
2810 |
-
|
2811 |
-
select: function(element) {
|
2812 |
-
return this[element.type == 'select-one' ?
|
2813 |
-
'selectOne' : 'selectMany'](element);
|
2814 |
-
},
|
2815 |
-
|
2816 |
-
selectOne: function(element) {
|
2817 |
-
var index = element.selectedIndex;
|
2818 |
-
return index >= 0 ? this.optionValue(element.options[index]) : null;
|
2819 |
-
},
|
2820 |
-
|
2821 |
-
selectMany: function(element) {
|
2822 |
-
var values, length = element.length;
|
2823 |
-
if (!length) return null;
|
2824 |
-
|
2825 |
-
for (var i = 0, values = []; i < length; i++) {
|
2826 |
-
var opt = element.options[i];
|
2827 |
-
if (opt.selected) values.push(this.optionValue(opt));
|
2828 |
-
}
|
2829 |
-
return values;
|
2830 |
-
},
|
2831 |
-
|
2832 |
-
optionValue: function(opt) {
|
2833 |
-
// extend element because hasAttribute may not be native
|
2834 |
-
return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
|
2835 |
-
}
|
2836 |
-
}
|
2837 |
-
|
2838 |
-
/*--------------------------------------------------------------------------*/
|
2839 |
-
|
2840 |
-
Abstract.TimedObserver = function() {}
|
2841 |
-
Abstract.TimedObserver.prototype = {
|
2842 |
-
initialize: function(element, frequency, callback) {
|
2843 |
-
this.frequency = frequency;
|
2844 |
-
this.element = $(element);
|
2845 |
-
this.callback = callback;
|
2846 |
-
|
2847 |
-
this.lastValue = this.getValue();
|
2848 |
-
this.registerCallback();
|
2849 |
-
},
|
2850 |
-
|
2851 |
-
registerCallback: function() {
|
2852 |
-
setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
|
2853 |
-
},
|
2854 |
-
|
2855 |
-
onTimerEvent: function() {
|
2856 |
-
var value = this.getValue();
|
2857 |
-
var changed = ('string' == typeof this.lastValue && 'string' == typeof value
|
2858 |
-
? this.lastValue != value : String(this.lastValue) != String(value));
|
2859 |
-
if (changed) {
|
2860 |
-
this.callback(this.element, value);
|
2861 |
-
this.lastValue = value;
|
2862 |
-
}
|
2863 |
-
}
|
2864 |
-
}
|
2865 |
-
|
2866 |
-
Form.Element.Observer = Class.create();
|
2867 |
-
Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
|
2868 |
-
getValue: function() {
|
2869 |
-
return Form.Element.getValue(this.element);
|
2870 |
-
}
|
2871 |
-
});
|
2872 |
-
|
2873 |
-
Form.Observer = Class.create();
|
2874 |
-
Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
|
2875 |
-
getValue: function() {
|
2876 |
-
return Form.serialize(this.element);
|
2877 |
-
}
|
2878 |
-
});
|
2879 |
-
|
2880 |
-
/*--------------------------------------------------------------------------*/
|
2881 |
-
|
2882 |
-
Abstract.EventObserver = function() {}
|
2883 |
-
Abstract.EventObserver.prototype = {
|
2884 |
-
initialize: function(element, callback) {
|
2885 |
-
this.element = $(element);
|
2886 |
-
this.callback = callback;
|
2887 |
-
|
2888 |
-
this.lastValue = this.getValue();
|
2889 |
-
if (this.element.tagName.toLowerCase() == 'form')
|
2890 |
-
this.registerFormCallbacks();
|
2891 |
-
else
|
2892 |
-
this.registerCallback(this.element);
|
2893 |
-
},
|
2894 |
-
|
2895 |
-
onElementEvent: function() {
|
2896 |
-
var value = this.getValue();
|
2897 |
-
if (this.lastValue != value) {
|
2898 |
-
this.callback(this.element, value);
|
2899 |
-
this.lastValue = value;
|
2900 |
-
}
|
2901 |
-
},
|
2902 |
-
|
2903 |
-
registerFormCallbacks: function() {
|
2904 |
-
Form.getElements(this.element).each(this.registerCallback.bind(this));
|
2905 |
-
},
|
2906 |
-
|
2907 |
-
registerCallback: function(element) {
|
2908 |
-
if (element.type) {
|
2909 |
-
switch (element.type.toLowerCase()) {
|
2910 |
-
case 'checkbox':
|
2911 |
-
case 'radio':
|
2912 |
-
Event.observe(element, 'click', this.onElementEvent.bind(this));
|
2913 |
-
break;
|
2914 |
-
default:
|
2915 |
-
Event.observe(element, 'change', this.onElementEvent.bind(this));
|
2916 |
-
break;
|
2917 |
-
}
|
2918 |
-
}
|
2919 |
-
}
|
2920 |
-
}
|
2921 |
-
|
2922 |
-
Form.Element.EventObserver = Class.create();
|
2923 |
-
Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
|
2924 |
-
getValue: function() {
|
2925 |
-
return Form.Element.getValue(this.element);
|
2926 |
-
}
|
2927 |
-
});
|
2928 |
-
|
2929 |
-
Form.EventObserver = Class.create();
|
2930 |
-
Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
|
2931 |
-
getValue: function() {
|
2932 |
-
return Form.serialize(this.element);
|
2933 |
-
}
|
2934 |
-
});
|
2935 |
-
if (!window.Event) {
|
2936 |
-
var Event = new Object();
|
2937 |
-
}
|
2938 |
-
|
2939 |
-
Object.extend(Event, {
|
2940 |
-
KEY_BACKSPACE: 8,
|
2941 |
-
KEY_TAB: 9,
|
2942 |
-
KEY_RETURN: 13,
|
2943 |
-
KEY_ESC: 27,
|
2944 |
-
KEY_LEFT: 37,
|
2945 |
-
KEY_UP: 38,
|
2946 |
-
KEY_RIGHT: 39,
|
2947 |
-
KEY_DOWN: 40,
|
2948 |
-
KEY_DELETE: 46,
|
2949 |
-
KEY_HOME: 36,
|
2950 |
-
KEY_END: 35,
|
2951 |
-
KEY_PAGEUP: 33,
|
2952 |
-
KEY_PAGEDOWN: 34,
|
2953 |
-
|
2954 |
-
element: function(event) {
|
2955 |
-
return $(event.target || event.srcElement);
|
2956 |
-
},
|
2957 |
-
|
2958 |
-
isLeftClick: function(event) {
|
2959 |
-
return (((event.which) && (event.which == 1)) ||
|
2960 |
-
((event.button) && (event.button == 1)));
|
2961 |
-
},
|
2962 |
-
|
2963 |
-
pointerX: function(event) {
|
2964 |
-
return event.pageX || (event.clientX +
|
2965 |
-
(document.documentElement.scrollLeft || document.body.scrollLeft));
|
2966 |
-
},
|
2967 |
-
|
2968 |
-
pointerY: function(event) {
|
2969 |
-
return event.pageY || (event.clientY +
|
2970 |
-
(document.documentElement.scrollTop || document.body.scrollTop));
|
2971 |
-
},
|
2972 |
-
|
2973 |
-
stop: function(event) {
|
2974 |
-
if (event.preventDefault) {
|
2975 |
-
event.preventDefault();
|
2976 |
-
event.stopPropagation();
|
2977 |
-
} else {
|
2978 |
-
event.returnValue = false;
|
2979 |
-
event.cancelBubble = true;
|
2980 |
-
}
|
2981 |
-
},
|
2982 |
-
|
2983 |
-
// find the first node with the given tagName, starting from the
|
2984 |
-
// node the event was triggered on; traverses the DOM upwards
|
2985 |
-
findElement: function(event, tagName) {
|
2986 |
-
var element = Event.element(event);
|
2987 |
-
while (element.parentNode && (!element.tagName ||
|
2988 |
-
(element.tagName.toUpperCase() != tagName.toUpperCase())))
|
2989 |
-
element = element.parentNode;
|
2990 |
-
return element;
|
2991 |
-
},
|
2992 |
-
|
2993 |
-
observers: false,
|
2994 |
-
|
2995 |
-
_observeAndCache: function(element, name, observer, useCapture) {
|
2996 |
-
if (!this.observers) this.observers = [];
|
2997 |
-
if (element.addEventListener) {
|
2998 |
-
this.observers.push([element, name, observer, useCapture]);
|
2999 |
-
element.addEventListener(name, observer, useCapture);
|
3000 |
-
} else if (element.attachEvent) {
|
3001 |
-
this.observers.push([element, name, observer, useCapture]);
|
3002 |
-
element.attachEvent('on' + name, observer);
|
3003 |
-
}
|
3004 |
-
},
|
3005 |
-
|
3006 |
-
unloadCache: function() {
|
3007 |
-
if (!Event.observers) return;
|
3008 |
-
for (var i = 0, length = Event.observers.length; i < length; i++) {
|
3009 |
-
Event.stopObserving.apply(this, Event.observers[i]);
|
3010 |
-
Event.observers[i][0] = null;
|
3011 |
-
}
|
3012 |
-
Event.observers = false;
|
3013 |
-
},
|
3014 |
-
|
3015 |
-
observe: function(element, name, observer, useCapture) {
|
3016 |
-
element = $(element);
|
3017 |
-
useCapture = useCapture || false;
|
3018 |
-
|
3019 |
-
if (name == 'keypress' &&
|
3020 |
-
(Prototype.Browser.WebKit || element.attachEvent))
|
3021 |
-
name = 'keydown';
|
3022 |
-
|
3023 |
-
Event._observeAndCache(element, name, observer, useCapture);
|
3024 |
-
},
|
3025 |
-
|
3026 |
-
stopObserving: function(element, name, observer, useCapture) {
|
3027 |
-
element = $(element);
|
3028 |
-
useCapture = useCapture || false;
|
3029 |
-
|
3030 |
-
if (name == 'keypress' &&
|
3031 |
-
(Prototype.Browser.WebKit || element.attachEvent))
|
3032 |
-
name = 'keydown';
|
3033 |
-
|
3034 |
-
if (element.removeEventListener) {
|
3035 |
-
element.removeEventListener(name, observer, useCapture);
|
3036 |
-
} else if (element.detachEvent) {
|
3037 |
-
try {
|
3038 |
-
element.detachEvent('on' + name, observer);
|
3039 |
-
} catch (e) {}
|
3040 |
-
}
|
3041 |
-
}
|
3042 |
-
});
|
3043 |
-
|
3044 |
-
/* prevent memory leaks in IE */
|
3045 |
-
if (Prototype.Browser.IE)
|
3046 |
-
Event.observe(window, 'unload', Event.unloadCache, false);
|
3047 |
-
var Position = {
|
3048 |
-
// set to true if needed, warning: firefox performance problems
|
3049 |
-
// NOT neeeded for page scrolling, only if draggable contained in
|
3050 |
-
// scrollable elements
|
3051 |
-
includeScrollOffsets: false,
|
3052 |
-
|
3053 |
-
// must be called before calling withinIncludingScrolloffset, every time the
|
3054 |
-
// page is scrolled
|
3055 |
-
prepare: function() {
|
3056 |
-
this.deltaX = window.pageXOffset
|
3057 |
-
|| document.documentElement.scrollLeft
|
3058 |
-
|| document.body.scrollLeft
|
3059 |
-
|| 0;
|
3060 |
-
this.deltaY = window.pageYOffset
|
3061 |
-
|| document.documentElement.scrollTop
|
3062 |
-
|| document.body.scrollTop
|
3063 |
-
|| 0;
|
3064 |
-
},
|
3065 |
-
|
3066 |
-
realOffset: function(element) {
|
3067 |
-
var valueT = 0, valueL = 0;
|
3068 |
-
do {
|
3069 |
-
valueT += element.scrollTop || 0;
|
3070 |
-
valueL += element.scrollLeft || 0;
|
3071 |
-
element = element.parentNode;
|
3072 |
-
} while (element);
|
3073 |
-
return [valueL, valueT];
|
3074 |
-
},
|
3075 |
-
|
3076 |
-
cumulativeOffset: function(element) {
|
3077 |
-
var valueT = 0, valueL = 0;
|
3078 |
-
do {
|
3079 |
-
valueT += element.offsetTop || 0;
|
3080 |
-
valueL += element.offsetLeft || 0;
|
3081 |
-
element = element.offsetParent;
|
3082 |
-
} while (element);
|
3083 |
-
return [valueL, valueT];
|
3084 |
-
},
|
3085 |
-
|
3086 |
-
positionedOffset: function(element) {
|
3087 |
-
var valueT = 0, valueL = 0;
|
3088 |
-
do {
|
3089 |
-
valueT += element.offsetTop || 0;
|
3090 |
-
valueL += element.offsetLeft || 0;
|
3091 |
-
element = element.offsetParent;
|
3092 |
-
if (element) {
|
3093 |
-
if(element.tagName=='BODY') break;
|
3094 |
-
var p = Element.getStyle(element, 'position');
|
3095 |
-
if (p == 'relative' || p == 'absolute') break;
|
3096 |
-
}
|
3097 |
-
} while (element);
|
3098 |
-
return [valueL, valueT];
|
3099 |
-
},
|
3100 |
-
|
3101 |
-
offsetParent: function(element) {
|
3102 |
-
if (element.offsetParent) return element.offsetParent;
|
3103 |
-
if (element == document.body) return element;
|
3104 |
-
|
3105 |
-
while ((element = element.parentNode) && element != document.body)
|
3106 |
-
if (Element.getStyle(element, 'position') != 'static')
|
3107 |
-
return element;
|
3108 |
-
|
3109 |
-
return document.body;
|
3110 |
-
},
|
3111 |
-
|
3112 |
-
// caches x/y coordinate pair to use with overlap
|
3113 |
-
within: function(element, x, y) {
|
3114 |
-
if (this.includeScrollOffsets)
|
3115 |
-
return this.withinIncludingScrolloffsets(element, x, y);
|
3116 |
-
this.xcomp = x;
|
3117 |
-
this.ycomp = y;
|
3118 |
-
this.offset = this.cumulativeOffset(element);
|
3119 |
-
|
3120 |
-
return (y >= this.offset[1] &&
|
3121 |
-
y < this.offset[1] + element.offsetHeight &&
|
3122 |
-
x >= this.offset[0] &&
|
3123 |
-
x < this.offset[0] + element.offsetWidth);
|
3124 |
-
},
|
3125 |
-
|
3126 |
-
withinIncludingScrolloffsets: function(element, x, y) {
|
3127 |
-
var offsetcache = this.realOffset(element);
|
3128 |
-
|
3129 |
-
this.xcomp = x + offsetcache[0] - this.deltaX;
|
3130 |
-
this.ycomp = y + offsetcache[1] - this.deltaY;
|
3131 |
-
this.offset = this.cumulativeOffset(element);
|
3132 |
-
|
3133 |
-
return (this.ycomp >= this.offset[1] &&
|
3134 |
-
this.ycomp < this.offset[1] + element.offsetHeight &&
|
3135 |
-
this.xcomp >= this.offset[0] &&
|
3136 |
-
this.xcomp < this.offset[0] + element.offsetWidth);
|
3137 |
-
},
|
3138 |
-
|
3139 |
-
// within must be called directly before
|
3140 |
-
overlap: function(mode, element) {
|
3141 |
-
if (!mode) return 0;
|
3142 |
-
if (mode == 'vertical')
|
3143 |
-
return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
|
3144 |
-
element.offsetHeight;
|
3145 |
-
if (mode == 'horizontal')
|
3146 |
-
return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
|
3147 |
-
element.offsetWidth;
|
3148 |
-
},
|
3149 |
-
|
3150 |
-
page: function(forElement) {
|
3151 |
-
var valueT = 0, valueL = 0;
|
3152 |
-
|
3153 |
-
var element = forElement;
|
3154 |
-
do {
|
3155 |
-
valueT += element.offsetTop || 0;
|
3156 |
-
valueL += element.offsetLeft || 0;
|
3157 |
-
|
3158 |
-
// Safari fix
|
3159 |
-
if (element.offsetParent == document.body)
|
3160 |
-
if (Element.getStyle(element,'position')=='absolute') break;
|
3161 |
-
|
3162 |
-
} while (element = element.offsetParent);
|
3163 |
-
|
3164 |
-
element = forElement;
|
3165 |
-
do {
|
3166 |
-
if (!window.opera || element.tagName=='BODY') {
|
3167 |
-
valueT -= element.scrollTop || 0;
|
3168 |
-
valueL -= element.scrollLeft || 0;
|
3169 |
-
}
|
3170 |
-
} while (element = element.parentNode);
|
3171 |
-
|
3172 |
-
return [valueL, valueT];
|
3173 |
-
},
|
3174 |
-
|
3175 |
-
clone: function(source, target) {
|
3176 |
-
var options = Object.extend({
|
3177 |
-
setLeft: true,
|
3178 |
-
setTop: true,
|
3179 |
-
setWidth: true,
|
3180 |
-
setHeight: true,
|
3181 |
-
offsetTop: 0,
|
3182 |
-
offsetLeft: 0
|
3183 |
-
}, arguments[2] || {})
|
3184 |
-
|
3185 |
-
// find page position of source
|
3186 |
-
source = $(source);
|
3187 |
-
var p = Position.page(source);
|
3188 |
-
|
3189 |
-
// find coordinate system to use
|
3190 |
-
target = $(target);
|
3191 |
-
var delta = [0, 0];
|
3192 |
-
var parent = null;
|
3193 |
-
// delta [0,0] will do fine with position: fixed elements,
|
3194 |
-
// position:absolute needs offsetParent deltas
|
3195 |
-
if (Element.getStyle(target,'position') == 'absolute') {
|
3196 |
-
parent = Position.offsetParent(target);
|
3197 |
-
delta = Position.page(parent);
|
3198 |
-
}
|
3199 |
-
|
3200 |
-
// correct by body offsets (fixes Safari)
|
3201 |
-
if (parent == document.body) {
|
3202 |
-
delta[0] -= document.body.offsetLeft;
|
3203 |
-
delta[1] -= document.body.offsetTop;
|
3204 |
-
}
|
3205 |
-
|
3206 |
-
// set position
|
3207 |
-
if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
|
3208 |
-
if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
|
3209 |
-
if(options.setWidth) target.style.width = source.offsetWidth + 'px';
|
3210 |
-
if(options.setHeight) target.style.height = source.offsetHeight + 'px';
|
3211 |
-
},
|
3212 |
-
|
3213 |
-
absolutize: function(element) {
|
3214 |
-
element = $(element);
|
3215 |
-
if (element.style.position == 'absolute') return;
|
3216 |
-
Position.prepare();
|
3217 |
-
|
3218 |
-
var offsets = Position.positionedOffset(element);
|
3219 |
-
var top = offsets[1];
|
3220 |
-
var left = offsets[0];
|
3221 |
-
var width = element.clientWidth;
|
3222 |
-
var height = element.clientHeight;
|
3223 |
-
|
3224 |
-
element._originalLeft = left - parseFloat(element.style.left || 0);
|
3225 |
-
element._originalTop = top - parseFloat(element.style.top || 0);
|
3226 |
-
element._originalWidth = element.style.width;
|
3227 |
-
element._originalHeight = element.style.height;
|
3228 |
-
|
3229 |
-
element.style.position = 'absolute';
|
3230 |
-
element.style.top = top + 'px';
|
3231 |
-
element.style.left = left + 'px';
|
3232 |
-
element.style.width = width + 'px';
|
3233 |
-
element.style.height = height + 'px';
|
3234 |
-
},
|
3235 |
-
|
3236 |
-
relativize: function(element) {
|
3237 |
-
element = $(element);
|
3238 |
-
if (element.style.position == 'relative') return;
|
3239 |
-
Position.prepare();
|
3240 |
-
|
3241 |
-
element.style.position = 'relative';
|
3242 |
-
var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
|
3243 |
-
var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
|
3244 |
-
|
3245 |
-
element.style.top = top + 'px';
|
3246 |
-
element.style.left = left + 'px';
|
3247 |
-
element.style.height = element._originalHeight;
|
3248 |
-
element.style.width = element._originalWidth;
|
3249 |
-
}
|
3250 |
-
}
|
3251 |
-
|
3252 |
-
// Safari returns margins on body which is incorrect if the child is absolutely
|
3253 |
-
// positioned. For performance reasons, redefine Position.cumulativeOffset for
|
3254 |
-
// KHTML/WebKit only.
|
3255 |
-
if (Prototype.Browser.WebKit) {
|
3256 |
-
Position.cumulativeOffset = function(element) {
|
3257 |
-
var valueT = 0, valueL = 0;
|
3258 |
-
do {
|
3259 |
-
valueT += element.offsetTop || 0;
|
3260 |
-
valueL += element.offsetLeft || 0;
|
3261 |
-
if (element.offsetParent == document.body)
|
3262 |
-
if (Element.getStyle(element, 'position') == 'absolute') break;
|
3263 |
-
|
3264 |
-
element = element.offsetParent;
|
3265 |
-
} while (element);
|
3266 |
-
|
3267 |
-
return [valueL, valueT];
|
3268 |
-
}
|
3269 |
-
}
|
3270 |
-
|
3271 |
-
Element.addMethods();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
js/dev/scriptaculous.js
DELETED
@@ -1,58 +0,0 @@
|
|
1 |
-
// script.aculo.us scriptaculous.js v1.7.1_beta3, Fri May 25 17:19:41 +0200 2007
|
2 |
-
|
3 |
-
// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
|
4 |
-
//
|
5 |
-
// Permission is hereby granted, free of charge, to any person obtaining
|
6 |
-
// a copy of this software and associated documentation files (the
|
7 |
-
// "Software"), to deal in the Software without restriction, including
|
8 |
-
// without limitation the rights to use, copy, modify, merge, publish,
|
9 |
-
// distribute, sublicense, and/or sell copies of the Software, and to
|
10 |
-
// permit persons to whom the Software is furnished to do so, subject to
|
11 |
-
// the following conditions:
|
12 |
-
//
|
13 |
-
// The above copyright notice and this permission notice shall be
|
14 |
-
// included in all copies or substantial portions of the Software.
|
15 |
-
//
|
16 |
-
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17 |
-
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18 |
-
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19 |
-
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20 |
-
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21 |
-
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22 |
-
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23 |
-
//
|
24 |
-
// For details, see the script.aculo.us web site: http://script.aculo.us/
|
25 |
-
|
26 |
-
var Scriptaculous = {
|
27 |
-
Version: '1.7.1_beta3',
|
28 |
-
require: function(libraryName) {
|
29 |
-
// inserting via DOM fails in Safari 2.0, so brute force approach
|
30 |
-
document.write('<script type="text/javascript" src="'+libraryName+'"></script>');
|
31 |
-
},
|
32 |
-
REQUIRED_PROTOTYPE: '1.5.1',
|
33 |
-
load: function() {
|
34 |
-
function convertVersionString(versionString){
|
35 |
-
var r = versionString.split('.');
|
36 |
-
return parseInt(r[0])*100000 + parseInt(r[1])*1000 + parseInt(r[2]);
|
37 |
-
}
|
38 |
-
|
39 |
-
if((typeof Prototype=='undefined') ||
|
40 |
-
(typeof Element == 'undefined') ||
|
41 |
-
(typeof Element.Methods=='undefined') ||
|
42 |
-
(convertVersionString(Prototype.Version) <
|
43 |
-
convertVersionString(Scriptaculous.REQUIRED_PROTOTYPE)))
|
44 |
-
throw("script.aculo.us requires the Prototype JavaScript framework >= " +
|
45 |
-
Scriptaculous.REQUIRED_PROTOTYPE);
|
46 |
-
|
47 |
-
$A(document.getElementsByTagName("script")).findAll( function(s) {
|
48 |
-
return (s.src && s.src.match(/scriptaculous\.js(\?.*)?$/))
|
49 |
-
}).each( function(s) {
|
50 |
-
var path = s.src.replace(/scriptaculous\.js(\?.*)?$/,'');
|
51 |
-
var includes = s.src.match(/\?.*load=([a-z,]*)/);
|
52 |
-
(includes ? includes[1] : 'builder,effects,dragdrop,controls,slider,sound').split(',').each(
|
53 |
-
function(include) { Scriptaculous.require(path+include+'.js') });
|
54 |
-
});
|
55 |
-
}
|
56 |
-
}
|
57 |
-
|
58 |
-
Scriptaculous.load();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
js/lib.js
CHANGED
@@ -1,207 +1,1228 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
this.
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
if(
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Simple Lightbox
|
3 |
+
* @author Archetyped (http://archetyped.com/tools/simple-lightbox/)
|
4 |
+
*
|
5 |
+
* Inspiration/History
|
6 |
+
* > 2010: Originally based on Lightbox Slideshow v1.1
|
7 |
+
* > by Justin Barkhuff (http://www.justinbarkhuff.com/lab/lightbox_slideshow/)
|
8 |
+
* > Largely based on Lightbox v2.02
|
9 |
+
* > by Lokesh Dhakar - http://huddletogether.com/projects/lightbox2/
|
10 |
+
* > 2011-01-12: Rebuilt as jQuery-compatible codebase
|
11 |
+
*
|
12 |
+
*/
|
13 |
+
|
14 |
+
|
15 |
+
(function($) {
|
16 |
+
SLB = {
|
17 |
+
/* Properties */
|
18 |
+
|
19 |
+
//Core
|
20 |
+
prefix : 'slb',
|
21 |
+
options : {},
|
22 |
+
//Activation
|
23 |
+
trigger : null,
|
24 |
+
urls_checked : {},
|
25 |
+
//Items
|
26 |
+
items : [],
|
27 |
+
item_curr : null,
|
28 |
+
item_init : null,
|
29 |
+
group : null,
|
30 |
+
media : {},
|
31 |
+
//Content
|
32 |
+
content: {
|
33 |
+
caption_enabled: true,
|
34 |
+
caption_src: true,
|
35 |
+
desc_enabled: true,
|
36 |
+
labels : {
|
37 |
+
closeLink : 'close',
|
38 |
+
loadingMsg : 'loading',
|
39 |
+
nextLink : 'next »',
|
40 |
+
prevLink : '« prev',
|
41 |
+
startSlideshow : 'start slideshow',
|
42 |
+
stopSlideshow : 'stop slideshow',
|
43 |
+
numDisplayPrefix : 'Image',
|
44 |
+
numDisplaySeparator : 'of'
|
45 |
+
}
|
46 |
+
},
|
47 |
+
//Layout
|
48 |
+
container : document,
|
49 |
+
masks : ['select','object','embed','iframe'],
|
50 |
+
layout: {
|
51 |
+
template: '',
|
52 |
+
parsed: '',
|
53 |
+
placeholders : {
|
54 |
+
slbContent: '<img id="slb_slbContent" />',
|
55 |
+
slbLoading: '<span id="slb_slbLoading">loading</span>',
|
56 |
+
slbClose: '<a class="slb_slbClose" href="#">close</a>',
|
57 |
+
navPrev: '<a class="slb_navPrev slb_nav" href="#">« prev</a>',
|
58 |
+
navNext: '<a class="slb_navNext slb_nav" href="#">» next</a>',
|
59 |
+
navSlideControl: '<a class="slb_navSlideControl" href="#">Stop</a>',
|
60 |
+
dataCaption: '<span class="slb_dataCaption"></span>',
|
61 |
+
dataDescription: '<span class="slb_dataDescription"></span>',
|
62 |
+
dataNumber: '<span class="slb_dataNumber"></span>'
|
63 |
+
}
|
64 |
+
},
|
65 |
+
//Slideshow
|
66 |
+
slideshow: {
|
67 |
+
active: null,
|
68 |
+
enabled: true,
|
69 |
+
loop: true,
|
70 |
+
duration: 4,
|
71 |
+
timer: null
|
72 |
+
},
|
73 |
+
//Animation
|
74 |
+
anim: {
|
75 |
+
active: true,
|
76 |
+
overlay_duration: 0,
|
77 |
+
overlay_opacity: .8,
|
78 |
+
resize_duration: 0
|
79 |
+
},
|
80 |
+
|
81 |
+
/* Initialization */
|
82 |
+
|
83 |
+
/**
|
84 |
+
* Initialize lightbox instance
|
85 |
+
* @param object options Instance options
|
86 |
+
*/
|
87 |
+
init: function(options) {
|
88 |
+
//Options
|
89 |
+
this.options = $.extend(true, {
|
90 |
+
//Core
|
91 |
+
prefix: null,
|
92 |
+
|
93 |
+
//Activation
|
94 |
+
trigger : null,
|
95 |
+
validateLinks : false,
|
96 |
+
|
97 |
+
//Content
|
98 |
+
captionEnabled: true,
|
99 |
+
captionSrc : true,
|
100 |
+
descEnabled: true,
|
101 |
+
labels : {},
|
102 |
+
|
103 |
+
//Layout
|
104 |
+
layout : null,
|
105 |
+
placeholders : {},
|
106 |
+
|
107 |
+
//Animation
|
108 |
+
animate : true,
|
109 |
+
overlayDuration : .2,
|
110 |
+
overlayOpacity : .8,
|
111 |
+
resizeSpeed : 400,
|
112 |
+
|
113 |
+
//Slideshow
|
114 |
+
autoPlay : true,
|
115 |
+
enableSlideshow : true,
|
116 |
+
loop : true,
|
117 |
+
slideTime : 4
|
118 |
+
}, options);
|
119 |
+
|
120 |
+
//Stop if no layout is defined
|
121 |
+
if (!this.options.layout || this.options.layout.toString().length == 0)
|
122 |
+
this.end();
|
123 |
+
|
124 |
+
/* Setup Properties */
|
125 |
+
|
126 |
+
//Prefix
|
127 |
+
if ( $.type(this.options.prefix) == 'string' && this.options.prefix.length > 0 ) {
|
128 |
+
this.prefix = this.options.prefix;
|
129 |
+
}
|
130 |
+
|
131 |
+
//Activation
|
132 |
+
this.trigger = ( $.isArray(this.options.trigger) ) ? this.options.trigger : [this.prefix];
|
133 |
+
|
134 |
+
//Content
|
135 |
+
$.extend(true, this.content, {
|
136 |
+
caption_enabled: !!this.options.captionEnabled,
|
137 |
+
caption_src: !!this.options.captionSrc,
|
138 |
+
desc_enabled: !!this.options.descEnabled,
|
139 |
+
labels: ( $.isPlainObject(this.options.labels) ) ? this.options.labels : {}
|
140 |
+
});
|
141 |
+
|
142 |
+
//Layout
|
143 |
+
$.extend(true, this.layout, {
|
144 |
+
template: this.options.layout,
|
145 |
+
placeholders: this.options.placeholders
|
146 |
+
});
|
147 |
+
|
148 |
+
//Animation
|
149 |
+
$.extend(this.anim, {
|
150 |
+
overlay_opacity: Math.max(Math.min(this.options.overlayOpacity,1),0)
|
151 |
+
});
|
152 |
+
if ( this.options.animate ) {
|
153 |
+
$.extend(this.anim, {
|
154 |
+
active: true,
|
155 |
+
overlay_duration: Math.max(this.options.overlayDuration,0),
|
156 |
+
resize_duration: this.options.resizeSpeed
|
157 |
+
});
|
158 |
+
} else {
|
159 |
+
$.extend(this.anim, {
|
160 |
+
active: false,
|
161 |
+
overlay_duration: 0,
|
162 |
+
resize_duration: 0
|
163 |
+
});
|
164 |
+
}
|
165 |
+
|
166 |
+
//Slideshow
|
167 |
+
$.extend(this.slideshow, {
|
168 |
+
play: !!this.options.autoPlay,
|
169 |
+
active: !!this.options.autoPlay,
|
170 |
+
enabled: !!this.options.enableSlideshow,
|
171 |
+
loop: ( !!this.options.enableSlideshow && !!this.options.loop ),
|
172 |
+
duration: ( $.isNumeric(this.options.slideTime) ) ? parseInt(this.options.slideTime) : 0
|
173 |
+
});
|
174 |
+
|
175 |
+
/* Init Layout */
|
176 |
+
|
177 |
+
var t = this;
|
178 |
+
var body = $('body');
|
179 |
+
|
180 |
+
//Overlay
|
181 |
+
$('<div/>', {
|
182 |
+
'id': this.getID('overlay'),
|
183 |
+
'css': {'display': 'none'}
|
184 |
+
}).appendTo(body)
|
185 |
+
.click(function() {t.end();});
|
186 |
+
|
187 |
+
//Viewer
|
188 |
+
var viewer = $('<div/>', {
|
189 |
+
'id': this.getID('viewer'),
|
190 |
+
'css': {'display': 'none'}
|
191 |
+
}).appendTo(body)
|
192 |
+
.click(function() {t.end();});
|
193 |
+
|
194 |
+
//Build layout from template
|
195 |
+
this.layout.parsed = this.getLayout();
|
196 |
+
|
197 |
+
//Insert layout into viewer
|
198 |
+
$(this.layout.parsed).appendTo(viewer);
|
199 |
+
|
200 |
+
//Set UI
|
201 |
+
this.initUI();
|
202 |
+
|
203 |
+
//Add events
|
204 |
+
this.initEvents();
|
205 |
+
},
|
206 |
+
|
207 |
+
/**
|
208 |
+
* Set localized values for UI elements
|
209 |
+
*/
|
210 |
+
initUI: function() {
|
211 |
+
this.get('slbClose').html(this.getLabel('closeLink'));
|
212 |
+
this.get('navNext').html(this.getLabel('nextLink'));
|
213 |
+
this.get('navPrev').html(this.getLabel('prevLink'));
|
214 |
+
this.get('navSlideControl').html( this.getLabel((this.slideshowActive()) ? 'stopSlideshow' : 'startSlideshow') );
|
215 |
+
},
|
216 |
+
|
217 |
+
/**
|
218 |
+
* Add events to various UI elements
|
219 |
+
*/
|
220 |
+
initEvents: function() {
|
221 |
+
var t = this, delay = 500;
|
222 |
+
//Remove all previous handlers
|
223 |
+
this.get('container,details,navPrev,navNext,navSlideControl,slbClose').unbind('click');
|
224 |
+
|
225 |
+
//Set event handlers
|
226 |
+
this.get('container,details').click(function(ev) {
|
227 |
+
ev.stopPropagation();
|
228 |
+
});
|
229 |
+
|
230 |
+
var clickP = function() {
|
231 |
+
//Handle double clicks
|
232 |
+
t.get('navPrev').unbind('click').click(false);
|
233 |
+
setTimeout(function() {t.get('navPrev').click(clickP);}, delay);
|
234 |
+
t.navPrev();
|
235 |
+
return false;
|
236 |
+
};
|
237 |
+
this.get('navPrev').click(function(){
|
238 |
+
return clickP();
|
239 |
+
});
|
240 |
+
|
241 |
+
var clickN = function() {
|
242 |
+
//Handle double clicks
|
243 |
+
t.get('navNext').unbind('click').click(false);
|
244 |
+
setTimeout(function() {t.get('navNext').click(clickN);}, delay);
|
245 |
+
t.navNext();
|
246 |
+
return false;
|
247 |
+
};
|
248 |
+
this.get('navNext').click(function() {
|
249 |
+
return clickN();
|
250 |
+
});
|
251 |
+
|
252 |
+
this.get('navSlideControl').click(function() {
|
253 |
+
t.slideshowToggle();
|
254 |
+
return false;
|
255 |
+
});
|
256 |
+
this.get('slbClose').click(function() {
|
257 |
+
t.end();
|
258 |
+
return false;
|
259 |
+
});
|
260 |
+
|
261 |
+
//Handle links on page
|
262 |
+
this.initLinks();
|
263 |
+
},
|
264 |
+
|
265 |
+
/**
|
266 |
+
* Finds all compatible image links on page
|
267 |
+
* @return void
|
268 |
+
*/
|
269 |
+
initLinks: function() {
|
270 |
+
var ph = '{relattr}', t = this;
|
271 |
+
var sel = [], selBase = 'a[href][rel*="' + ph + '"]:not([rel~="' + this.addPrefix('off') + '"])';
|
272 |
+
|
273 |
+
//Click event handler
|
274 |
+
var handler = function() {
|
275 |
+
t.view(this);
|
276 |
+
return false;
|
277 |
+
};
|
278 |
+
|
279 |
+
//Build selector
|
280 |
+
for (var x = 0; x < this.trigger.length; x++) {
|
281 |
+
sel.push(selBase.replace(ph, this.trigger[x]));
|
282 |
+
}
|
283 |
+
sel = sel.join(',');
|
284 |
+
//Add event handler to links
|
285 |
+
$(sel, $(this.container)).live('click', handler);
|
286 |
+
},
|
287 |
+
|
288 |
+
/* Display */
|
289 |
+
|
290 |
+
/**
|
291 |
+
* Display viewer
|
292 |
+
* If item is part of a group, add other items in group
|
293 |
+
* @param node item Link element of item to display
|
294 |
+
*/
|
295 |
+
view: function(item) {
|
296 |
+
item = $(item);
|
297 |
+
this.mask();
|
298 |
+
|
299 |
+
this.items = [];
|
300 |
+
this.setGroup(item);
|
301 |
+
|
302 |
+
var t = this;
|
303 |
+
var groupTemp = {};
|
304 |
+
this.fileExists(this.itemSource(item),
|
305 |
+
function() {
|
306 |
+
/* File Exists */
|
307 |
+
|
308 |
+
/* Handlers */
|
309 |
+
|
310 |
+
/**
|
311 |
+
* Add item to group
|
312 |
+
* @param obj el Item to add
|
313 |
+
* @param int idx DOM position index of item
|
314 |
+
* @return int Total number of items in group
|
315 |
+
*/
|
316 |
+
var addItem = function(el, idx) {
|
317 |
+
groupTemp[idx] = el;
|
318 |
+
return groupTemp.length;
|
319 |
+
};
|
320 |
+
|
321 |
+
/**
|
322 |
+
* Build final item array & launch viewer
|
323 |
+
*/
|
324 |
+
var proceed = function() {
|
325 |
+
t.item_init = 0;
|
326 |
+
//Sort links by document order
|
327 |
+
var order = [], el;
|
328 |
+
for (var x in groupTemp) {
|
329 |
+
order.push(x);
|
330 |
+
}
|
331 |
+
order.sort(function(a, b) { return (a - b); });
|
332 |
+
for (x = 0; x < order.length; x++) {
|
333 |
+
el = groupTemp[order[x]];
|
334 |
+
// Check if link being evaluated is the same as the clicked link
|
335 |
+
if ($(el).get(0) == $(item).get(0)) {
|
336 |
+
t.item_init = x;
|
337 |
+
}
|
338 |
+
t.items.push({'link':t.itemSource($(el)), 'title':t.getCaption(el), 'desc': t.getDescription(el)});
|
339 |
+
}
|
340 |
+
// Calculate top offset for the viewer and display
|
341 |
+
var vwrTop = $(document).scrollTop() + ($(window).height() / 15);
|
342 |
+
t.get('viewer').css('top', vwrTop + 'px').show();
|
343 |
+
t.itemLoad(t.item_init);
|
344 |
+
};
|
345 |
+
|
346 |
+
/* Display */
|
347 |
+
|
348 |
+
//Overlay
|
349 |
+
t.get('overlay')
|
350 |
+
.height($(document).height())
|
351 |
+
.fadeTo(t.anim.overlay_duration, t.options.overlayOpacity);
|
352 |
+
|
353 |
+
//Single item (not in group)
|
354 |
+
if ( !t.hasGroup() ) {
|
355 |
+
//Display item
|
356 |
+
t.item_init = 0;
|
357 |
+
addItem(item, t.item_init);
|
358 |
+
proceed();
|
359 |
+
} else {
|
360 |
+
//Item in group
|
361 |
+
var links = $(t.container).find('a');
|
362 |
+
//Get other items in group
|
363 |
+
var grpLinks = [];
|
364 |
+
var i, link;
|
365 |
+
for ( i = 0; i < links.length; i++ ) {
|
366 |
+
link = $(links[i]);
|
367 |
+
if ( t.itemSource(link) && t.inGroup(link) ) {
|
368 |
+
//Add links in group
|
369 |
+
grpLinks.push(link);
|
370 |
+
}
|
371 |
+
}
|
372 |
+
|
373 |
+
//Loop through group links, validate, and add to items array
|
374 |
+
var processed = 0;
|
375 |
+
for ( i = 0; i < grpLinks.length; i++ ) {
|
376 |
+
link = grpLinks[i];
|
377 |
+
t.fileExists(t.itemSource($(link)),
|
378 |
+
function(args) {
|
379 |
+
/* File exists */
|
380 |
+
|
381 |
+
//Add item
|
382 |
+
var el = args.items[args.idx];
|
383 |
+
addItem(el, args.idx);
|
384 |
+
processed++;
|
385 |
+
//Display valid items after all items parsed
|
386 |
+
if ( processed == args.items.length )
|
387 |
+
proceed();
|
388 |
+
},
|
389 |
+
function(args) {
|
390 |
+
/* File does not exist */
|
391 |
+
processed++;
|
392 |
+
//Display valid items after all items parsed
|
393 |
+
if (args.idx == args.items.length)
|
394 |
+
proceed();
|
395 |
+
},
|
396 |
+
{'idx': i, 'items': grpLinks});
|
397 |
+
}
|
398 |
+
}
|
399 |
+
},
|
400 |
+
function() {
|
401 |
+
/* File does not exist */
|
402 |
+
t.end();
|
403 |
+
});
|
404 |
+
},
|
405 |
+
|
406 |
+
/**
|
407 |
+
* Close the viewer
|
408 |
+
*/
|
409 |
+
end: function() {
|
410 |
+
this.keyboardDisable();
|
411 |
+
this.slideshowPause();
|
412 |
+
this.get('viewer').hide();
|
413 |
+
this.get('overlay').fadeOut(this.anim.overlay_duration);
|
414 |
+
this.unmask();
|
415 |
+
},
|
416 |
+
|
417 |
+
/**
|
418 |
+
* Resizes viewer to fit image
|
419 |
+
* @param int imgWidth Image width in pixels
|
420 |
+
* @param int imgHeight Image height in pixels
|
421 |
+
*/
|
422 |
+
viewerResize: function(w, h) {
|
423 |
+
var d = this.viewerSize(w, h);
|
424 |
+
//Resize container
|
425 |
+
this.get('container').animate({width: d.width, height: d.height}, this.anim.resize_duration);
|
426 |
+
//Resize overlay
|
427 |
+
this.get('overlay').css('min-width', d.width);
|
428 |
+
this.itemShow();
|
429 |
+
},
|
430 |
+
|
431 |
+
/**
|
432 |
+
* Retrieve or build container size
|
433 |
+
* @param int w Container width to set
|
434 |
+
* @param int h Container height to set
|
435 |
+
* @return obj Container width (w)/height (h) values
|
436 |
+
*/
|
437 |
+
viewerSize: function(w, h) {
|
438 |
+
var style = 'padding';
|
439 |
+
var hz = ['left', 'right'], vt = ['top', 'bottom'];
|
440 |
+
var ph = 0, pv = 0;
|
441 |
+
var t = this;
|
442 |
+
//Calculate spacing around item
|
443 |
+
|
444 |
+
var getVal = function(prop) {
|
445 |
+
var unit = 'px';
|
446 |
+
prop = style + '-' + prop;
|
447 |
+
var ptemp = t.get('content').css( prop );
|
448 |
+
if ( ptemp.indexOf(unit) == -1 ) {
|
449 |
+
ptemp = 0;
|
450 |
+
} else {
|
451 |
+
ptemp = ptemp.replace(unit, '');
|
452 |
+
}
|
453 |
+
return ( $.isNumeric(ptemp) ) ? parseFloat(ptemp) : 0;
|
454 |
+
};
|
455 |
+
|
456 |
+
//Horizontal
|
457 |
+
for ( var x = 0; x < hz.length; x++) {
|
458 |
+
ph += getVal(hz[x]);
|
459 |
+
}
|
460 |
+
//Vertical
|
461 |
+
for ( x = 0; x < vt.length; x++) {
|
462 |
+
pv += getVal(vt[x]);
|
463 |
+
}
|
464 |
+
var c = {
|
465 |
+
'width': w + ph,
|
466 |
+
'height': h + pv
|
467 |
+
};
|
468 |
+
return c;
|
469 |
+
},
|
470 |
+
|
471 |
+
/**
|
472 |
+
* Displays objects that may conflict with the viewer
|
473 |
+
* @param bool show (optional) Whether or not to show objects (Default: TRUE)
|
474 |
+
*/
|
475 |
+
unmask: function (show) {
|
476 |
+
show = ( typeof(show) == 'undefined' ) ? true : !!show;
|
477 |
+
var vis = (show) ? 'visible' : 'hidden';
|
478 |
+
$(this.masks.join(',')).css('visibility', vis);
|
479 |
+
},
|
480 |
+
|
481 |
+
/**
|
482 |
+
* Hides objects that may conflict with the viewer
|
483 |
+
* @uses unmask() to hide objects
|
484 |
+
*/
|
485 |
+
mask: function () {
|
486 |
+
this.unmask(false);
|
487 |
+
},
|
488 |
+
|
489 |
+
/* Item */
|
490 |
+
|
491 |
+
/**
|
492 |
+
* Retrieve item property
|
493 |
+
* @uses items to retrieve property from item in array
|
494 |
+
* @param int idx Item position index
|
495 |
+
* @param string prop Item property to retrieve
|
496 |
+
* @return mixed Item property (Default: empty string)
|
497 |
+
*/
|
498 |
+
itemProp: function(idx, prop) {
|
499 |
+
return ( idx < this.items.length && prop in this.items[idx] ) ? this.items[idx][prop] : '';
|
500 |
+
},
|
501 |
+
|
502 |
+
/**
|
503 |
+
* Preloads requested item prior to displaying it in viewer
|
504 |
+
* @param int idx Index of item in items property
|
505 |
+
* @uses items to retrieve item at specified index
|
506 |
+
* @uses viewerResize() to resize viewer after item has loaded
|
507 |
+
*/
|
508 |
+
itemLoad: function(idx) {
|
509 |
+
this.item_curr = idx;
|
510 |
+
|
511 |
+
this.keyboardDisable();
|
512 |
+
this.slideshowPause();
|
513 |
+
|
514 |
+
//Hide elements during transition
|
515 |
+
this.get('slbLoading').show();
|
516 |
+
this.get('slbContent').hide();
|
517 |
+
this.get('details').hide();
|
518 |
+
var preloader = new Image();
|
519 |
+
var t = this;
|
520 |
+
|
521 |
+
//Event handler: Display item when loaded
|
522 |
+
$(preloader).bind('load', function() {
|
523 |
+
t.get('slbContent').attr('src', preloader.src);
|
524 |
+
t.viewerResize(preloader.width, preloader.height);
|
525 |
+
|
526 |
+
//Restart slideshow if active
|
527 |
+
if ( t.slideshowActive() )
|
528 |
+
t.slideshowStart();
|
529 |
+
});
|
530 |
+
|
531 |
+
//Load image
|
532 |
+
preloader.src = this.itemProp(this.item_curr, 'link');
|
533 |
+
},
|
534 |
+
|
535 |
+
/**
|
536 |
+
* Display image and begin preloading neighbors.
|
537 |
+
*/
|
538 |
+
itemShow: function() {
|
539 |
+
this.get('slbLoading').hide();
|
540 |
+
var t = this;
|
541 |
+
this.get('slbContent').fadeIn(500, function() { t.contentUpdate(); });
|
542 |
+
if ( this.hasItems() ) {
|
543 |
+
this.itemPreloadSiblings();
|
544 |
+
}
|
545 |
+
},
|
546 |
+
|
547 |
+
/**
|
548 |
+
* Preloads items surrounding current item
|
549 |
+
*/
|
550 |
+
itemPreloadSiblings: function() {
|
551 |
+
//Prev
|
552 |
+
var idxPrev = ( this.itemFirst() ) ? this.items.length - 1 : this.item_curr - 1;
|
553 |
+
var itemPrev = new Image();
|
554 |
+
itemPrev.src = this.itemProp(idxPrev, 'link');
|
555 |
+
|
556 |
+
//Next
|
557 |
+
var idxNext = ( this.itemLast() ) ? 0 : this.item_curr + 1;
|
558 |
+
if ( idxNext != idxPrev ) {
|
559 |
+
var itemNext = new Image();
|
560 |
+
itemNext.src = this.itemProp(idxNext, 'link');
|
561 |
+
}
|
562 |
+
},
|
563 |
+
|
564 |
+
/**
|
565 |
+
* Check if there is at least one image to display in the viewer
|
566 |
+
* @return bool TRUE if at least one image is found
|
567 |
+
* @uses items to check for images
|
568 |
+
*/
|
569 |
+
hasItem: function() {
|
570 |
+
return ( this.items.length > 0 );
|
571 |
+
},
|
572 |
+
|
573 |
+
/**
|
574 |
+
* Check if there are multiple images to display in the viewer
|
575 |
+
* @return bool TRUE if there are multiple images
|
576 |
+
* @uses items to determine the number of images
|
577 |
+
*/
|
578 |
+
hasItems: function() {
|
579 |
+
return ( this.items.length > 1 );
|
580 |
+
},
|
581 |
+
|
582 |
+
/**
|
583 |
+
* Check if the current image is the first image in the list
|
584 |
+
* @return bool TRUE if image is first
|
585 |
+
* @uses item_curr to check index of current image
|
586 |
+
*/
|
587 |
+
itemFirst: function() {
|
588 |
+
return ( this.item_curr == 0 );
|
589 |
+
},
|
590 |
+
|
591 |
+
/**
|
592 |
+
* Check if the current image is the last image in the list
|
593 |
+
* @return bool TRUE if image is last
|
594 |
+
* @uses item_curr to check index of current image
|
595 |
+
* @uses items to compare current image to total number of images
|
596 |
+
*/
|
597 |
+
itemLast: function() {
|
598 |
+
return ( this.item_curr == this.items.length - 1 );
|
599 |
+
},
|
600 |
+
|
601 |
+
/**
|
602 |
+
* Retrieve source URI in link
|
603 |
+
* @param obj el
|
604 |
+
* @return string Source file URI
|
605 |
+
*/
|
606 |
+
itemSource: function(el) {
|
607 |
+
var src = $(el).attr('href');
|
608 |
+
var attr = $(el).attr('rel') || '';
|
609 |
+
if ( attr.length ) {
|
610 |
+
//Attachment source
|
611 |
+
var mSrc = this.mediaProp(el, 'source');
|
612 |
+
//Set source using extended properties
|
613 |
+
if ( $.type(mSrc) === 'string' && mSrc.length )
|
614 |
+
src = mSrc;
|
615 |
+
}
|
616 |
+
return src;
|
617 |
+
},
|
618 |
+
|
619 |
+
/**
|
620 |
+
* Check if current link is part of a gallery
|
621 |
+
* @param obj item
|
622 |
+
* @param string gType Gallery type to check for
|
623 |
+
* @return bool Whether link is part of a gallery
|
624 |
+
*/
|
625 |
+
itemGallery: function(item, gType) {
|
626 |
+
var ret = false;
|
627 |
+
var galls = {
|
628 |
+
'wp': '.gallery-icon',
|
629 |
+
'ng': '.ngg-gallery-thumbnail'
|
630 |
+
};
|
631 |
+
|
632 |
+
|
633 |
+
if ( typeof gType == 'undefined' || !(gType in galls) ) {
|
634 |
+
gType = 'wp';
|
635 |
+
}
|
636 |
+
return ( $(item).parent(galls[gType]).length > 0 ) ? true : false ;
|
637 |
+
},
|
638 |
+
|
639 |
+
/* Media */
|
640 |
+
|
641 |
+
/**
|
642 |
+
* Retrieve ID of media item
|
643 |
+
* @param obj el Link element
|
644 |
+
* @return string|bool Media ID (Default: false - No ID)
|
645 |
+
*/
|
646 |
+
mediaId: function(el) {
|
647 |
+
var h = $(el).attr('href');
|
648 |
+
if ($.type(h) !== 'string')
|
649 |
+
h = false;
|
650 |
+
return h;
|
651 |
+
},
|
652 |
+
|
653 |
+
/**
|
654 |
+
* Retrieve Media properties
|
655 |
+
* @param obj el Link element
|
656 |
+
* @return obj Properties for Media item (Default: Empty)
|
657 |
+
*/
|
658 |
+
mediaProps: function(el) {
|
659 |
+
var props = {},
|
660 |
+
mId = this.mediaId(el);
|
661 |
+
if (mId && mId in this.media) {
|
662 |
+
props = this.media[mId];
|
663 |
+
}
|
664 |
+
return props;
|
665 |
+
},
|
666 |
+
|
667 |
+
/**
|
668 |
+
* Retrieve single property for media item
|
669 |
+
* @param obj el Image link DOM element
|
670 |
+
* @param string prop Property to retrieve
|
671 |
+
* @return mixed|null Item property (Default: NULL if property does not exist)
|
672 |
+
*/
|
673 |
+
mediaProp: function(el, prop) {
|
674 |
+
var props = this.mediaProps(el);
|
675 |
+
return (prop in props) ? props[prop] : null;
|
676 |
+
},
|
677 |
+
|
678 |
+
/* Content */
|
679 |
+
|
680 |
+
/**
|
681 |
+
* Retrieve specified label
|
682 |
+
* @param string id Label ID
|
683 |
+
* @param string def (optional) Default value if specified label is invalid
|
684 |
+
* @return string Label text
|
685 |
+
*/
|
686 |
+
getLabel: function(id, def) {
|
687 |
+
if ( typeof def == 'undefined' ) {
|
688 |
+
def = '';
|
689 |
+
}
|
690 |
+
return ( id in this.content.labels ) ? this.content.labels[id] : def;
|
691 |
+
},
|
692 |
+
|
693 |
+
/**
|
694 |
+
* Build caption for displayed item
|
695 |
+
* @param obj item DOM link element
|
696 |
+
* @return string Image caption
|
697 |
+
*/
|
698 |
+
getCaption: function(item) {
|
699 |
+
item = $(item);
|
700 |
+
var caption = '';
|
701 |
+
if ( this.content.caption_enabled ) {
|
702 |
+
var sels = {
|
703 |
+
'capt': '.wp-caption-text',
|
704 |
+
'gIcon': '.gallery-icon'
|
705 |
+
};
|
706 |
+
var els = {
|
707 |
+
'link': item,
|
708 |
+
'origin': item,
|
709 |
+
'sibs': null,
|
710 |
+
'img': null
|
711 |
+
};
|
712 |
+
//WP Caption
|
713 |
+
if ( this.itemGallery(els.link, 'wp') ) {
|
714 |
+
els.origin = $(els.link).parent();
|
715 |
+
}
|
716 |
+
if ( (els.sibs = $(els.origin).siblings(sels.capt)) && $(els.sibs).length > 0 ) {
|
717 |
+
caption = $.trim($(els.sibs).first().text());
|
718 |
+
}
|
719 |
+
|
720 |
+
//Fall back to image properties
|
721 |
+
if ( !caption ) {
|
722 |
+
els.img = $(els.link).find('img').first();
|
723 |
+
if ( $(els.img).length ) {
|
724 |
+
//Image title / alt
|
725 |
+
caption = $(els.img).attr('title') || $(els.img).attr('alt');
|
726 |
+
caption = $.trim(caption);
|
727 |
+
}
|
728 |
+
}
|
729 |
+
|
730 |
+
//Media properties
|
731 |
+
if ( !caption ) {
|
732 |
+
caption = this.mediaProp(els.link, 'title') || '';
|
733 |
+
caption = $.trim(caption);
|
734 |
+
}
|
735 |
+
|
736 |
+
//Fall back Link Text
|
737 |
+
if ( !caption ) {
|
738 |
+
var c = '';
|
739 |
+
if ( ( c = $.trim($(els.link).text()) ) && c.length) {
|
740 |
+
caption = c;
|
741 |
+
} else if (this.options.captionSrc) {
|
742 |
+
//Fall back to Link href
|
743 |
+
caption = $(els.link).attr('href');
|
744 |
+
var trimChars = ['/', '#', '.'];
|
745 |
+
//Trim invalid characters
|
746 |
+
while ( caption.length && $.inArray(caption.charAt(0), trimChars) != -1 )
|
747 |
+
caption = caption.substr(1);
|
748 |
+
while ( caption.length && $.inArray(caption.charAt(caption.length - 1), trimChars) != -1 )
|
749 |
+
caption = caption.substr(0, caption.length - 1);
|
750 |
+
|
751 |
+
//Strip to base file name
|
752 |
+
var idx = caption.lastIndexOf('/');
|
753 |
+
if ( -1 != idx )
|
754 |
+
caption = caption.substr(idx + 1);
|
755 |
+
//Strip extension
|
756 |
+
idx = caption.lastIndexOf('.');
|
757 |
+
if ( -1 != idx ) {
|
758 |
+
caption = caption.slice(0, idx);
|
759 |
+
}
|
760 |
+
}
|
761 |
+
caption = $.trim(caption);
|
762 |
+
}
|
763 |
+
}
|
764 |
+
return caption;
|
765 |
+
},
|
766 |
+
|
767 |
+
/**
|
768 |
+
* Retrieve item description
|
769 |
+
* @param obj item
|
770 |
+
* @return string Item description (Default: empty string)
|
771 |
+
*/
|
772 |
+
getDescription: function(item) {
|
773 |
+
var desc = '';
|
774 |
+
if ( this.content.desc_enabled ) {
|
775 |
+
//Retrieve description
|
776 |
+
if ( this.itemGallery(item, 'ng') ) {
|
777 |
+
desc = $(item).attr('title');
|
778 |
+
} else {
|
779 |
+
desc = this.mediaProp(item, 'desc');
|
780 |
+
}
|
781 |
+
|
782 |
+
if (!desc)
|
783 |
+
desc = '';
|
784 |
+
}
|
785 |
+
return desc;
|
786 |
+
},
|
787 |
+
|
788 |
+
/**
|
789 |
+
* Display item details
|
790 |
+
*/
|
791 |
+
contentUpdate: function() {
|
792 |
+
//Caption
|
793 |
+
if (this.content.caption_enabled) {
|
794 |
+
this.get('dataCaption').text(this.itemProp(this.item_curr, 'title'));
|
795 |
+
this.get('dataCaption').show();
|
796 |
+
} else {
|
797 |
+
this.get('dataCaption').hide();
|
798 |
+
}
|
799 |
+
|
800 |
+
//Description
|
801 |
+
this.get('dataDescription').html(this.itemProp(this.item_curr, 'desc'));
|
802 |
+
|
803 |
+
//Handle grouped items
|
804 |
+
if ( this.hasItems() ) {
|
805 |
+
var num_display = this.getLabel('numDisplayPrefix') + ' ' + (this.item_curr + 1) + ' ' + this.getLabel('numDisplaySeparator') + ' ' + this.items.length;
|
806 |
+
this.get('dataNumber')
|
807 |
+
.text(num_display)
|
808 |
+
.show();
|
809 |
+
}
|
810 |
+
|
811 |
+
//Resize content area
|
812 |
+
this.get('details').width(this.get('container').width());
|
813 |
+
this.navUpdate();
|
814 |
+
var t = this;
|
815 |
+
this.get('details').animate({height: 'show', opacity: 'show'}, 650);
|
816 |
+
},
|
817 |
+
|
818 |
+
/* Layout */
|
819 |
+
|
820 |
+
/**
|
821 |
+
* Build layout from template
|
822 |
+
* @uses options.layout
|
823 |
+
* @return string Layout markup (HTML)
|
824 |
+
*/
|
825 |
+
getLayout: function() {
|
826 |
+
var l = this.layout.template;
|
827 |
+
|
828 |
+
//Expand placeholders
|
829 |
+
var ph, phs, phr;
|
830 |
+
for ( ph in this.layout.placeholders ) {
|
831 |
+
phs = '{' + ph + '}';
|
832 |
+
//Continue to next placeholder if current one is not in layout
|
833 |
+
if (l.indexOf(phs) == -1)
|
834 |
+
continue;
|
835 |
+
phr = new RegExp(phs, "g");
|
836 |
+
l = l.replace(phr, this.layout.placeholders[ph]);
|
837 |
+
}
|
838 |
+
|
839 |
+
//Return final layout
|
840 |
+
return l;
|
841 |
+
|
842 |
+
},
|
843 |
+
|
844 |
+
/* Grouping */
|
845 |
+
|
846 |
+
/**
|
847 |
+
* Sets group based on current item
|
848 |
+
* @param obj item DOM element to get group from
|
849 |
+
*/
|
850 |
+
setGroup: function(item) {
|
851 |
+
this.group = this.getGroup(item);
|
852 |
+
},
|
853 |
+
|
854 |
+
/**
|
855 |
+
* Extract group name from
|
856 |
+
* @param obj item Element to extract group name from
|
857 |
+
* @return string Group name
|
858 |
+
*/
|
859 |
+
getGroup: function(item) {
|
860 |
+
//Return global group property if no item specified
|
861 |
+
if ( typeof item == 'undefined' || 0 == $(item).length )
|
862 |
+
return this.group;
|
863 |
+
//Get item's group
|
864 |
+
var g = '';
|
865 |
+
var attr = $(item).attr('rel') || '';
|
866 |
+
if ( attr != '' ) {
|
867 |
+
var gTmp = '',
|
868 |
+
gSt = '[',
|
869 |
+
gEnd = ']',
|
870 |
+
search = this.addPrefix('group') + gSt,
|
871 |
+
idx,
|
872 |
+
prefix = ' ';
|
873 |
+
//Find group indicator
|
874 |
+
idx = attr.indexOf(search);
|
875 |
+
//Prefix with space to find whole word
|
876 |
+
if ( prefix != search.charAt(0) && idx > 0 ) {
|
877 |
+
search = prefix + search;
|
878 |
+
idx = attr.indexOf(search);
|
879 |
+
}
|
880 |
+
//Continue processing if value is found
|
881 |
+
if ( idx != -1 ) {
|
882 |
+
//Extract group name
|
883 |
+
gTmp = $.trim(attr.substring(idx).replace(search, ''));
|
884 |
+
//Check if group defined
|
885 |
+
if (gTmp.length > 1 && gTmp.indexOf(gEnd) > 0) {
|
886 |
+
//Extract group name
|
887 |
+
g = gTmp.substring(0, gTmp.indexOf(gEnd));
|
888 |
+
}
|
889 |
+
}
|
890 |
+
}
|
891 |
+
return g;
|
892 |
+
},
|
893 |
+
|
894 |
+
/**
|
895 |
+
* Check if item is part of current group
|
896 |
+
* @param obj item Item to check
|
897 |
+
* @return bool TRUE if item is in current group, FALSE otherwise
|
898 |
+
*/
|
899 |
+
inGroup: function(item) {
|
900 |
+
return ( this.hasGroup() && ( this.getGroup(item) == this.getGroup() ) ) ? true : false;
|
901 |
+
},
|
902 |
+
|
903 |
+
/**
|
904 |
+
* Check if group is set
|
905 |
+
* @return bool TRUE if group is set, FALSE otherwise
|
906 |
+
*/
|
907 |
+
hasGroup: function() {
|
908 |
+
return ( $.type(this.group) == 'string' && this.group.length > 0 ) ? true : false;
|
909 |
+
},
|
910 |
+
|
911 |
+
/* Slideshow */
|
912 |
+
|
913 |
+
/**
|
914 |
+
* Checks if slideshow is currently activated
|
915 |
+
* @return bool TRUE if slideshow is active, false otherwise
|
916 |
+
* @uses slideshow.active to check slideshow activation status
|
917 |
+
*/
|
918 |
+
slideshowActive: function() {
|
919 |
+
return this.slideshow.active;
|
920 |
+
},
|
921 |
+
|
922 |
+
/**
|
923 |
+
* Start the slideshow
|
924 |
+
*/
|
925 |
+
slideshowStart: function() {
|
926 |
+
this.slideshow.active = true;
|
927 |
+
var t = this;
|
928 |
+
clearInterval(this.slideshow.timer);
|
929 |
+
this.slideshow.timer = setInterval(function() { t.navNext(); t.slideshowPause(); }, this.slideshow.duration * 1000);
|
930 |
+
this.get('navSlideControl').text(this.getLabel('stopSlideshow'));
|
931 |
+
},
|
932 |
+
|
933 |
+
/**
|
934 |
+
* Stop the slideshow
|
935 |
+
*/
|
936 |
+
slideshowStop: function() {
|
937 |
+
this.slideshow.active = false;
|
938 |
+
if ( this.slideshow.timer ) {
|
939 |
+
clearInterval(this.slideshow.timer);
|
940 |
+
}
|
941 |
+
this.get('navSlideControl').text(this.getLabel('startSlideshow'));
|
942 |
+
},
|
943 |
+
|
944 |
+
/**
|
945 |
+
* Toggles the slideshow status
|
946 |
+
*/
|
947 |
+
slideshowToggle: function() {
|
948 |
+
if ( this.slideshowActive() ) {
|
949 |
+
this.slideshowStop();
|
950 |
+
} else {
|
951 |
+
this.slideshowStart();
|
952 |
+
}
|
953 |
+
},
|
954 |
+
|
955 |
+
/**
|
956 |
+
* Pauses the slideshow
|
957 |
+
* Stops the slideshow but does not change the slideshow's activation status
|
958 |
+
*/
|
959 |
+
slideshowPause: function() {
|
960 |
+
if ( this.slideshow.timer ) {
|
961 |
+
clearInterval(this.slideshow.timer);
|
962 |
+
}
|
963 |
+
},
|
964 |
+
|
965 |
+
/* Navigation */
|
966 |
+
|
967 |
+
/**
|
968 |
+
* Display appropriate previous and next hover navigation.
|
969 |
+
*/
|
970 |
+
navUpdate: function() {
|
971 |
+
if ( this.hasItems() ) {
|
972 |
+
this.get('navPrev').show();
|
973 |
+
this.get('navNext').show();
|
974 |
+
if ( this.slideshow.enabled ) {
|
975 |
+
this.get('navSlideControl').show();
|
976 |
+
if ( this.slideshowActive() ) {
|
977 |
+
this.slideshowStart();
|
978 |
+
} else {
|
979 |
+
this.slideshowStop();
|
980 |
+
}
|
981 |
+
} else {
|
982 |
+
this.get('navSlideControl').hide();
|
983 |
+
}
|
984 |
+
} else {
|
985 |
+
// Hide navigation controls when only one image exists
|
986 |
+
this.get('dataNumber').hide();
|
987 |
+
this.get('navPrev').hide();
|
988 |
+
this.get('navNext').hide();
|
989 |
+
this.get('navSlideControl').hide();
|
990 |
+
}
|
991 |
+
this.keyboardEnable();
|
992 |
+
},
|
993 |
+
|
994 |
+
/**
|
995 |
+
* Show the next image in the list
|
996 |
+
*/
|
997 |
+
navNext : function() {
|
998 |
+
if ( this.hasItems() ) {
|
999 |
+
if ( !this.slideshow.loop && this.itemLast() ) {
|
1000 |
+
return this.end();
|
1001 |
+
}
|
1002 |
+
if ( this.itemLast() ) {
|
1003 |
+
this.navFirst();
|
1004 |
+
} else {
|
1005 |
+
this.itemLoad(this.item_curr + 1);
|
1006 |
+
}
|
1007 |
+
}
|
1008 |
+
},
|
1009 |
+
|
1010 |
+
/**
|
1011 |
+
* Show the previous image in the list
|
1012 |
+
*/
|
1013 |
+
navPrev : function() {
|
1014 |
+
if ( this.hasItems() ) {
|
1015 |
+
if ( !this.slideshow.loop && this.itemFirst() ) {
|
1016 |
+
return this.end();
|
1017 |
+
}
|
1018 |
+
if ( this.itemFirst() ) {
|
1019 |
+
this.navLast();
|
1020 |
+
} else {
|
1021 |
+
this.itemLoad(this.item_curr - 1);
|
1022 |
+
}
|
1023 |
+
}
|
1024 |
+
},
|
1025 |
+
|
1026 |
+
/**
|
1027 |
+
* Show the first image in the list
|
1028 |
+
*/
|
1029 |
+
navFirst : function() {
|
1030 |
+
if ( this.hasItems() ) {
|
1031 |
+
this.itemLoad(0);
|
1032 |
+
}
|
1033 |
+
},
|
1034 |
+
|
1035 |
+
/**
|
1036 |
+
* Show the last image in the list
|
1037 |
+
*/
|
1038 |
+
navLast : function() {
|
1039 |
+
if ( this.hasItems() ) {
|
1040 |
+
this.itemLoad(this.items.length - 1);
|
1041 |
+
}
|
1042 |
+
},
|
1043 |
+
|
1044 |
+
/**
|
1045 |
+
* Enable image navigation via the keyboard
|
1046 |
+
*/
|
1047 |
+
keyboardEnable: function() {
|
1048 |
+
var t = this;
|
1049 |
+
$(document).keydown(function(e) {
|
1050 |
+
t.keyboardControl(e);
|
1051 |
+
});
|
1052 |
+
},
|
1053 |
+
|
1054 |
+
/**
|
1055 |
+
* Disable image navigation via the keyboard
|
1056 |
+
*/
|
1057 |
+
keyboardDisable: function() {
|
1058 |
+
$(document).unbind('keydown');
|
1059 |
+
},
|
1060 |
+
|
1061 |
+
/**
|
1062 |
+
* Handler for keyboard events
|
1063 |
+
* @param event e Keyboard event data
|
1064 |
+
*/
|
1065 |
+
keyboardControl: function(e) {
|
1066 |
+
var code = e.which;
|
1067 |
+
var key = String.fromCharCode(code).toLowerCase();
|
1068 |
+
|
1069 |
+
if ( code == 27 || key == 'x' ) {
|
1070 |
+
//Close
|
1071 |
+
this.end();
|
1072 |
+
} else if ( code == 39 || key =='n' ) {
|
1073 |
+
//Next
|
1074 |
+
this.navNext();
|
1075 |
+
} else if ( code == 37 || key == 'p' ) {
|
1076 |
+
//Previous
|
1077 |
+
this.navPrev();
|
1078 |
+
}
|
1079 |
+
},
|
1080 |
+
|
1081 |
+
/* Helpers */
|
1082 |
+
|
1083 |
+
/**
|
1084 |
+
* Generate separator text
|
1085 |
+
* @param string sep Separator text
|
1086 |
+
* @return string Separator text
|
1087 |
+
*/
|
1088 |
+
getSep: function(sep) {
|
1089 |
+
return ( typeof sep == 'undefined' ) ? '_' : sep;
|
1090 |
+
},
|
1091 |
+
|
1092 |
+
/**
|
1093 |
+
* Retrieve prefix
|
1094 |
+
* @return string Object prefix
|
1095 |
+
*/
|
1096 |
+
getPrefix: function() {
|
1097 |
+
return this.prefix;
|
1098 |
+
},
|
1099 |
+
|
1100 |
+
/**
|
1101 |
+
* Add prefix to text
|
1102 |
+
* @param string txt Text to add prefix to
|
1103 |
+
* @param string sep (optional) Separator text
|
1104 |
+
* @return string Prefixed text
|
1105 |
+
*/
|
1106 |
+
addPrefix: function(txt, sep) {
|
1107 |
+
return this.getPrefix() + this.getSep(sep) + txt;
|
1108 |
+
},
|
1109 |
+
|
1110 |
+
hasPrefix: function(txt) {
|
1111 |
+
return ( txt.indexOf(this.addPrefix('')) === 0 ) ? true : false;
|
1112 |
+
},
|
1113 |
+
|
1114 |
+
/**
|
1115 |
+
* Generate formatted ID for viewer-specific elements
|
1116 |
+
* @param string id Base ID of element
|
1117 |
+
* @return string Formatted ID
|
1118 |
+
*/
|
1119 |
+
getID: function(id) {
|
1120 |
+
return this.addPrefix(id);
|
1121 |
+
},
|
1122 |
+
|
1123 |
+
/**
|
1124 |
+
* Generate formatted selector for viewer-specific elements
|
1125 |
+
* Compares specified ID to placeholders first, then named elements
|
1126 |
+
* Multiple selectors can be included and separated by commas (',')
|
1127 |
+
* @param string id Base ID of element
|
1128 |
+
* @uses layout.placeholders to compare id to placeholder names
|
1129 |
+
* @return string Formatted selector
|
1130 |
+
*/
|
1131 |
+
getSel: function(id) {
|
1132 |
+
//Process multiple selectors
|
1133 |
+
var delim = ',', prefix = '#', sel;
|
1134 |
+
if (id.toString().indexOf(delim) != -1) {
|
1135 |
+
//Split
|
1136 |
+
var sels = id.toString().split(delim);
|
1137 |
+
//Build selector
|
1138 |
+
for (var x = 0; x < sels.length; x++) {
|
1139 |
+
sels[x] = this.getSel($.trim(sels[x]));
|
1140 |
+
}
|
1141 |
+
//Join
|
1142 |
+
sel = sels.join(delim);
|
1143 |
+
} else {
|
1144 |
+
//Single selector
|
1145 |
+
if ( id in this.layout.placeholders ) {
|
1146 |
+
var ph = $( this.layout.placeholders[id] );
|
1147 |
+
if (!ph.attr('id')) {
|
1148 |
+
//Class selector
|
1149 |
+
prefix = '.';
|
1150 |
+
}
|
1151 |
+
}
|
1152 |
+
sel = prefix + this.getID(id);
|
1153 |
+
}
|
1154 |
+
|
1155 |
+
return sel;
|
1156 |
+
},
|
1157 |
+
|
1158 |
+
/**
|
1159 |
+
* Retrieve viewer-specific element
|
1160 |
+
* @param string id Base ID of element
|
1161 |
+
* @uses getSel() to generate formatted selector for element
|
1162 |
+
* @return object jQuery object of selected element(s)
|
1163 |
+
*/
|
1164 |
+
get: function(id) {
|
1165 |
+
return $(this.getSel(id));
|
1166 |
+
},
|
1167 |
+
|
1168 |
+
/**
|
1169 |
+
* Checks if file exists using AJAX request
|
1170 |
+
* @param string url File URL
|
1171 |
+
* @param callback success Callback to run if file exists
|
1172 |
+
* @param callback failure Callback to run if file does not exist
|
1173 |
+
* @param obj args Arguments for callback
|
1174 |
+
*/
|
1175 |
+
fileExists: function(url, success, failure, args) {
|
1176 |
+
//Validate
|
1177 |
+
var t = this;
|
1178 |
+
if ( !$.isPlainObject(args) ) {
|
1179 |
+
args = null;
|
1180 |
+
}
|
1181 |
+
if ( !$.isFunction(failure) ) {
|
1182 |
+
failure = function() {
|
1183 |
+
t.end();
|
1184 |
+
};
|
1185 |
+
}
|
1186 |
+
if ( !$.isFunction(success) ) {
|
1187 |
+
success = failure;
|
1188 |
+
}
|
1189 |
+
|
1190 |
+
//Immediate success when validation disabled
|
1191 |
+
if ( !this.options.validateLinks ) {
|
1192 |
+
return success(args);
|
1193 |
+
}
|
1194 |
+
|
1195 |
+
//Validate link
|
1196 |
+
var statusFail = 400;
|
1197 |
+
var stateCheck = 4;
|
1198 |
+
var proceed = function(res) {
|
1199 |
+
if ( res.status < statusFail ) {
|
1200 |
+
success(args);
|
1201 |
+
} else {
|
1202 |
+
failure(args);
|
1203 |
+
}
|
1204 |
+
};
|
1205 |
+
|
1206 |
+
//Check if URL already processed
|
1207 |
+
if ( url in this.urls_checked ) {
|
1208 |
+
proceed(this.urls_checked[url]);
|
1209 |
+
} else {
|
1210 |
+
//Build AJAX request to check new file
|
1211 |
+
var req = new XMLHttpRequest();
|
1212 |
+
req.open('HEAD', url, true);
|
1213 |
+
req.onreadystatechange = function() {
|
1214 |
+
if ( stateCheck == this.readyState ) {
|
1215 |
+
t.addUrl(url, this);
|
1216 |
+
proceed(this);
|
1217 |
+
}
|
1218 |
+
};
|
1219 |
+
req.send();
|
1220 |
+
}
|
1221 |
+
},
|
1222 |
+
|
1223 |
+
addUrl: function(url, res) {
|
1224 |
+
if (!(url in this.urls_checked))
|
1225 |
+
this.urls_checked[url] = res;
|
1226 |
+
}
|
1227 |
+
};
|
1228 |
+
})(jQuery);
|
l10n/simple-lightbox.pot
ADDED
@@ -0,0 +1,161 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Copyright (C) 2010
|
2 |
+
# This file is distributed under the same license as the package.
|
3 |
+
msgid ""
|
4 |
+
msgstr ""
|
5 |
+
"Project-Id-Version: \n"
|
6 |
+
"Report-Msgid-Bugs-To: http://wordpress.org/tag/simple-lightbox\n"
|
7 |
+
"POT-Creation-Date: 2011-10-14 03:38:17+00:00\n"
|
8 |
+
"MIME-Version: 1.0\n"
|
9 |
+
"Content-Type: text/plain; charset=UTF-8\n"
|
10 |
+
"Content-Transfer-Encoding: 8bit\n"
|
11 |
+
"PO-Revision-Date: 2010-MO-DA HO:MI+ZONE\n"
|
12 |
+
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
13 |
+
"Language-Team: LANGUAGE <LL@li.org>\n"
|
14 |
+
|
15 |
+
#: model.php:88
|
16 |
+
msgid "Activation"
|
17 |
+
msgstr ""
|
18 |
+
|
19 |
+
#: model.php:89
|
20 |
+
msgid "Grouping"
|
21 |
+
msgstr ""
|
22 |
+
|
23 |
+
#: model.php:90
|
24 |
+
msgid "UI"
|
25 |
+
msgstr ""
|
26 |
+
|
27 |
+
#: model.php:91
|
28 |
+
msgid "Labels"
|
29 |
+
msgstr ""
|
30 |
+
|
31 |
+
#: model.php:94
|
32 |
+
msgid "Enable Lightbox Functionality"
|
33 |
+
msgstr ""
|
34 |
+
|
35 |
+
#: model.php:95
|
36 |
+
msgid "Enable on Home page"
|
37 |
+
msgstr ""
|
38 |
+
|
39 |
+
#: model.php:96
|
40 |
+
msgid "Enable on Posts"
|
41 |
+
msgstr ""
|
42 |
+
|
43 |
+
#: model.php:97
|
44 |
+
msgid "Enable on Pages"
|
45 |
+
msgstr ""
|
46 |
+
|
47 |
+
#: model.php:98
|
48 |
+
msgid "Enable on Archive Pages (tags, categories, etc.)"
|
49 |
+
msgstr ""
|
50 |
+
|
51 |
+
#: model.php:99
|
52 |
+
msgid "Enable backwards-compatibility with legacy lightbox links"
|
53 |
+
msgstr ""
|
54 |
+
|
55 |
+
#: model.php:100
|
56 |
+
msgid "Activate image attachment links"
|
57 |
+
msgstr ""
|
58 |
+
|
59 |
+
#: model.php:101
|
60 |
+
msgid "Validate links"
|
61 |
+
msgstr ""
|
62 |
+
|
63 |
+
#: model.php:102
|
64 |
+
msgid "Group image links (for displaying as a slideshow)"
|
65 |
+
msgstr ""
|
66 |
+
|
67 |
+
#: model.php:103
|
68 |
+
msgid "Group image links by Post (e.g. on pages with multiple posts)"
|
69 |
+
msgstr ""
|
70 |
+
|
71 |
+
#: model.php:104
|
72 |
+
msgid "Group gallery links separately"
|
73 |
+
msgstr ""
|
74 |
+
|
75 |
+
#: model.php:105
|
76 |
+
msgid "Theme"
|
77 |
+
msgstr ""
|
78 |
+
|
79 |
+
#: model.php:106
|
80 |
+
msgid "Animate lightbox resizing"
|
81 |
+
msgstr ""
|
82 |
+
|
83 |
+
#: model.php:107
|
84 |
+
msgid "Automatically Start Slideshow"
|
85 |
+
msgstr ""
|
86 |
+
|
87 |
+
#: model.php:108
|
88 |
+
msgid "Slide Duration (Seconds)"
|
89 |
+
msgstr ""
|
90 |
+
|
91 |
+
#: model.php:109
|
92 |
+
msgid "Loop through images"
|
93 |
+
msgstr ""
|
94 |
+
|
95 |
+
#: model.php:110
|
96 |
+
msgid "Overlay Opacity (0 - 1)"
|
97 |
+
msgstr ""
|
98 |
+
|
99 |
+
#: model.php:111
|
100 |
+
msgid "Enable caption"
|
101 |
+
msgstr ""
|
102 |
+
|
103 |
+
#: model.php:112
|
104 |
+
msgid "Use image URI as caption when link title not set"
|
105 |
+
msgstr ""
|
106 |
+
|
107 |
+
#: model.php:113
|
108 |
+
msgid "Enable description"
|
109 |
+
msgstr ""
|
110 |
+
|
111 |
+
#: model.php:114
|
112 |
+
msgid "Close link (for accessibility only, image used for button)"
|
113 |
+
msgstr ""
|
114 |
+
|
115 |
+
#: model.php:115
|
116 |
+
msgid "Loading indicator"
|
117 |
+
msgstr ""
|
118 |
+
|
119 |
+
#: model.php:116
|
120 |
+
msgid "Next Image link"
|
121 |
+
msgstr ""
|
122 |
+
|
123 |
+
#: model.php:117
|
124 |
+
msgid "Previous Image link"
|
125 |
+
msgstr ""
|
126 |
+
|
127 |
+
#: model.php:118
|
128 |
+
msgid "Start Slideshow link"
|
129 |
+
msgstr ""
|
130 |
+
|
131 |
+
#: model.php:119
|
132 |
+
msgid "Stop Slideshow link"
|
133 |
+
msgstr ""
|
134 |
+
|
135 |
+
#: model.php:120
|
136 |
+
msgid "Image number prefix (e.g. <strong>Image</strong> x of y)"
|
137 |
+
msgstr ""
|
138 |
+
|
139 |
+
#: model.php:121
|
140 |
+
msgid "Image number separator (e.g. Image x <strong>of</strong> y)"
|
141 |
+
msgstr ""
|
142 |
+
|
143 |
+
#: model.php:728
|
144 |
+
msgid "Settings"
|
145 |
+
msgstr ""
|
146 |
+
|
147 |
+
#: model.php:729
|
148 |
+
msgid "Reset"
|
149 |
+
msgstr ""
|
150 |
+
|
151 |
+
#: model.php:730
|
152 |
+
msgid "Are you sure you want to reset your settings?"
|
153 |
+
msgstr ""
|
154 |
+
|
155 |
+
#: model.php:746
|
156 |
+
msgid "You do not have sufficient permissions to manage plugins for this blog."
|
157 |
+
msgstr ""
|
158 |
+
|
159 |
+
#: model.php:796
|
160 |
+
msgid "Lightbox Settings"
|
161 |
+
msgstr ""
|
main.php
CHANGED
@@ -2,13 +2,13 @@
|
|
2 |
/*
|
3 |
Plugin Name: Simple Lightbox
|
4 |
Plugin URI: http://archetyped.com/tools/simple-lightbox/
|
5 |
-
Description: Customizable Lightbox for Wordpress
|
6 |
-
Version: 1.3.1
|
7 |
Author: Archetyped
|
8 |
Author URI: http://archetyped.com
|
9 |
*/
|
10 |
/*
|
11 |
-
Copyright
|
12 |
|
13 |
This program is free software; you can redistribute it and/or
|
14 |
modify it under the terms of the GNU General Public License
|
@@ -24,14 +24,18 @@ You should have received a copy of the GNU General Public License
|
|
24 |
along with this program; if not, write to the Free Software
|
25 |
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
26 |
*/
|
27 |
-
|
28 |
require_once 'model.php';
|
29 |
|
30 |
-
$slb
|
31 |
|
32 |
function slb_enabled() {
|
33 |
global $slb;
|
34 |
return $slb->is_enabled();
|
35 |
}
|
36 |
|
|
|
|
|
|
|
|
|
|
|
37 |
?>
|
2 |
/*
|
3 |
Plugin Name: Simple Lightbox
|
4 |
Plugin URI: http://archetyped.com/tools/simple-lightbox/
|
5 |
+
Description: Highly Customizable Lightbox for Wordpress
|
6 |
+
Version: 1.6.3.1
|
7 |
Author: Archetyped
|
8 |
Author URI: http://archetyped.com
|
9 |
*/
|
10 |
/*
|
11 |
+
Copyright 2011 Solomon Marchessault (contact@archetyped.com)
|
12 |
|
13 |
This program is free software; you can redistribute it and/or
|
14 |
modify it under the terms of the GNU General Public License
|
24 |
along with this program; if not, write to the Free Software
|
25 |
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
26 |
*/
|
|
|
27 |
require_once 'model.php';
|
28 |
|
29 |
+
$slb = new SLB_Lightbox();
|
30 |
|
31 |
function slb_enabled() {
|
32 |
global $slb;
|
33 |
return $slb->is_enabled();
|
34 |
}
|
35 |
|
36 |
+
function slb_register_theme($name, $title, $stylesheet_url, $layout) {
|
37 |
+
global $slb;
|
38 |
+
$slb->register_theme($name, $title, $stylesheet_url, $layout);
|
39 |
+
}
|
40 |
+
|
41 |
?>
|
model.php
CHANGED
@@ -1,6 +1,7 @@
|
|
1 |
<?php
|
2 |
|
3 |
require_once 'includes/class.base.php';
|
|
|
4 |
|
5 |
/**
|
6 |
* Lightbox functionality class
|
@@ -11,6 +12,14 @@ class SLB_Lightbox extends SLB_Base {
|
|
11 |
|
12 |
/*-** Properties **-*/
|
13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
/**
|
15 |
* Page that plugin options are on
|
16 |
* @var string
|
@@ -24,38 +33,82 @@ class SLB_Lightbox extends SLB_Base {
|
|
24 |
var $options_admin_form = 'options.php';
|
25 |
|
26 |
/**
|
27 |
-
*
|
28 |
-
*
|
29 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
30 |
* @var array
|
31 |
*/
|
32 |
-
var $
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
|
60 |
function SLB_Lightbox() {
|
61 |
$this->__construct();
|
@@ -64,15 +117,99 @@ class SLB_Lightbox extends SLB_Base {
|
|
64 |
function __construct() {
|
65 |
parent::__construct();
|
66 |
$this->init();
|
|
|
|
|
|
|
|
|
67 |
}
|
68 |
|
69 |
-
|
70 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
71 |
}
|
72 |
|
73 |
function register_hooks() {
|
74 |
-
|
|
|
75 |
/* Admin */
|
|
|
76 |
//Init lightbox admin
|
77 |
add_action('admin_init', $this->m('admin_settings'));
|
78 |
//Enqueue header files (CSS/JS)
|
@@ -80,34 +217,50 @@ class SLB_Lightbox extends SLB_Base {
|
|
80 |
//Reset Settings
|
81 |
add_action('admin_action_' . $this->add_prefix('reset'), $this->m('admin_reset'));
|
82 |
add_action('admin_notices', $this->m('admin_notices'));
|
|
|
|
|
|
|
|
|
83 |
|
84 |
/* Client-side */
|
85 |
-
|
|
|
|
|
86 |
add_action('wp_enqueue_scripts', $this->m('enqueue_files'));
|
87 |
add_action('wp_head', $this->m('client_init'));
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
95 |
}
|
|
|
|
|
96 |
|
|
|
|
|
97 |
/**
|
98 |
-
*
|
99 |
-
* @
|
|
|
|
|
100 |
*/
|
101 |
-
function
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
update_option($opt, $data[0]);
|
108 |
-
}
|
109 |
}
|
110 |
-
|
111 |
/*-** Helpers **-*/
|
112 |
|
113 |
/**
|
@@ -115,127 +268,797 @@ class SLB_Lightbox extends SLB_Base {
|
|
115 |
* @return bool TRUE if lightbox is currently enabled, FALSE otherwise
|
116 |
*/
|
117 |
function is_enabled($check_request = true) {
|
118 |
-
$ret = (
|
119 |
if ( $ret && $check_request ) {
|
120 |
$opt = '';
|
121 |
//Determine option to check
|
122 |
if ( is_home() )
|
123 |
$opt = 'home';
|
124 |
-
elseif (
|
125 |
-
$opt = '
|
|
|
126 |
elseif ( is_archive() || is_search() )
|
127 |
$opt = 'archive';
|
128 |
//Check option
|
129 |
-
if ( !
|
130 |
-
$ret =
|
131 |
}
|
132 |
}
|
133 |
return $ret;
|
134 |
}
|
135 |
|
|
|
|
|
136 |
/**
|
137 |
-
*
|
138 |
-
*
|
139 |
-
*
|
140 |
-
*
|
141 |
-
*
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
$
|
149 |
-
|
150 |
-
$
|
151 |
-
|
152 |
-
|
153 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
154 |
}
|
155 |
|
156 |
/**
|
157 |
-
*
|
158 |
-
*
|
159 |
-
* @
|
|
|
|
|
|
|
|
|
|
|
|
|
160 |
*/
|
161 |
-
function
|
162 |
-
|
163 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
164 |
}
|
165 |
|
166 |
/**
|
167 |
-
*
|
168 |
-
* @param string $
|
169 |
-
* @return
|
|
|
170 |
*/
|
171 |
-
function
|
172 |
-
$
|
173 |
-
|
174 |
-
|
175 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
176 |
}
|
177 |
|
178 |
/**
|
179 |
-
* Retrieve
|
180 |
-
* @param string $
|
181 |
-
* @
|
182 |
-
* @return
|
183 |
*/
|
184 |
-
function
|
185 |
-
$
|
186 |
-
if
|
187 |
-
|
188 |
-
|
189 |
-
if ( $formatted ) {
|
190 |
-
if ( is_bool($ret) || ( is_string($ret) && 'on' == $ret ) )
|
191 |
-
$ret = ( $ret ) ? 'Enabled' : 'Disabled';
|
192 |
-
if ( is_numeric($ret) )
|
193 |
-
$ret = strval($ret);
|
194 |
-
$ret = htmlentities($ret);
|
195 |
-
}
|
196 |
-
} elseif ( ! is_array($this->options_default[$option]) ) {
|
197 |
-
$ret = $this->options_default[$option];
|
198 |
}
|
199 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
200 |
}
|
201 |
|
202 |
/*-** Frontend **-*/
|
203 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
204 |
/**
|
205 |
* Scans post content for image links and activates them
|
206 |
*
|
207 |
* Lightbox will not be activated for feeds
|
208 |
* @param $content
|
|
|
209 |
*/
|
210 |
-
function
|
211 |
-
//
|
212 |
-
if (
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
226 |
}
|
227 |
|
228 |
-
if (
|
229 |
-
|
230 |
-
$rel .= ' lightbox[' . $this->add_prefix($post->ID) . ']';
|
231 |
-
$link_new = '<a rel="' . $rel . '"' . substr($link_new,2);
|
232 |
-
//Insert modified link
|
233 |
-
$content = str_replace($link, $link_new, $content);
|
234 |
}
|
|
|
|
|
|
|
235 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
236 |
}
|
237 |
}
|
238 |
-
return $content;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
239 |
}
|
240 |
|
241 |
/**
|
@@ -244,8 +1067,11 @@ class SLB_Lightbox extends SLB_Base {
|
|
244 |
function enqueue_files() {
|
245 |
if ( ! $this->is_enabled() )
|
246 |
return;
|
247 |
-
|
248 |
-
|
|
|
|
|
|
|
249 |
}
|
250 |
|
251 |
/**
|
@@ -255,58 +1081,216 @@ class SLB_Lightbox extends SLB_Base {
|
|
255 |
function client_init() {
|
256 |
if ( ! $this->is_enabled() )
|
257 |
return;
|
258 |
-
|
259 |
$options = array();
|
260 |
$out = array();
|
261 |
-
$out['script_start'] = '<script type="text/javascript">Event.observe(window,"load",function(){';
|
262 |
-
$out['script_end'] = '});</script>';
|
263 |
$js_code = array();
|
264 |
-
//Activate links on page
|
265 |
-
if ( $this->get_option_value('activate_links') ) {
|
266 |
-
$rel = ( $this->get_option_value('group_links') ) ? 'lightbox[' . $this->get_prefix() . ']' : 'lightbox';
|
267 |
-
ob_start();
|
268 |
-
?>
|
269 |
-
$$('a[href$=".jpg"]:not([rel~="lightbox"])','a[href$=".jpeg"]:not([rel~="lightbox"])','a[href$=".gif"]:not([rel~="lightbox"])','a[href$=".png"]:not([rel~="lightbox"])').each(function(el){if (! /(^|\b)lightbox\[.+\]($|\b)/i.test(el.rel)){var rel=(el.rel.length > 0) ? el.rel + ' ' : '';el.rel=rel + '<?php echo $rel; ?>';}});
|
270 |
-
<?php
|
271 |
-
$js_code[] = ob_get_clean();
|
272 |
-
}
|
273 |
//Get options
|
274 |
$options = array(
|
275 |
-
'
|
276 |
-
'
|
277 |
-
'
|
278 |
-
'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
279 |
);
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
elseif ($val === FALSE || empty($val))
|
285 |
-
$val = 'false';
|
286 |
-
$lb_obj[] = "'{$option}':{$val}";
|
287 |
-
}
|
288 |
//Load UI Strings
|
289 |
-
if ( ($strings = $this->
|
290 |
-
$
|
291 |
-
|
292 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
293 |
}
|
294 |
|
295 |
/**
|
296 |
* Build JS object of UI strings when initializing lightbox
|
297 |
-
* @return
|
298 |
*/
|
299 |
-
function
|
300 |
-
$ret =
|
|
|
301 |
$prefix = 'txt_';
|
302 |
-
$opt_strings = array_filter(array_keys($this->
|
303 |
-
if ( $opt_strings ) {
|
304 |
-
|
305 |
foreach ( $opt_strings as $key ) {
|
306 |
$name = substr($key, strlen($prefix));
|
307 |
-
$
|
308 |
}
|
309 |
-
$ret = "'strings':{" . implode(',', $strings) . "}";
|
310 |
}
|
311 |
return $ret;
|
312 |
}
|
@@ -315,6 +1299,7 @@ class SLB_Lightbox extends SLB_Base {
|
|
315 |
|
316 |
/**
|
317 |
* Adds custom links below plugin on plugin listing page
|
|
|
318 |
* @param $actions
|
319 |
* @param $plugin_file
|
320 |
* @param $plugin_data
|
@@ -323,9 +1308,9 @@ class SLB_Lightbox extends SLB_Base {
|
|
323 |
function admin_plugin_action_links($actions, $plugin_file, $plugin_data, $context) {
|
324 |
//Add link to settings (only if active)
|
325 |
if ( is_plugin_active($this->util->get_plugin_base_name()) ) {
|
326 |
-
$settings = __('Settings');
|
327 |
-
$reset = __('Reset');
|
328 |
-
$reset_confirm = "'" . __('Are you sure you want to reset your settings?') . "'";
|
329 |
$action = $this->add_prefix('reset');
|
330 |
$reset_link = wp_nonce_url(add_query_arg('action', $action, remove_query_arg(array($this->add_prefix('action'), 'action'), $_SERVER['REQUEST_URI'])), $action);
|
331 |
array_unshift($actions, '<a class="delete" href="options-media.php#' . $this->admin_get_settings_section() . '" title="' . $settings . '">' . $settings . '</a>');
|
@@ -334,6 +1319,52 @@ class SLB_Lightbox extends SLB_Base {
|
|
334 |
return $actions;
|
335 |
}
|
336 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
337 |
/**
|
338 |
* Reset plugin settings
|
339 |
* Redirects to referring page upon completion
|
@@ -341,11 +1372,11 @@ class SLB_Lightbox extends SLB_Base {
|
|
341 |
function admin_reset() {
|
342 |
//Validate user
|
343 |
if ( ! current_user_can('activate_plugins') || ! check_admin_referer($this->add_prefix('reset')) )
|
344 |
-
wp_die(__('You do not have sufficient permissions to manage plugins for this blog.'));
|
345 |
$action = 'reset';
|
346 |
if ( isset($_REQUEST['action']) && $this->add_prefix($action) == $_REQUEST['action'] ) {
|
347 |
//Reset settings
|
348 |
-
$this->
|
349 |
$uri = remove_query_arg(array('_wpnonce', 'action'), add_query_arg(array($this->add_prefix('action') => $action), $_SERVER['REQUEST_URI']));
|
350 |
//Redirect user
|
351 |
wp_redirect($uri);
|
@@ -378,6 +1409,7 @@ class SLB_Lightbox extends SLB_Base {
|
|
378 |
/**
|
379 |
* Adds settings section for Lightbox functionality
|
380 |
* Section is added to Settings > Media Admin menu
|
|
|
381 |
*/
|
382 |
function admin_settings() {
|
383 |
$page = $this->options_admin_page;
|
@@ -390,37 +1422,26 @@ class SLB_Lightbox extends SLB_Base {
|
|
390 |
$page = 'media';
|
391 |
$section = $this->get_prefix();
|
392 |
//Section
|
393 |
-
add_settings_section($section, '<
|
394 |
-
//
|
395 |
-
|
396 |
-
|
397 |
-
$func = 'admin_field_' . $key;
|
398 |
-
$label = ( isset($defaults[1]) ) ? $defaults[1] : '';
|
399 |
-
$callback = ( method_exists($this, $func) ) ? $this->m($func) : $this->m('admin_field_default');
|
400 |
-
$args = array('opt' => $key);
|
401 |
-
//Check if option is a section header
|
402 |
-
if ( ! is_array($defaults) ) {
|
403 |
-
$label = '<h4 class="subhead">' . $defaults . '</h4>';
|
404 |
-
$callback = $this->m('admin_field_header');
|
405 |
-
} elseif ( is_null(get_option($id, null)) ) {
|
406 |
-
//Add option to DB if not yet set
|
407 |
-
$args['label_for'] = $id;
|
408 |
-
update_option($id, htmlentities2($defaults[0]));
|
409 |
-
}
|
410 |
-
add_settings_field($id, __($label), $callback, $page, $section, $args);
|
411 |
-
register_setting($page, $id);
|
412 |
-
}
|
413 |
-
}
|
414 |
|
|
|
|
|
|
|
|
|
415 |
function admin_enqueue_files() {
|
416 |
-
|
417 |
-
|
|
|
418 |
}
|
419 |
}
|
420 |
|
421 |
/**
|
422 |
* Get ID of settings section on admin page
|
423 |
* @return string ID of settings section
|
|
|
424 |
*/
|
425 |
function admin_get_settings_section() {
|
426 |
return $this->add_prefix('settings');
|
@@ -429,67 +1450,34 @@ class SLB_Lightbox extends SLB_Base {
|
|
429 |
/**
|
430 |
* Placeholder function for lightbox admin settings
|
431 |
* Required because setting init function requires a callback
|
|
|
432 |
*/
|
433 |
-
function admin_section() {
|
434 |
-
|
435 |
-
/**
|
436 |
-
* General field builder
|
437 |
-
* @param string $option Option name to build field for
|
438 |
-
* @param string $format Field markup (using sprintf specifiers)
|
439 |
-
* @param string $type (optional) Type of field being build (e.g. checkbox, text, etc.)
|
440 |
-
* Specifiers:
|
441 |
-
* 1. Field ID
|
442 |
-
* 2. Field Value
|
443 |
-
* 3. Field Default Value (formatted)
|
444 |
-
* 4. Field Type
|
445 |
-
*/
|
446 |
-
function admin_the_field($option, $format = '', $type = '') {
|
447 |
-
$opt = $this->get_option($option);
|
448 |
-
$format_default = '<input id="%1$s" name="%1$s" %4$s class="code" /> (Default: %3$s)';
|
449 |
-
if ( empty($format) && $format !== false )
|
450 |
-
$format = $format_default;
|
451 |
-
if ( empty($type) || !is_string($type) ) {
|
452 |
-
$type_default = 'text';
|
453 |
-
$type = ( is_bool($opt->value_default) ) ? 'checkbox' : $type_default;
|
454 |
-
}
|
455 |
-
//Adjust type and value formatting based on type
|
456 |
-
switch ( $type ) {
|
457 |
-
case 'checkbox' :
|
458 |
-
if ( $opt->value )
|
459 |
-
$opt->attr['checked'] = 'checked';
|
460 |
-
break;
|
461 |
-
case 'text' :
|
462 |
-
if ( $format == $format_default )
|
463 |
-
$format = str_replace('%4$s', '%4$s value="%2$s"', $format);
|
464 |
-
break;
|
465 |
-
}
|
466 |
-
$opt->attr['type'] = $type;
|
467 |
-
//Build attribute string
|
468 |
-
$attr = '';
|
469 |
-
if ( ! empty($opt->attr) ) {
|
470 |
-
$attr = $this->util->build_attribute_string($opt->attr);
|
471 |
-
}
|
472 |
-
|
473 |
-
echo sprintf($format, $opt->id, htmlentities($opt->value), $opt->value_default_formatted, $attr);
|
474 |
}
|
475 |
|
476 |
-
|
477 |
-
* Builds header for settings subsection
|
478 |
-
* @param array $args Arguments set in admin_settings
|
479 |
-
*/
|
480 |
-
function admin_field_header($args) {
|
481 |
-
$opt = ( isset($args['opt']) ) ? $args['opt'] : '';
|
482 |
-
$this->admin_the_field($opt, false, 'header');
|
483 |
-
}
|
484 |
|
485 |
-
|
486 |
-
|
487 |
-
|
488 |
-
|
489 |
-
|
490 |
-
$
|
491 |
-
$this->
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
492 |
}
|
493 |
}
|
494 |
|
495 |
-
?>
|
1 |
<?php
|
2 |
|
3 |
require_once 'includes/class.base.php';
|
4 |
+
require_once 'includes/class.options.php';
|
5 |
|
6 |
/**
|
7 |
* Lightbox functionality class
|
12 |
|
13 |
/*-** Properties **-*/
|
14 |
|
15 |
+
/**
|
16 |
+
* Themes
|
17 |
+
* @var array
|
18 |
+
*/
|
19 |
+
var $themes = array();
|
20 |
+
|
21 |
+
var $theme_default = 'default';
|
22 |
+
|
23 |
/**
|
24 |
* Page that plugin options are on
|
25 |
* @var string
|
33 |
var $options_admin_form = 'options.php';
|
34 |
|
35 |
/**
|
36 |
+
* Value to identify activated links
|
37 |
+
* Formatted on initialization
|
38 |
+
* @var string
|
39 |
+
*/
|
40 |
+
var $attr = null;
|
41 |
+
|
42 |
+
/**
|
43 |
+
* Legacy attribute (for backwards compatibility)
|
44 |
+
* @var string
|
45 |
+
*/
|
46 |
+
var $attr_legacy = 'lightbox';
|
47 |
+
|
48 |
+
/**
|
49 |
+
* Properties for media attachments in current request
|
50 |
+
* > Key (string) Attachment URI
|
51 |
+
* > Value (assoc-array) Attachment properties (url, etc.)
|
52 |
+
* > source: Source URL
|
53 |
+
* @var array
|
54 |
+
*/
|
55 |
+
var $media_attachments = array();
|
56 |
+
|
57 |
+
/**
|
58 |
+
* Raw media items
|
59 |
+
* Used for populating media object on client-side
|
60 |
+
* > Key: Item URI
|
61 |
+
* > Value: Associative array of media properties
|
62 |
+
* > type: Item type (Default: null)
|
63 |
+
* > id: Item ID (Default: null)
|
64 |
* @var array
|
65 |
*/
|
66 |
+
var $media_items_raw = array();
|
67 |
+
|
68 |
+
/**
|
69 |
+
* Media types
|
70 |
+
* @var array
|
71 |
+
*/
|
72 |
+
var $media_types = array('img' => 'image', 'att' => 'attachment');
|
73 |
+
|
74 |
+
/* Widget properties */
|
75 |
+
|
76 |
+
/**
|
77 |
+
* Widget callback key
|
78 |
+
* @var string
|
79 |
+
*/
|
80 |
+
var $widget_callback = 'callback';
|
81 |
+
|
82 |
+
/**
|
83 |
+
* Key to use to store original callback
|
84 |
+
* @var string
|
85 |
+
*/
|
86 |
+
var $widget_callback_orig = 'callback_orig';
|
87 |
+
|
88 |
+
/**
|
89 |
+
* Used to track if widget is currently being processed or not
|
90 |
+
* @var bool
|
91 |
+
*/
|
92 |
+
var $widget_processing = false;
|
93 |
+
|
94 |
+
/* Instance members */
|
95 |
+
|
96 |
+
/**
|
97 |
+
* Options instance
|
98 |
+
* @var SLB_Options
|
99 |
+
*/
|
100 |
+
var $options = null;
|
101 |
+
|
102 |
+
/**
|
103 |
+
* Base field definitions
|
104 |
+
* Stores system/user-defined field definitions
|
105 |
+
* @var SLB_Fields
|
106 |
+
*/
|
107 |
+
var $fields = null;
|
108 |
+
|
109 |
+
var $h_temp = array();
|
110 |
+
|
111 |
+
/* Constructor */
|
112 |
|
113 |
function SLB_Lightbox() {
|
114 |
$this->__construct();
|
117 |
function __construct() {
|
118 |
parent::__construct();
|
119 |
$this->init();
|
120 |
+
|
121 |
+
//Init objects
|
122 |
+
$this->attr = $this->get_prefix();
|
123 |
+
$this->fields = new SLB_Fields();
|
124 |
}
|
125 |
|
126 |
+
/* Init */
|
127 |
+
|
128 |
+
function init_env() {
|
129 |
+
//Localization
|
130 |
+
$ldir = 'l10n';
|
131 |
+
$lpath = $this->util->get_plugin_file_path($ldir, array(false, false));
|
132 |
+
$lpath_abs = $this->util->get_file_path($ldir);
|
133 |
+
if ( is_dir($lpath_abs) ) {
|
134 |
+
load_plugin_textdomain($this->util->get_plugin_textdomain(), false, $lpath);
|
135 |
+
}
|
136 |
+
//Options
|
137 |
+
$func_opts = 'init_options';
|
138 |
+
if ( isset($this) && method_exists($this, $func_opts) ) {
|
139 |
+
call_user_func($this->m($func_opts));
|
140 |
+
}
|
141 |
+
|
142 |
+
//Context
|
143 |
+
$func_context = $this->m('set_client_context');
|
144 |
+
$hook_context = ( is_admin() ) ? 'admin_head' : 'wp_head';
|
145 |
+
add_action($hook_context, $func_context);
|
146 |
+
}
|
147 |
+
|
148 |
+
/**
|
149 |
+
* Init options
|
150 |
+
*/
|
151 |
+
function init_options() {
|
152 |
+
//Setup options
|
153 |
+
$p = $this->util->get_plugin_base(true);
|
154 |
+
$options_config = array (
|
155 |
+
'groups' => array (
|
156 |
+
'activation' => __('Activation', $p),
|
157 |
+
'grouping' => __('Grouping', $p),
|
158 |
+
'ui' => __('UI', $p),
|
159 |
+
'labels' => __('Labels', $p)
|
160 |
+
),
|
161 |
+
'items' => array (
|
162 |
+
'enabled' => array('title' => __('Enable Lightbox Functionality', $p), 'default' => true, 'group' => 'activation'),
|
163 |
+
'enabled_home' => array('title' => __('Enable on Home page', $p), 'default' => true, 'group' => 'activation'),
|
164 |
+
'enabled_post' => array('title' => __('Enable on Posts', $p), 'default' => true, 'group' => 'activation'),
|
165 |
+
'enabled_page' => array('title' => __('Enable on Pages', $p), 'default' => true, 'group' => 'activation'),
|
166 |
+
'enabled_archive' => array('title' => __('Enable on Archive Pages (tags, categories, etc.)', $p), 'default' => true, 'group' => 'activation'),
|
167 |
+
'enabled_widget' => array('title' => __('Enable for Widgets', $p), 'default' => false, 'group' => 'activation'),
|
168 |
+
'enabled_compat' => array('title' => __('Enable backwards-compatibility with legacy lightbox links', $p), 'default' => false, 'group' => 'activation'),
|
169 |
+
'activate_attachments' => array('title' => __('Activate image attachment links', $p), 'default' => true, 'group' => 'activation'),
|
170 |
+
'validate_links' => array('title' => __('Validate links', $p), 'default' => false, 'group' => 'activation'),
|
171 |
+
'group_links' => array('title' => __('Group image links (for displaying as a slideshow)', $p), 'default' => true, 'group' => 'grouping'),
|
172 |
+
'group_post' => array('title' => __('Group image links by Post (e.g. on pages with multiple posts)', $p), 'default' => true, 'group' => 'grouping'),
|
173 |
+
'group_gallery' => array('title' => __('Group gallery links separately', $p), 'default' => false, 'group' => 'grouping'),
|
174 |
+
'group_widget' => array('title' => __('Group widget links separately', $p), 'default' => false, 'group' => 'grouping'),
|
175 |
+
'theme' => array('title' => __('Theme', $p), 'default' => 'default', 'group' => 'ui', 'parent' => 'option_theme'),
|
176 |
+
'animate' => array('title' => __('Animate lightbox resizing', $p), 'default' => true, 'group' => 'ui'),
|
177 |
+
'autostart' => array('title' => __('Automatically Start Slideshow', $p), 'default' => true, 'group' => 'ui'),
|
178 |
+
'duration' => array('title' => __('Slide Duration (Seconds)', $p), 'default' => '6', 'attr' => array('size' => 3, 'maxlength' => 3), 'group' => 'ui'),
|
179 |
+
'loop' => array('title' => __('Loop through images', $p), 'default' => true, 'group' => 'ui'),
|
180 |
+
'overlay_opacity' => array('title' => __('Overlay Opacity (0 - 1)', $p), 'default' => '0.8', 'attr' => array('size' => 3, 'maxlength' => 3), 'group' => 'ui'),
|
181 |
+
'enabled_caption' => array('title' => __('Enable caption', $p), 'default' => true, 'group' => 'ui'),
|
182 |
+
'caption_src' => array('title' => __('Use image URI as caption when link title not set', $p), 'default' => true, 'group' => 'ui'),
|
183 |
+
'enabled_desc' => array('title' => __('Enable description', $p), 'default' => true, 'group' => 'ui'),
|
184 |
+
'txt_closeLink' => array('title' => __('Close link (for accessibility only, image used for button)', $p), 'default' => 'close', 'group' => 'labels'),
|
185 |
+
'txt_loadingMsg' => array('title' => __('Loading indicator', $p), 'default' => 'loading', 'group' => 'labels'),
|
186 |
+
'txt_nextLink' => array('title' => __('Next Image link', $p), 'default' => 'next »', 'group' => 'labels'),
|
187 |
+
'txt_prevLink' => array('title' => __('Previous Image link', $p), 'default' => '« prev', 'group' => 'labels'),
|
188 |
+
'txt_startSlideshow' => array('title' => __('Start Slideshow link', $p), 'default' => 'start slideshow', 'group' => 'labels'),
|
189 |
+
'txt_stopSlideshow' => array('title' => __('Stop Slideshow link', $p), 'default' => 'stop slideshow', 'group' => 'labels'),
|
190 |
+
'txt_numDisplayPrefix' => array('title' => __('Image number prefix (e.g. <strong>Image</strong> x of y)', $p), 'default' => 'Image', 'group' => 'labels'),
|
191 |
+
'txt_numDisplaySeparator' => array('title' => __('Image number separator (e.g. Image x <strong>of</strong> y)', $p), 'default' => 'of', 'group' => 'labels')
|
192 |
+
),
|
193 |
+
'legacy' => array (
|
194 |
+
'header_activation' => null,
|
195 |
+
'header_enabled' => null,
|
196 |
+
'header_strings' => null,
|
197 |
+
'header_ui' => null,
|
198 |
+
'enabled_single' => array('enabled_post', 'enabled_page')
|
199 |
+
)
|
200 |
+
);
|
201 |
+
$opt_theme =& $options_config['items']['theme'];
|
202 |
+
$opt_theme['default'] = $this->theme_default = $this->add_prefix($this->theme_default);
|
203 |
+
$opt_theme['options'] = $this->m('get_theme_options');
|
204 |
+
|
205 |
+
$this->options = new SLB_Options($options_config);
|
206 |
}
|
207 |
|
208 |
function register_hooks() {
|
209 |
+
parent::register_hooks();
|
210 |
+
|
211 |
/* Admin */
|
212 |
+
|
213 |
//Init lightbox admin
|
214 |
add_action('admin_init', $this->m('admin_settings'));
|
215 |
//Enqueue header files (CSS/JS)
|
217 |
//Reset Settings
|
218 |
add_action('admin_action_' . $this->add_prefix('reset'), $this->m('admin_reset'));
|
219 |
add_action('admin_notices', $this->m('admin_notices'));
|
220 |
+
//Plugin listing
|
221 |
+
add_filter('plugin_action_links_' . $this->util->get_plugin_base_name(), $this->m('admin_plugin_action_links'), 10, 4);
|
222 |
+
add_action('in_plugin_update_message-' . $this->util->get_plugin_base_name(), $this->m('admin_plugin_update_message'), 10, 2);
|
223 |
+
add_filter('site_transient_update_plugins', $this->m('admin_plugin_update_transient'));
|
224 |
|
225 |
/* Client-side */
|
226 |
+
|
227 |
+
//Init lightbox
|
228 |
+
$priority = 99;
|
229 |
add_action('wp_enqueue_scripts', $this->m('enqueue_files'));
|
230 |
add_action('wp_head', $this->m('client_init'));
|
231 |
+
add_action('wp_footer', $this->m('client_footer'), $priority);
|
232 |
+
//Link activation
|
233 |
+
add_filter('the_content', $this->m('activate_links'), $priority);
|
234 |
+
//Gallery wrapping
|
235 |
+
add_filter('the_content', $this->m('gallery_wrap'), 1);
|
236 |
+
add_filter('the_content', $this->m('gallery_unwrap'), $priority + 1);
|
237 |
+
|
238 |
+
|
239 |
+
/* Themes */
|
240 |
+
$this->util->add_action('init_themes', $this->m('init_default_themes'));
|
241 |
+
|
242 |
+
/* Widgets */
|
243 |
+
add_filter('sidebars_widgets', $this->m('sidebars_widgets'));
|
244 |
}
|
245 |
+
|
246 |
+
/* Methods */
|
247 |
|
248 |
+
/*-** Request **-*/
|
249 |
+
|
250 |
/**
|
251 |
+
* Output current context to client-side
|
252 |
+
* @uses `wp_head` action as hook
|
253 |
+
* @uses `admin_head` action as hook
|
254 |
+
* @return void
|
255 |
*/
|
256 |
+
function set_client_context() {
|
257 |
+
if ( !$this->is_enabled() )
|
258 |
+
return false;
|
259 |
+
$ctx = new stdClass();
|
260 |
+
$ctx->context = $this->util->get_context();
|
261 |
+
echo $this->util->build_script_element($this->util->extend_client_object($ctx), 'context');
|
|
|
|
|
262 |
}
|
263 |
+
|
264 |
/*-** Helpers **-*/
|
265 |
|
266 |
/**
|
268 |
* @return bool TRUE if lightbox is currently enabled, FALSE otherwise
|
269 |
*/
|
270 |
function is_enabled($check_request = true) {
|
271 |
+
$ret = ( $this->options->get_bool('enabled') && !is_feed() && !is_admin() ) ? true : false;
|
272 |
if ( $ret && $check_request ) {
|
273 |
$opt = '';
|
274 |
//Determine option to check
|
275 |
if ( is_home() )
|
276 |
$opt = 'home';
|
277 |
+
elseif ( is_singular() ) {
|
278 |
+
$opt = ( is_page() ) ? 'page' : 'post';
|
279 |
+
}
|
280 |
elseif ( is_archive() || is_search() )
|
281 |
$opt = 'archive';
|
282 |
//Check option
|
283 |
+
if ( !empty($opt) && ( $opt = 'enabled_' . $opt ) && $this->options->has($opt) ) {
|
284 |
+
$ret = $this->options->get_bool($opt);
|
285 |
}
|
286 |
}
|
287 |
return $ret;
|
288 |
}
|
289 |
|
290 |
+
/*-** Widgets **-*/
|
291 |
+
|
292 |
/**
|
293 |
+
* Reroute widget display handlers to internal method
|
294 |
+
* @param array $sidebar_widgets List of sidebars & their widgets
|
295 |
+
* @uses WP Hook `sidebars_widgets` to intercept widget list
|
296 |
+
* @global $wp_registered_widgets to reroute display callback
|
297 |
+
* @return array Sidebars and widgets (unmodified)
|
298 |
+
*/
|
299 |
+
function sidebars_widgets($sidebars_widgets) {
|
300 |
+
global $wp_registered_widgets;
|
301 |
+
static $widgets_processed = false;
|
302 |
+
if ( is_admin() || empty($wp_registered_widgets) || $widgets_processed || !is_object($this->options) || !$this->is_enabled() || !$this->options->get_bool('enabled_widget') )
|
303 |
+
return $sidebars_widgets;
|
304 |
+
$widgets_processed = true;
|
305 |
+
//Fetch active widgets from all sidebars
|
306 |
+
foreach ( $sidebars_widgets as $sb => $ws ) {
|
307 |
+
//Skip inactive widgets and empty sidebars
|
308 |
+
if ( 'wp_inactive_widgets' == $sb || empty($ws) || !is_array($ws) )
|
309 |
+
continue;
|
310 |
+
foreach ( $ws as $w ) {
|
311 |
+
if ( isset($wp_registered_widgets[$w]) && isset($wp_registered_widgets[$w][$this->widget_callback]) ) {
|
312 |
+
$wref =& $wp_registered_widgets[$w];
|
313 |
+
//Backup original callback
|
314 |
+
$wref[$this->widget_callback_orig] = $wref[$this->widget_callback];
|
315 |
+
//Reroute callback
|
316 |
+
$wref[$this->widget_callback] = $this->m('widget_callback');
|
317 |
+
unset($wref);
|
318 |
+
}
|
319 |
+
}
|
320 |
+
}
|
321 |
+
|
322 |
+
return $sidebars_widgets;
|
323 |
}
|
324 |
|
325 |
/**
|
326 |
+
* Widget display handler
|
327 |
+
* Original widget display handler is called inside of an output buffer & links in output are processed before sending to browser
|
328 |
+
* @param array $args Widget instance properties
|
329 |
+
* @param int (optional) $widget_args Additional widget args (usually the widget's instance number)
|
330 |
+
* @see WP_Widget::display_callback() for more information
|
331 |
+
* @see sidebars_widgets() for callback modification
|
332 |
+
* @global $wp_registered_widgets
|
333 |
+
* @uses widget_process_links() to Process links in widget content
|
334 |
+
* @return void
|
335 |
*/
|
336 |
+
function widget_callback($args, $widget_args = 1) {
|
337 |
+
global $wp_registered_widgets;
|
338 |
+
$wid = ( isset($args['widget_id']) ) ? $args['widget_id'] : false;
|
339 |
+
//Stop processing if widget data invalid
|
340 |
+
if ( !$wid || !isset($wp_registered_widgets[$wid]) || !($w =& $wp_registered_widgets[$wid]) || !isset($w['id']) || $wid != $w['id'] )
|
341 |
+
return false;
|
342 |
+
//Get original callback
|
343 |
+
if ( !isset($w[$this->widget_callback_orig]) || !($cb = $w[$this->widget_callback_orig]) || !is_callable($cb) )
|
344 |
+
return false;
|
345 |
+
$params = func_get_args();
|
346 |
+
$this->widget_processing = true;
|
347 |
+
//Start output buffer
|
348 |
+
ob_start();
|
349 |
+
//Call original callback
|
350 |
+
call_user_func_array($cb, $params);
|
351 |
+
//Flush output buffer
|
352 |
+
echo $this->widget_process_links(ob_get_clean(), $wid);
|
353 |
+
$this->widget_processing = false;
|
354 |
}
|
355 |
|
356 |
/**
|
357 |
+
* Process links in widget content
|
358 |
+
* @param string $content Widget content
|
359 |
+
* @return string Processed widget content
|
360 |
+
* @uses process_links() to process links
|
361 |
*/
|
362 |
+
function widget_process_links($content, $id) {
|
363 |
+
$id = ( $this->options->get_bool('group_widget') ) ? "widget_$id" : null;
|
364 |
+
return $this->process_links($content, $id);
|
365 |
+
}
|
366 |
+
|
367 |
+
/*-** Theme **-*/
|
368 |
+
|
369 |
+
/**
|
370 |
+
* Retrieve themes
|
371 |
+
* @uses do_action() Calls 'slb_init_themes' hook to allow plugins to register themes
|
372 |
+
* @uses $themes to return registered themes
|
373 |
+
* @return array Retrieved themes
|
374 |
+
*/
|
375 |
+
function get_themes() {
|
376 |
+
static $fetched = false;
|
377 |
+
if ( !$fetched ) {
|
378 |
+
$this->themes = array();
|
379 |
+
$this->util->do_action('init_themes');
|
380 |
+
$fetched = true;
|
381 |
+
}
|
382 |
+
return $this->themes;
|
383 |
}
|
384 |
|
385 |
/**
|
386 |
+
* Retrieve theme
|
387 |
+
* @param string $name Name of theme to retrieve
|
388 |
+
* @uses theme_exists() to check for existence of theme
|
389 |
+
* @return array Theme data
|
390 |
*/
|
391 |
+
function get_theme($name = '') {
|
392 |
+
$name = strval($name);
|
393 |
+
//Default: Get current theme if no theme specified
|
394 |
+
if ( empty($name) ) {
|
395 |
+
$name = $this->options->get_value('theme');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
396 |
}
|
397 |
+
if ( !$this->theme_exists($name) )
|
398 |
+
$name = $this->theme_default;
|
399 |
+
return $this->themes[$name];
|
400 |
+
}
|
401 |
+
|
402 |
+
/**
|
403 |
+
* Retrieve specific of theme data
|
404 |
+
* @uses get_theme() to retrieve theme data
|
405 |
+
* @param string $name Theme name
|
406 |
+
* @param string $field Theme field to retrieve
|
407 |
+
* @return mixed Field data
|
408 |
+
*/
|
409 |
+
function get_theme_data($name = '', $field) {
|
410 |
+
$theme = $this->get_theme($name);
|
411 |
+
return ( isset($theme[$field]) ) ? $theme[$field] : '';
|
412 |
+
}
|
413 |
+
|
414 |
+
/**
|
415 |
+
* Retrieve theme stylesheet URL
|
416 |
+
* @param string $name Theme name
|
417 |
+
* @uses get_theme_data() to retrieve theme data
|
418 |
+
* @return string Stylesheet URL
|
419 |
+
*/
|
420 |
+
function get_theme_style($name = '') {
|
421 |
+
return $this->get_theme_data($name, 'stylesheet_url');
|
422 |
+
}
|
423 |
+
|
424 |
+
/**
|
425 |
+
* Retrieve theme layout
|
426 |
+
* @uses get_theme_data() to retrieve theme data
|
427 |
+
* @param string $name Theme name
|
428 |
+
* @param bool $filter (optional) Filter layout based on user preferences
|
429 |
+
* @return string Theme layout HTML
|
430 |
+
*/
|
431 |
+
function get_theme_layout($name = '', $filter = true) {
|
432 |
+
$l = $this->get_theme_data($name, 'layout');
|
433 |
+
//Filter
|
434 |
+
if ( !$this->options->get_bool('enabled_caption') )
|
435 |
+
$l = str_replace($this->get_theme_placeholder('dataCaption'), '', $l);
|
436 |
+
if ( !$this->options->get_bool('enabled_desc') )
|
437 |
+
$l = str_replace($this->get_theme_placeholder('dataDescription'), '', $l);
|
438 |
+
return $l;
|
439 |
+
}
|
440 |
+
|
441 |
+
/**
|
442 |
+
* Check whether a theme exists
|
443 |
+
* @param string $name Theme to look for
|
444 |
+
* @uses get_themes() to intialize themes if not already performed
|
445 |
+
* @return bool TRUE if theme exists, FALSE otherwise
|
446 |
+
*/
|
447 |
+
function theme_exists($name) {
|
448 |
+
$this->get_themes();
|
449 |
+
return ( isset($this->themes[trim(strval($name))]) );
|
450 |
+
}
|
451 |
+
|
452 |
+
/**
|
453 |
+
* Register lightbox theme
|
454 |
+
* @param string $name Unique theme name
|
455 |
+
* @param string $title Display name for theme
|
456 |
+
* @param string $stylesheet_url URL to stylesheet
|
457 |
+
* @param string $layout Layout HTML
|
458 |
+
* @uses $themes to store the registered theme
|
459 |
+
*/
|
460 |
+
function register_theme($name, $title, $stylesheet_url, $layout) {
|
461 |
+
if ( !is_array($this->themes) ) {
|
462 |
+
$this->themes = array();
|
463 |
+
}
|
464 |
+
|
465 |
+
//Validate parameters
|
466 |
+
$name = trim(strval($name));
|
467 |
+
$title = trim(strval($title));
|
468 |
+
$stylesheet_url = trim(strval($stylesheet_url));
|
469 |
+
$layout = $this->format_theme_layout($layout);
|
470 |
+
|
471 |
+
$defaults = array(
|
472 |
+
'name' => '',
|
473 |
+
'title' => '',
|
474 |
+
'stylesheet_url' => '',
|
475 |
+
'layout' => ''
|
476 |
+
);
|
477 |
+
|
478 |
+
//Add theme to array
|
479 |
+
$this->themes[$name] = wp_parse_args(compact(array_keys($defaults), $defaults));
|
480 |
+
}
|
481 |
+
|
482 |
+
/**
|
483 |
+
* Build theme placeholder
|
484 |
+
* @param string $name Placeholder name
|
485 |
+
* @return string Placeholder
|
486 |
+
*/
|
487 |
+
function get_theme_placeholder($name) {
|
488 |
+
return '{' . $name . '}';
|
489 |
+
}
|
490 |
+
|
491 |
+
/**
|
492 |
+
* Formats layout for usage in JS
|
493 |
+
* @param string $layout Layout to format
|
494 |
+
* @return string Formatted layout
|
495 |
+
*/
|
496 |
+
function format_theme_layout($layout = '') {
|
497 |
+
//Remove line breaks
|
498 |
+
$layout = str_replace(array("\r\n", "\n", "\r", "\t"), '', $layout);
|
499 |
+
|
500 |
+
//Escape quotes
|
501 |
+
$layout = str_replace("'", "\'", $layout);
|
502 |
+
|
503 |
+
//Return
|
504 |
+
return "'" . $layout . "'";
|
505 |
+
}
|
506 |
+
|
507 |
+
/**
|
508 |
+
* Add default themes
|
509 |
+
* @uses register_theme() to register the theme(s)
|
510 |
+
*/
|
511 |
+
function init_default_themes() {
|
512 |
+
$name = $this->theme_default;
|
513 |
+
$title = 'Default';
|
514 |
+
$stylesheet_url = $this->util->get_file_url('css/lightbox.css');
|
515 |
+
$layout = file_get_contents($this->util->normalize_path($this->util->get_path_base(), 'templates', 'default', 'layout.html'));
|
516 |
+
$this->register_theme($name, $title, $stylesheet_url, $layout);
|
517 |
+
//Testing: Additional themes
|
518 |
+
$this->register_theme('black', 'Black', $this->util->get_file_url('css/lb_black.css'), $layout);
|
519 |
}
|
520 |
|
521 |
/*-** Frontend **-*/
|
522 |
|
523 |
+
/**
|
524 |
+
* Builds wrapper for grouping
|
525 |
+
* @return object Wrapper properties
|
526 |
+
* > open
|
527 |
+
* > close
|
528 |
+
*/
|
529 |
+
function group_get_wrapper() {
|
530 |
+
static $wrapper = null;
|
531 |
+
if ( is_null($wrapper) ) {
|
532 |
+
$start = '<';
|
533 |
+
$end = '>';
|
534 |
+
$terminate = '/';
|
535 |
+
$val = $this->add_prefix('group');
|
536 |
+
//Build properties
|
537 |
+
$wrapper = array(
|
538 |
+
'open' => $start . $val . $end,
|
539 |
+
'close' => $start . $terminate . $val . $end
|
540 |
+
);
|
541 |
+
//Convert to object
|
542 |
+
$wrapper = (object) $wrapper;
|
543 |
+
}
|
544 |
+
return $wrapper;
|
545 |
+
}
|
546 |
+
|
547 |
+
/**
|
548 |
+
* Wraps galleries for grouping
|
549 |
+
* @uses `the_content` Filter hook
|
550 |
+
* @uses gallery_wrap_callback to Wrap shortcodes for grouping
|
551 |
+
* @param string $content Post content
|
552 |
+
* @return string Modified post content
|
553 |
+
*/
|
554 |
+
function gallery_wrap($content) {
|
555 |
+
if ( !$this->is_enabled() )
|
556 |
+
return $content;
|
557 |
+
//Stop processing if option not enabled
|
558 |
+
if ( !$this->options->get_bool('group_gallery') )
|
559 |
+
return $content;
|
560 |
+
global $shortcode_tags;
|
561 |
+
//Save default shortcode handlers to temp variable
|
562 |
+
$sc_temp = $shortcode_tags;
|
563 |
+
//Find gallery shortcodes
|
564 |
+
$shortcodes = array('gallery', 'nggallery');
|
565 |
+
$m = $this->m('gallery_wrap_callback');
|
566 |
+
$shortcode_tags = array();
|
567 |
+
foreach ( $shortcodes as $tag ) {
|
568 |
+
$shortcode_tags[$tag] = $m;
|
569 |
+
}
|
570 |
+
//Wrap gallery shortcodes
|
571 |
+
$content = do_shortcode($content);
|
572 |
+
//Restore default shortcode handlers
|
573 |
+
$shortcode_tags = $sc_temp;
|
574 |
+
|
575 |
+
return $content;
|
576 |
+
}
|
577 |
+
|
578 |
+
/**
|
579 |
+
* Wraps gallery shortcodes for later processing
|
580 |
+
* @param array $attr Shortcode attributes
|
581 |
+
* @param string $content Content enclosed in shortcode
|
582 |
+
* @param string $tag Shortcode name
|
583 |
+
* @return string Wrapped gallery shortcode
|
584 |
+
*/
|
585 |
+
function gallery_wrap_callback($attr, $content = null, $tag) {
|
586 |
+
//Rebuild shortcode
|
587 |
+
$sc = '[' . $tag . ' ' . $this->util->build_attribute_string($attr) . ']';
|
588 |
+
if ( !empty($content) )
|
589 |
+
$sc .= $content . '[/' . $tag .']';
|
590 |
+
//Wrap shortcode
|
591 |
+
$w = $this->group_get_wrapper();
|
592 |
+
$sc = $w->open . $sc . $w->close;
|
593 |
+
return $sc;
|
594 |
+
}
|
595 |
+
|
596 |
+
/**
|
597 |
+
* Removes wrapping from galleries
|
598 |
+
* @uses `the_content` filter hook
|
599 |
+
* @param $content Post content
|
600 |
+
* @return string Modified post content
|
601 |
+
*/
|
602 |
+
function gallery_unwrap($content) {
|
603 |
+
if ( !$this->is_enabled() )
|
604 |
+
return $content;
|
605 |
+
//Stop processing if option not enabled
|
606 |
+
if ( !$this->options->get_bool('group_gallery') )
|
607 |
+
return $content;
|
608 |
+
$w = $this->group_get_wrapper();
|
609 |
+
if ( strpos($content, $w->open) !== false ) {
|
610 |
+
$content = str_replace($w->open, '', $content);
|
611 |
+
$content = str_replace($w->close, '', $content);
|
612 |
+
}
|
613 |
+
return $content;
|
614 |
+
}
|
615 |
+
|
616 |
+
/**
|
617 |
+
* Retrieve supported media types
|
618 |
+
* @return object Supported media types
|
619 |
+
*/
|
620 |
+
function get_media_types() {
|
621 |
+
static $t = null;
|
622 |
+
if ( is_null($t) )
|
623 |
+
$t = (object) $this->media_types;
|
624 |
+
return $t;
|
625 |
+
}
|
626 |
+
|
627 |
+
/**
|
628 |
+
* Check if media type is supported
|
629 |
+
* @param string $type Media type
|
630 |
+
* @return bool If media type is supported
|
631 |
+
*/
|
632 |
+
function is_media_type_supported($type) {
|
633 |
+
$ret = false;
|
634 |
+
$t = $this->get_media_types();
|
635 |
+
foreach ( $t as $n => $v ) {
|
636 |
+
if ( $type == $v ) {
|
637 |
+
$ret = true;
|
638 |
+
break;
|
639 |
+
}
|
640 |
+
}
|
641 |
+
return $ret;
|
642 |
+
}
|
643 |
+
|
644 |
/**
|
645 |
* Scans post content for image links and activates them
|
646 |
*
|
647 |
* Lightbox will not be activated for feeds
|
648 |
* @param $content
|
649 |
+
* @return string Post content
|
650 |
*/
|
651 |
+
function activate_links($content) {
|
652 |
+
//Activate links only if enabled
|
653 |
+
if ( !$this->is_enabled() ) {
|
654 |
+
return $content;
|
655 |
+
}
|
656 |
+
|
657 |
+
$groups = array();
|
658 |
+
$w = $this->group_get_wrapper();
|
659 |
+
$g_ph_f = '[%s]';
|
660 |
+
|
661 |
+
//Strip groups
|
662 |
+
if ( $this->options->get_bool('group_gallery') ) {
|
663 |
+
$groups = array();
|
664 |
+
static $g_idx = 1;
|
665 |
+
$g_end_idx = 0;
|
666 |
+
//Iterate through galleries
|
667 |
+
while ( ($g_start_idx = strpos($content, $w->open, $g_end_idx)) && $g_start_idx !== false
|
668 |
+
&& ($g_end_idx = strpos($content, $w->close, $g_start_idx)) && $g_end_idx != false ) {
|
669 |
+
$g_start_idx += strlen($w->open);
|
670 |
+
//Extract gallery content & save for processing
|
671 |
+
$g_len = $g_end_idx - $g_start_idx;
|
672 |
+
$groups[$g_idx] = substr($content, $g_start_idx, $g_len);
|
673 |
+
//Replace content with placeholder
|
674 |
+
$g_ph = sprintf($g_ph_f, $g_idx);
|
675 |
+
$content = substr_replace($content, $g_ph, $g_start_idx, $g_len);
|
676 |
+
//Increment gallery count
|
677 |
+
$g_idx++;
|
678 |
+
//Update end index
|
679 |
+
$g_end_idx = $g_start_idx + strlen($w->open);
|
680 |
+
}
|
681 |
+
}
|
682 |
+
|
683 |
+
//General link processing
|
684 |
+
$content = $this->process_links($content);
|
685 |
+
|
686 |
+
//Reintegrate Groups
|
687 |
+
foreach ( $groups as $group => $g_content ) {
|
688 |
+
$g_ph = $w->open . sprintf($g_ph_f, $group) . $w->close;
|
689 |
+
//Skip group if placeholder does not exist in content
|
690 |
+
if ( strpos($content, $g_ph) === false ) {
|
691 |
+
continue;
|
692 |
+
}
|
693 |
+
//Replace placeholder with processed content
|
694 |
+
$content = str_replace($g_ph, $w->open . $this->process_links($g_content, 'gallery_' . $group) . $w->close, $content);
|
695 |
+
}
|
696 |
+
return $content;
|
697 |
+
}
|
698 |
+
|
699 |
+
/**
|
700 |
+
* Retrieve HTML links in content
|
701 |
+
* @param string $content Content to get links from
|
702 |
+
* @param bool (optional) $unique Remove duplicates from returned links (Default: FALSE)
|
703 |
+
* @return array Links in content
|
704 |
+
*/
|
705 |
+
function get_links($content, $unique = false) {
|
706 |
+
$rgx = "/\<a[^\>]+href=.*?\>/i";
|
707 |
+
$links = array();
|
708 |
+
preg_match_all($rgx, $content, $links);
|
709 |
+
$links = $links[0];
|
710 |
+
if ( $unique )
|
711 |
+
$links = array_unique($links);
|
712 |
+
return $links;
|
713 |
+
}
|
714 |
+
|
715 |
+
/**
|
716 |
+
* Process links in content
|
717 |
+
* @global obj $wpdb DB instance
|
718 |
+
* @global obj $post Current post
|
719 |
+
* @param string $content Text containing links
|
720 |
+
* @param string (optional) $group Group to add links to (Default: none)
|
721 |
+
* @return string Content with processed links
|
722 |
+
*/
|
723 |
+
function process_links($content, $group = null) {
|
724 |
+
//Validate content before processing
|
725 |
+
if ( !is_string($content) || empty($content) )
|
726 |
+
return $content;
|
727 |
+
$links = $this->get_links($content, true);
|
728 |
+
//Process links
|
729 |
+
if ( count($links) > 0 ) {
|
730 |
+
global $wpdb;
|
731 |
+
global $post;
|
732 |
+
$types = $this->get_media_types();
|
733 |
+
$img_types = array('jpg', 'jpeg', 'gif', 'png');
|
734 |
+
$protocol = array('http://', 'https://');
|
735 |
+
$domain = str_replace($protocol, '', strtolower(get_bloginfo('url')));
|
736 |
+
|
737 |
+
//Format Group
|
738 |
+
$group_base = ( is_scalar($group) ) ? trim(strval($group)) : '';
|
739 |
+
if ( !$this->options->get_bool('group_links') ) {
|
740 |
+
$group_base = null;
|
741 |
+
}
|
742 |
+
|
743 |
+
//Iterate through links & add lightbox if necessary
|
744 |
+
foreach ( $links as $link ) {
|
745 |
+
//Init vars
|
746 |
+
$pid = 0;
|
747 |
+
$link_new = $link;
|
748 |
+
$internal = false;
|
749 |
+
$group = $group_base;
|
750 |
+
|
751 |
+
//Parse link attributes
|
752 |
+
$attr = $this->util->parse_attribute_string($link_new, array('rel' => '', 'href' => ''));
|
753 |
+
$h =& $attr['href'];
|
754 |
+
$r =& $attr['rel'];
|
755 |
+
$attrs_all = $this->get_attributes($r, false);
|
756 |
+
$attrs = $this->get_attributes($attrs_all);
|
757 |
+
|
758 |
+
//Stop processing invalid, disabled, or legacy links
|
759 |
+
if ( empty($h)
|
760 |
+
|| 0 === strpos($h, '#')
|
761 |
+
|| $this->has_attribute($attrs, $this->make_attribute_disabled())
|
762 |
+
|| $this->has_attribute($attrs_all, $this->attr_legacy, false)
|
763 |
+
)
|
764 |
+
continue;
|
765 |
+
|
766 |
+
//Check if item links to internal media (attachment)
|
767 |
+
$hdom = str_replace($protocol, '', strtolower($h));
|
768 |
+
if ( strpos($hdom, $domain) === 0 ) {
|
769 |
+
//Save URL for further processing
|
770 |
+
$internal = true;
|
771 |
+
}
|
772 |
+
|
773 |
+
//Determine link type
|
774 |
+
$type = false;
|
775 |
+
|
776 |
+
//Check if link has already been processed
|
777 |
+
if ( $internal && $this->media_item_cached($h) ) {
|
778 |
+
$i = $this->get_cached_media_item($h);
|
779 |
+
$type = $i['type'];
|
780 |
+
}
|
781 |
+
|
782 |
+
elseif ( $this->util->has_file_extension($h, $img_types) ) {
|
783 |
+
//Direct Image file
|
784 |
+
$type = $types->img;
|
785 |
+
}
|
786 |
+
|
787 |
+
elseif ( $internal && is_local_attachment($h) && ( $pid = url_to_postid($h) ) && wp_attachment_is_image($pid) ) {
|
788 |
+
//Attachment URI
|
789 |
+
$type = $types->att;
|
790 |
+
}
|
791 |
+
|
792 |
+
//Stop processing if link type not valid
|
793 |
+
if ( !$type || ( $type == $types->att && !$this->options->get_bool('activate_attachments') ) )
|
794 |
+
continue;
|
795 |
+
|
796 |
+
//Set group (if necessary)
|
797 |
+
if ( $this->options->get_bool('group_links') ) {
|
798 |
+
//Normalize group
|
799 |
+
if ( !is_string($group) )
|
800 |
+
$group = '';
|
801 |
+
//Get preset group attribute
|
802 |
+
$g_name = $this->make_attribute_name('group');
|
803 |
+
$g = ( $this->has_attribute($attrs, $g_name) ) ? $this->get_attribute($attrs, $g_name) : $this->get_attribute($attrs, $this->attr);
|
804 |
+
|
805 |
+
if ( is_string($g) && ($g = trim($g)) && strlen($g) )
|
806 |
+
$group = $g;
|
807 |
+
//Group links by post?
|
808 |
+
if ( !$this->widget_processing && $this->options->get_bool('group_post') ) {
|
809 |
+
$group = ( strlen($group) ) ? '_' . $group : '';
|
810 |
+
$group = $post->ID . $group;
|
811 |
}
|
812 |
|
813 |
+
if ( empty($group) ) {
|
814 |
+
$group = $this->get_prefix();
|
|
|
|
|
|
|
|
|
815 |
}
|
816 |
+
|
817 |
+
//Set group attribute
|
818 |
+
$attrs = $this->set_attribute($attrs, $g_name, $group);
|
819 |
}
|
820 |
+
|
821 |
+
//Activate link
|
822 |
+
$attrs = $this->set_attribute($attrs, $this->attr);
|
823 |
+
|
824 |
+
//Process internal links
|
825 |
+
if ( $internal ) {
|
826 |
+
//Mark as internal
|
827 |
+
$attrs = $this->set_attribute($attrs, 'internal');
|
828 |
+
//Add to media items array
|
829 |
+
$this->cache_media_item($h, $type, $pid);
|
830 |
+
}
|
831 |
+
|
832 |
+
//Convert rel attribute to string
|
833 |
+
$r = $this->build_attributes(array_merge($attrs_all, $attrs));
|
834 |
+
|
835 |
+
//Update link in content
|
836 |
+
$link_new = '<a ' . $this->util->build_attribute_string($attr) . '>';
|
837 |
+
$content = str_replace($link, $link_new, $content);
|
838 |
+
unset($h, $r);
|
839 |
}
|
840 |
}
|
841 |
+
return $content;
|
842 |
+
}
|
843 |
+
|
844 |
+
/**
|
845 |
+
* Generates link attributes from array
|
846 |
+
* @param array $attrs Link Attributes
|
847 |
+
* @return string Attribute string
|
848 |
+
*/
|
849 |
+
function build_attributes($attrs) {
|
850 |
+
$a = array();
|
851 |
+
//Validate attributes
|
852 |
+
$attrs = $this->get_attributes($attrs, false);
|
853 |
+
//Iterate through attributes and build output array
|
854 |
+
foreach ( $attrs as $key => $val ) {
|
855 |
+
//Standard attributes
|
856 |
+
if ( is_bool($val) && $val ) {
|
857 |
+
$a[] = $key;
|
858 |
+
}
|
859 |
+
//Attributes with values
|
860 |
+
elseif ( is_string($val) ) {
|
861 |
+
$a[] = $key . '[' . $val . ']';
|
862 |
+
}
|
863 |
+
}
|
864 |
+
return implode(' ', $a);
|
865 |
+
}
|
866 |
+
|
867 |
+
/**
|
868 |
+
* Build attribute name
|
869 |
+
* Makes sure name is only prefixed once
|
870 |
+
* @return string Formatted attribute name
|
871 |
+
*/
|
872 |
+
function make_attribute_name($name = '') {
|
873 |
+
$sep = '_';
|
874 |
+
$name = trim($name);
|
875 |
+
//Generate valid name
|
876 |
+
if ( $name != $this->attr ) {
|
877 |
+
//Use default name
|
878 |
+
if ( empty($name) )
|
879 |
+
$name = $this->attr;
|
880 |
+
//Add prefix if not yet set
|
881 |
+
elseif ( strpos($name, $this->attr . $sep) !== 0 )
|
882 |
+
$name = $this->attr . $sep . $name;
|
883 |
+
}
|
884 |
+
return $name;
|
885 |
+
}
|
886 |
+
|
887 |
+
/**
|
888 |
+
* Create attribute to disable lightbox for current link
|
889 |
+
* @return string Disabled lightbox attribute
|
890 |
+
*/
|
891 |
+
function make_attribute_disabled() {
|
892 |
+
static $ret = null;
|
893 |
+
if ( is_null($ret) ) {
|
894 |
+
$ret = $this->make_attribute_name('off');
|
895 |
+
}
|
896 |
+
return $ret;
|
897 |
+
}
|
898 |
+
|
899 |
+
/**
|
900 |
+
* Set attribute to array
|
901 |
+
* Attribute is added to array if it does not exist
|
902 |
+
* @param array $attrs Current attribute array
|
903 |
+
* @param string $name Name of attribute to add
|
904 |
+
* @param string (optional) $value Attribute value
|
905 |
+
* @return array Updated attribute array
|
906 |
+
*/
|
907 |
+
function set_attribute($attrs, $name, $value = null) {
|
908 |
+
//Validate attribute array
|
909 |
+
$attrs = $this->get_attributes($attrs, false);
|
910 |
+
//Build attribute name
|
911 |
+
$name = $this->make_attribute_name($name);
|
912 |
+
//Set attribute
|
913 |
+
$attrs[$name] = true;
|
914 |
+
if ( !empty($value) && is_string($value) )
|
915 |
+
$attrs[$name] = $value;
|
916 |
+
return $attrs;
|
917 |
+
}
|
918 |
+
|
919 |
+
/**
|
920 |
+
* Convert attribute string into array
|
921 |
+
* @param string $attr_string Attribute string
|
922 |
+
* @param bool (optional) $internal Whether only internal attributes should be evaluated (Default: TRUE)
|
923 |
+
* @return array Attributes as associative array
|
924 |
+
*/
|
925 |
+
function get_attributes($attr_string, $internal = true) {
|
926 |
+
$ret = array();
|
927 |
+
//Protect bracketed values prior to parsing attributes string
|
928 |
+
if ( is_string($attr_string) ) {
|
929 |
+
$attr_string = trim($attr_string);
|
930 |
+
$attr_vals = array();
|
931 |
+
$attr_keys = array();
|
932 |
+
$offset = 0;
|
933 |
+
while ( ($bo = strpos($attr_string,'[', $offset)) && $bo !== false
|
934 |
+
&& ($bc = strpos($attr_string,']', $bo)) && $bc !== false
|
935 |
+
) {
|
936 |
+
//Push all preceding attributes into array
|
937 |
+
$attr_temp = explode(' ', substr($attr_string, $offset, $bo));
|
938 |
+
//Get attribute name
|
939 |
+
$name = array_pop($attr_temp);
|
940 |
+
$attr_keys = array_merge($attr_keys, $attr_temp);
|
941 |
+
//Add to values array
|
942 |
+
$attr_vals[$name] = substr($attr_string, $bo+1, $bc-$bo-1);
|
943 |
+
//Update offset
|
944 |
+
$offset = $bc+1;
|
945 |
+
}
|
946 |
+
//Parse remaining attributes
|
947 |
+
$attr_keys = array_merge($attr_keys, array_filter(explode(' ', substr($attr_string, $offset))));
|
948 |
+
//Set default values for all keys
|
949 |
+
$attr_keys = array_fill_keys($attr_keys, TRUE);
|
950 |
+
//Merge attributes with values
|
951 |
+
$ret = array_merge($attr_keys, $attr_vals);
|
952 |
+
} elseif ( is_array($attr_string) )
|
953 |
+
$ret = $attr_string;
|
954 |
+
|
955 |
+
//Filter non-internal attributes if necessary
|
956 |
+
if ( $internal && is_array($ret) ) {
|
957 |
+
foreach ( array_keys($ret) as $attr ) {
|
958 |
+
if ( $attr == $this->attr)
|
959 |
+
continue;
|
960 |
+
if ( strpos($attr, $this->attr . '_') !== 0 )
|
961 |
+
unset($ret[$attr]);
|
962 |
+
}
|
963 |
+
}
|
964 |
+
|
965 |
+
return $ret;
|
966 |
+
}
|
967 |
+
|
968 |
+
/**
|
969 |
+
* Retrieve attribute value
|
970 |
+
* @param string|array $attrs Attributes to retrieve attribute value from
|
971 |
+
* @param string $attr Attribute name to retrieve
|
972 |
+
* @param bool (optional) $internal Whether only internal attributes should be evaluated (Default: TRUE)
|
973 |
+
* @return string|bool Attribute value (Default: FALSE)
|
974 |
+
*/
|
975 |
+
function get_attribute($attrs, $attr, $internal = true) {
|
976 |
+
$ret = false;
|
977 |
+
$attrs = $this->get_attributes($attrs, $internal);
|
978 |
+
//Validate attribute name for internal attributes
|
979 |
+
if ( $internal )
|
980 |
+
$attr = $this->make_attribute_name($attr);
|
981 |
+
if ( isset($attrs[$attr]) ) {
|
982 |
+
$ret = $attrs[$attr];
|
983 |
+
}
|
984 |
+
return $ret;
|
985 |
+
}
|
986 |
+
|
987 |
+
/**
|
988 |
+
* Checks if attribute exists
|
989 |
+
* @param string|array $attrs Attributes to retrieve attribute value from
|
990 |
+
* @param string $attr Attribute name to retrieve
|
991 |
+
* @param bool (optional) $internal Whether only internal attributes should be evaluated (Default: TRUE)
|
992 |
+
* @return bool Whether or not attribute exists
|
993 |
+
*/
|
994 |
+
function has_attribute($attrs, $attr, $internal = true) {
|
995 |
+
return ( $this->get_attribute($attrs, $attr, $internal) !== false ) ? true : false;
|
996 |
+
}
|
997 |
+
|
998 |
+
/**
|
999 |
+
* Cache media properties for later processing
|
1000 |
+
* @param string $uri URI for internal media (e.g. direct uri, attachment uri, etc.)
|
1001 |
+
* @param string $type Media type (image, attachment, etc.)
|
1002 |
+
* @param int (optional) $id ID of media item (if available) (Default: NULL)
|
1003 |
+
*/
|
1004 |
+
function cache_media_item($uri, $type, $id = null) {
|
1005 |
+
//Cache media item
|
1006 |
+
if ( $this->is_media_type_supported($type) && !$this->media_item_cached($uri) ) {
|
1007 |
+
//Set properties
|
1008 |
+
$i = array('type' => null, 'id' => null, 'source' => null);
|
1009 |
+
//Type
|
1010 |
+
$i['type'] = $type;
|
1011 |
+
$t = $this->get_media_types();
|
1012 |
+
//Source
|
1013 |
+
if ( $type == $t->img )
|
1014 |
+
$i['source'] = $uri;
|
1015 |
+
//ID
|
1016 |
+
if ( is_numeric($id) )
|
1017 |
+
$i['id'] = absint($id);
|
1018 |
+
|
1019 |
+
$this->media_items_raw[$uri] = $i;
|
1020 |
+
}
|
1021 |
+
}
|
1022 |
+
|
1023 |
+
/**
|
1024 |
+
* Checks if media item has already been cached
|
1025 |
+
* @param string $uri URI of media item
|
1026 |
+
* @return boolean Whether media item has been cached
|
1027 |
+
*/
|
1028 |
+
function media_item_cached($uri) {
|
1029 |
+
$ret = false;
|
1030 |
+
if ( !$uri || !is_string($uri) )
|
1031 |
+
return $ret;
|
1032 |
+
return ( isset($this->media_items_raw[$uri]) ) ? true : false;
|
1033 |
+
}
|
1034 |
+
|
1035 |
+
/**
|
1036 |
+
* Retrieve cached media item
|
1037 |
+
* @param string $uri Media item URI
|
1038 |
+
* @return array|null Media item properties (NULL if not set)
|
1039 |
+
*/
|
1040 |
+
function get_cached_media_item($uri) {
|
1041 |
+
$ret = null;
|
1042 |
+
if ( $this->media_item_cached($uri) ) {
|
1043 |
+
$ret = $this->media_items_raw[$uri];
|
1044 |
+
}
|
1045 |
+
return $ret;
|
1046 |
+
}
|
1047 |
+
|
1048 |
+
/**
|
1049 |
+
* Retrieve cached media items
|
1050 |
+
* @return array Cached media items
|
1051 |
+
*/
|
1052 |
+
function &get_cached_media_items() {
|
1053 |
+
return $this->media_items_raw;
|
1054 |
+
}
|
1055 |
+
|
1056 |
+
/**
|
1057 |
+
* Check if media items have been cached
|
1058 |
+
* @return boolean
|
1059 |
+
*/
|
1060 |
+
function has_cached_media_items() {
|
1061 |
+
return ( !empty($this->media_items_raw) ) ? true : false;
|
1062 |
}
|
1063 |
|
1064 |
/**
|
1067 |
function enqueue_files() {
|
1068 |
if ( ! $this->is_enabled() )
|
1069 |
return;
|
1070 |
+
|
1071 |
+
//$lib = 'js/' . ( ( ( defined('WP_DEBUG') && WP_DEBUG ) || isset($_REQUEST[$this->add_prefix('debug')]) ) ? 'dev/lib.dev.js' : 'lib.js' );
|
1072 |
+
$lib = 'js/lib.js';
|
1073 |
+
wp_enqueue_script($this->add_prefix('lib'), $this->util->get_file_url($lib), array('jquery'), $this->util->get_plugin_version());
|
1074 |
+
wp_enqueue_style($this->add_prefix('style'), $this->get_theme_style(), array(), $this->util->get_plugin_version());
|
1075 |
}
|
1076 |
|
1077 |
/**
|
1081 |
function client_init() {
|
1082 |
if ( ! $this->is_enabled() )
|
1083 |
return;
|
1084 |
+
echo '<!-- SLB -->' . PHP_EOL;
|
1085 |
$options = array();
|
1086 |
$out = array();
|
|
|
|
|
1087 |
$js_code = array();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1088 |
//Get options
|
1089 |
$options = array(
|
1090 |
+
'validateLinks' => $this->options->get_bool('validate_links'),
|
1091 |
+
'autoPlay' => $this->options->get_bool('autostart'),
|
1092 |
+
'slideTime' => $this->options->get_value('duration'),
|
1093 |
+
'loop' => $this->options->get_bool('loop'),
|
1094 |
+
'overlayOpacity' => $this->options->get_value('overlay_opacity'),
|
1095 |
+
'animate' => $this->options->get_bool('animate'),
|
1096 |
+
'captionEnabled' => $this->options->get_bool('enabled_caption'),
|
1097 |
+
'captionSrc' => $this->options->get_bool('caption_src'),
|
1098 |
+
'descEnabled' => $this->options->get_bool('enabled_desc'),
|
1099 |
+
'trigger' => array($this->get_prefix()),
|
1100 |
+
'prefix' => $this->get_prefix()
|
1101 |
);
|
1102 |
+
//Backwards compatibility
|
1103 |
+
if ( $this->options->get_bool('enabled_compat'))
|
1104 |
+
$options['trigger'][] = $this->attr_legacy;
|
1105 |
+
|
|
|
|
|
|
|
|
|
1106 |
//Load UI Strings
|
1107 |
+
if ( ($strings = $this->build_labels()) && !empty($strings) )
|
1108 |
+
$options['labels'] = $strings;
|
1109 |
+
//Load Layout
|
1110 |
+
$options['layout'] = $this->get_theme_layout();
|
1111 |
+
|
1112 |
+
//Build client output
|
1113 |
+
echo $this->util->build_script_element($this->util->call_client_method('init', $options), 'init', true, true);
|
1114 |
+
echo PHP_EOL . '<!-- /SLB -->' . PHP_EOL;
|
1115 |
+
}
|
1116 |
+
|
1117 |
+
/**
|
1118 |
+
* Output code in footer
|
1119 |
+
* > Media attachment URLs
|
1120 |
+
* @uses `_wp_attached_file` to match attachment ID to URI
|
1121 |
+
* @uses `_wp_attachment_metadata` to retrieve attachment metadata
|
1122 |
+
*/
|
1123 |
+
function client_footer() {
|
1124 |
+
echo '<!-- X -->';
|
1125 |
+
//Stop if not enabled or if there are no media items to process
|
1126 |
+
if ( !$this->is_enabled() || !$this->has_cached_media_items() )
|
1127 |
+
return;
|
1128 |
+
echo '<!-- SLB -->' . PHP_EOL;
|
1129 |
+
|
1130 |
+
global $wpdb;
|
1131 |
+
|
1132 |
+
$this->media_attachments = array();
|
1133 |
+
$props = array('id', 'type', 'desc', 'title', 'source');
|
1134 |
+
$props = (object) array_combine($props, $props);
|
1135 |
+
|
1136 |
+
//Separate media into buckets by type
|
1137 |
+
$m_bucket = array();
|
1138 |
+
$type = $id = null;
|
1139 |
+
|
1140 |
+
$m_items =& $this->get_cached_media_items();
|
1141 |
+
foreach ( $m_items as $uri => $p ) {
|
1142 |
+
$type = $p[$props->type];
|
1143 |
+
if ( empty($type) )
|
1144 |
+
continue;
|
1145 |
+
if ( !isset($m_bucket[$type]) )
|
1146 |
+
$m_bucket[$type] = array();
|
1147 |
+
//Add to bucket for type (by reference)
|
1148 |
+
$m_bucket[$type][$uri] =& $m_items[$uri];
|
1149 |
+
}
|
1150 |
+
|
1151 |
+
//Process links by type
|
1152 |
+
$t = $this->get_media_types();
|
1153 |
+
|
1154 |
+
//Direct image links
|
1155 |
+
if ( isset($m_bucket[$t->img]) ) {
|
1156 |
+
$b =& $m_bucket[$t->img];
|
1157 |
+
$uris_base = array();
|
1158 |
+
$uri_prefix = wp_upload_dir();
|
1159 |
+
$uri_prefix = $this->util->normalize_path($uri_prefix['baseurl'], true);
|
1160 |
+
foreach ( array_keys($b) as $uri ) {
|
1161 |
+
$uris_base[str_replace($uri_prefix, '', $uri)] = $uri;
|
1162 |
+
}
|
1163 |
+
|
1164 |
+
//Retrieve attachment IDs
|
1165 |
+
$uris_flat = "('" . implode("','", array_keys($uris_base)) . "')";
|
1166 |
+
$q = $wpdb->prepare("SELECT post_id, meta_value FROM $wpdb->postmeta WHERE `meta_key` = %s AND LOWER(`meta_value`) IN $uris_flat LIMIT %d", '_wp_attached_file', count($b));
|
1167 |
+
$pids_temp = $wpdb->get_results($q);
|
1168 |
+
//Match IDs with URIs
|
1169 |
+
if ( $pids_temp ) {
|
1170 |
+
foreach ( $pids_temp as $pd ) {
|
1171 |
+
$f = $pd->meta_value;
|
1172 |
+
if ( is_numeric($pd->post_id) && isset($uris_base[$f]) ) {
|
1173 |
+
$b[$uris_base[$f]][$props->id] = absint($pd->post_id);
|
1174 |
+
}
|
1175 |
+
}
|
1176 |
+
}
|
1177 |
+
//Destroy worker vars
|
1178 |
+
unset($b, $uri, $uris_base, $uris_flat, $q, $pids_temp, $pd);
|
1179 |
+
}
|
1180 |
+
|
1181 |
+
//Image attachments
|
1182 |
+
if ( isset($m_bucket[$t->att]) ) {
|
1183 |
+
$b =& $m_bucket[$t->att];
|
1184 |
+
|
1185 |
+
//Attachment source URI
|
1186 |
+
foreach ( $b as $uri => $p ) {
|
1187 |
+
$s = wp_get_attachment_url($p[$props->id]);
|
1188 |
+
if ( !!$s )
|
1189 |
+
$b[$uri][$props->source] = $s;
|
1190 |
+
}
|
1191 |
+
//Destroy worker vars
|
1192 |
+
unset($b, $uri, $p);
|
1193 |
+
}
|
1194 |
+
|
1195 |
+
//Retrieve attachment IDs
|
1196 |
+
$ids = array();
|
1197 |
+
foreach ( $m_items as $uri => $p ) {
|
1198 |
+
//Add post ID to query
|
1199 |
+
if ( isset($p[$props->id]) ) {
|
1200 |
+
$id = $p[$props->id];
|
1201 |
+
//Create array for ID (support multiple URIs per ID)
|
1202 |
+
if ( !isset($ids[$id]) ) {
|
1203 |
+
$ids[$id] = array();
|
1204 |
+
}
|
1205 |
+
//Add URI to ID
|
1206 |
+
$ids[$id][] = $uri;
|
1207 |
+
}
|
1208 |
+
}
|
1209 |
+
|
1210 |
+
//Retrieve attachment properties
|
1211 |
+
if ( !empty($ids) ) {
|
1212 |
+
$ids_flat = array_keys($ids);
|
1213 |
+
$atts = get_posts(array('post_type' => 'attachment', 'include' => $ids_flat));
|
1214 |
+
$ids_flat = "('" . implode("','", $ids_flat) . "')";
|
1215 |
+
$atts_meta = $wpdb->get_results($wpdb->prepare("SELECT `post_id`,`meta_value` FROM $wpdb->postmeta WHERE `post_id` IN $ids_flat AND `meta_key` = %s LIMIT %d", '_wp_attachment_metadata', count($ids)));
|
1216 |
+
//Rebuild metadata array
|
1217 |
+
if ( $atts_meta ) {
|
1218 |
+
$meta = array();
|
1219 |
+
foreach ( $atts_meta as $att_meta ) {
|
1220 |
+
$meta[$att_meta->post_id] = $att_meta->meta_value;
|
1221 |
+
}
|
1222 |
+
$atts_meta = $meta;
|
1223 |
+
unset($meta);
|
1224 |
+
} else {
|
1225 |
+
$atts_meta = array();
|
1226 |
+
}
|
1227 |
+
|
1228 |
+
//Process attachments
|
1229 |
+
if ( $atts ) {
|
1230 |
+
foreach ( $atts as $att ) {
|
1231 |
+
if ( !isset($ids[$att->ID]) )
|
1232 |
+
continue;
|
1233 |
+
//Add attachment
|
1234 |
+
//Set properties
|
1235 |
+
$m = array(
|
1236 |
+
$props->title => $att->post_title,
|
1237 |
+
$props->desc => $att->post_content,
|
1238 |
+
);
|
1239 |
+
//Add metadata
|
1240 |
+
if ( isset($atts_meta[$att->ID]) && ($a = unserialize($atts_meta[$att->ID])) && is_array($a) ) {
|
1241 |
+
//Move original size into `sizes` array
|
1242 |
+
foreach ( array('file', 'width', 'height') as $d ) {
|
1243 |
+
if ( !isset($a[$d]) )
|
1244 |
+
continue;
|
1245 |
+
$a['sizes']['original'][$d] = $a[$d];
|
1246 |
+
unset($a[$d]);
|
1247 |
+
}
|
1248 |
+
|
1249 |
+
//Strip extraneous metadata
|
1250 |
+
foreach ( array('hwstring_small') as $d ) {
|
1251 |
+
if ( isset($a[$d]) )
|
1252 |
+
unset($a[$d]);
|
1253 |
+
}
|
1254 |
+
|
1255 |
+
$m = array_merge($a, $m);
|
1256 |
+
unset($a, $d);
|
1257 |
+
}
|
1258 |
+
|
1259 |
+
//Save to object
|
1260 |
+
foreach ( $ids[$att->ID] as $uri ) {
|
1261 |
+
if ( isset($m_items[$uri]) )
|
1262 |
+
$m = array_merge($m_items[$uri], $m);
|
1263 |
+
$this->media_attachments[$uri] = $m;
|
1264 |
+
}
|
1265 |
+
}
|
1266 |
+
}
|
1267 |
+
}
|
1268 |
+
|
1269 |
+
//Media attachments
|
1270 |
+
if ( !empty($this->media_attachments) ) {
|
1271 |
+
$obj = 'media';
|
1272 |
+
$atch_out = $this->util->extend_client_object($obj, $this->media_attachments);
|
1273 |
+
echo $this->util->build_script_element($atch_out, $obj);
|
1274 |
+
}
|
1275 |
+
|
1276 |
+
echo PHP_EOL . '<!-- /SLB -->' . PHP_EOL;
|
1277 |
}
|
1278 |
|
1279 |
/**
|
1280 |
* Build JS object of UI strings when initializing lightbox
|
1281 |
+
* @return array UI strings
|
1282 |
*/
|
1283 |
+
function build_labels() {
|
1284 |
+
$ret = array();
|
1285 |
+
//Get all UI options
|
1286 |
$prefix = 'txt_';
|
1287 |
+
$opt_strings = array_filter(array_keys($this->options->get_items()), create_function('$opt', 'return ( strpos($opt, "' . $prefix . '") === 0 );'));
|
1288 |
+
if ( count($opt_strings) ) {
|
1289 |
+
//Build array of UI options
|
1290 |
foreach ( $opt_strings as $key ) {
|
1291 |
$name = substr($key, strlen($prefix));
|
1292 |
+
$ret[$name] = $this->options->get_value($key);
|
1293 |
}
|
|
|
1294 |
}
|
1295 |
return $ret;
|
1296 |
}
|
1299 |
|
1300 |
/**
|
1301 |
* Adds custom links below plugin on plugin listing page
|
1302 |
+
* @uses `plugin_action_links_$plugin-name` Filter hook
|
1303 |
* @param $actions
|
1304 |
* @param $plugin_file
|
1305 |
* @param $plugin_data
|
1308 |
function admin_plugin_action_links($actions, $plugin_file, $plugin_data, $context) {
|
1309 |
//Add link to settings (only if active)
|
1310 |
if ( is_plugin_active($this->util->get_plugin_base_name()) ) {
|
1311 |
+
$settings = __('Settings', $this->get_prefix());
|
1312 |
+
$reset = __('Reset', $this->get_prefix());
|
1313 |
+
$reset_confirm = "'" . __('Are you sure you want to reset your settings?', $this->get_prefix()) . "'";
|
1314 |
$action = $this->add_prefix('reset');
|
1315 |
$reset_link = wp_nonce_url(add_query_arg('action', $action, remove_query_arg(array($this->add_prefix('action'), 'action'), $_SERVER['REQUEST_URI'])), $action);
|
1316 |
array_unshift($actions, '<a class="delete" href="options-media.php#' . $this->admin_get_settings_section() . '" title="' . $settings . '">' . $settings . '</a>');
|
1319 |
return $actions;
|
1320 |
}
|
1321 |
|
1322 |
+
/**
|
1323 |
+
* Adds additional message for plugin updates
|
1324 |
+
* @uses `in_plugin_update_message-$plugin-name` Action hook
|
1325 |
+
* @var array $plugin_data Current plugin data
|
1326 |
+
* @var object $r Update response data
|
1327 |
+
*/
|
1328 |
+
function admin_plugin_update_message($plugin_data, $r) {
|
1329 |
+
if ( !isset($r->new_version) )
|
1330 |
+
return false;
|
1331 |
+
if ( stripos($r->new_version, 'beta') !== false ) {
|
1332 |
+
$cls_notice = $this->add_prefix('notice');
|
1333 |
+
echo '<br />' . $this->admin_plugin_update_get_message($r);
|
1334 |
+
}
|
1335 |
+
}
|
1336 |
+
|
1337 |
+
/**
|
1338 |
+
* Modify update plugins response data if necessary
|
1339 |
+
* @uses `site_transient_update_plugins` Filter hook
|
1340 |
+
* @param obj $transient Transient data
|
1341 |
+
* @return obj Modified transient data
|
1342 |
+
*/
|
1343 |
+
function admin_plugin_update_transient($transient) {
|
1344 |
+
$n = $this->util->get_plugin_base_name();
|
1345 |
+
if ( isset($transient->response) && isset($transient->response[$n]) && is_object($transient->response[$n]) && !isset($transient->response[$n]->upgrade_notice) ) {
|
1346 |
+
$r =& $transient->response[$n];
|
1347 |
+
$r->upgrade_notice = $this->admin_plugin_update_get_message($r);
|
1348 |
+
}
|
1349 |
+
return $transient;
|
1350 |
+
}
|
1351 |
+
|
1352 |
+
/**
|
1353 |
+
* Retrieve custom update message
|
1354 |
+
* @param obj $r Response data from plugin update API
|
1355 |
+
* @return string Message (Default: empty string)
|
1356 |
+
*/
|
1357 |
+
function admin_plugin_update_get_message($r) {
|
1358 |
+
$msg = '';
|
1359 |
+
$cls_notice = $this->add_prefix('notice');
|
1360 |
+
if ( !is_object($r) || !isset($r->new_version) )
|
1361 |
+
return $msg;
|
1362 |
+
if ( stripos($r->new_version, 'beta') !== false ) {
|
1363 |
+
$msg = "<strong class=\"$cls_notice\">Notice:</strong> This update is a <strong class=\"$cls_notice\">Beta version</strong>. It is highly recommended that you test the update on a test server before updating the plugin on a production server.";
|
1364 |
+
}
|
1365 |
+
return $msg;
|
1366 |
+
}
|
1367 |
+
|
1368 |
/**
|
1369 |
* Reset plugin settings
|
1370 |
* Redirects to referring page upon completion
|
1372 |
function admin_reset() {
|
1373 |
//Validate user
|
1374 |
if ( ! current_user_can('activate_plugins') || ! check_admin_referer($this->add_prefix('reset')) )
|
1375 |
+
wp_die(__('You do not have sufficient permissions to manage plugins for this blog.', $this->get_prefix()));
|
1376 |
$action = 'reset';
|
1377 |
if ( isset($_REQUEST['action']) && $this->add_prefix($action) == $_REQUEST['action'] ) {
|
1378 |
//Reset settings
|
1379 |
+
$this->options->reset(true);
|
1380 |
$uri = remove_query_arg(array('_wpnonce', 'action'), add_query_arg(array($this->add_prefix('action') => $action), $_SERVER['REQUEST_URI']));
|
1381 |
//Redirect user
|
1382 |
wp_redirect($uri);
|
1409 |
/**
|
1410 |
* Adds settings section for Lightbox functionality
|
1411 |
* Section is added to Settings > Media Admin menu
|
1412 |
+
* @todo Move appropriate code to options class
|
1413 |
*/
|
1414 |
function admin_settings() {
|
1415 |
$page = $this->options_admin_page;
|
1422 |
$page = 'media';
|
1423 |
$section = $this->get_prefix();
|
1424 |
//Section
|
1425 |
+
add_settings_section($section, '<div id="' . $this->admin_get_settings_section() . '">' . __('Lightbox Settings', $this->util->get_plugin_textdomain()) . '</div>', $this->m('admin_section'), $page);
|
1426 |
+
//Register settings container
|
1427 |
+
register_setting($page, $this->add_prefix('options'), $this->options->m('validate'));
|
1428 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1429 |
|
1430 |
+
/**
|
1431 |
+
* Enqueues header files for admin pages
|
1432 |
+
* @todo Separate and move options CSS to options class
|
1433 |
+
*/
|
1434 |
function admin_enqueue_files() {
|
1435 |
+
//Enqueue custom CSS for options page
|
1436 |
+
if ( is_admin() && ( basename($_SERVER['SCRIPT_NAME']) == $this->options_admin_page || $this->util->is_context('admin_page_plugins')) ) {
|
1437 |
+
wp_enqueue_style($this->add_prefix('admin'), $this->util->get_file_url('css/admin.css'), array(), $this->util->get_plugin_version());
|
1438 |
}
|
1439 |
}
|
1440 |
|
1441 |
/**
|
1442 |
* Get ID of settings section on admin page
|
1443 |
* @return string ID of settings section
|
1444 |
+
* @todo Eval for moving to options class
|
1445 |
*/
|
1446 |
function admin_get_settings_section() {
|
1447 |
return $this->add_prefix('settings');
|
1450 |
/**
|
1451 |
* Placeholder function for lightbox admin settings
|
1452 |
* Required because setting init function requires a callback
|
1453 |
+
* @todo Evaluate for moving to options class
|
1454 |
*/
|
1455 |
+
function admin_section() {
|
1456 |
+
$this->options->build();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1457 |
}
|
1458 |
|
1459 |
+
/* Custom fields */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1460 |
|
1461 |
+
function get_theme_options() {
|
1462 |
+
//Get themes
|
1463 |
+
$themes = $this->get_themes();
|
1464 |
+
|
1465 |
+
//Pop out default theme
|
1466 |
+
$theme_default = $themes[$this->theme_default];
|
1467 |
+
unset($themes[$this->theme_default]);
|
1468 |
+
|
1469 |
+
//Sort themes by title
|
1470 |
+
uasort($themes, create_function('$a,$b', 'return strcmp($a[\'title\'], $b[\'title\']);'));
|
1471 |
+
|
1472 |
+
//Insert default theme at top of array
|
1473 |
+
$themes = array($this->theme_default => $theme_default) + $themes;
|
1474 |
+
|
1475 |
+
//Build options
|
1476 |
+
foreach ( $themes as $name => $props ) {
|
1477 |
+
$themes[$name] = $props['title'];
|
1478 |
+
}
|
1479 |
+
return $themes;
|
1480 |
}
|
1481 |
}
|
1482 |
|
1483 |
+
?>
|
readme.txt
CHANGED
@@ -1,40 +1,50 @@
|
|
1 |
-
===
|
2 |
-
Contributors:
|
3 |
-
|
4 |
-
|
5 |
-
|
|
|
|
|
6 |
Stable tag: trunk
|
7 |
|
8 |
-
A simple and customizable Lightbox for Wordpress
|
9 |
|
10 |
== Description ==
|
11 |
|
12 |
-
Simple Lightbox
|
|
|
|
|
13 |
|
14 |
-
|
|
|
|
|
15 |
Options for customizing the lightbox behavior are located in the **Settings > Media** admin menu in the **Lightbox Settings** section (or just click the **Settings** link below the plugin's name when viewing the list of installed plugins)
|
16 |
|
17 |
-
*
|
18 |
-
*
|
|
|
|
|
|
|
|
|
|
|
19 |
* Enable Lightbox depending on Page Type (Home, Pages, Archive, etc.)
|
20 |
-
*
|
21 |
-
* Group
|
22 |
-
*
|
23 |
-
*
|
24 |
-
*
|
25 |
-
* Loop through images (Default: Enabled)
|
26 |
-
* Overlay Opacity (0 - 1) (Default: 0.8)
|
27 |
|
28 |
#### Usage
|
29 |
-
|
30 |
-
|
|
|
|
|
|
|
31 |
|
32 |
== Installation ==
|
33 |
|
34 |
-
1.
|
35 |
-
1.
|
36 |
-
1. Verify that your theme uses the `wp_head()` template tag (this is where the necessary files will be added to your theme output)
|
37 |
-
1. Let plugin automatically add lightbox functionality for links to images or manually add `rel="lightbox"` to any image links that you want to be displayed in a lightbox
|
38 |
|
39 |
== Upgrade Notice ==
|
40 |
|
@@ -42,7 +52,7 @@ No upgrade notices
|
|
42 |
|
43 |
== Frequently Asked Questions ==
|
44 |
|
45 |
-
|
46 |
|
47 |
== Screenshots ==
|
48 |
|
@@ -50,13 +60,138 @@ Send your questions to wp@archetyped.com
|
|
50 |
2. Customized UI Text
|
51 |
|
52 |
== Changelog ==
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
53 |
= 1.3.1 =
|
54 |
-
*
|
|
|
55 |
= 1.3 =
|
56 |
-
*
|
57 |
-
*
|
58 |
-
*
|
59 |
-
*
|
60 |
|
61 |
= 1.2.1 =
|
62 |
* Fixed: Image title given higher precedence than Image alt (more compatible w/WP workflow)
|
@@ -72,5 +207,6 @@ Send your questions to wp@archetyped.com
|
|
72 |
* Optimized: Options menu field building
|
73 |
* Optimized: Loading of default values for plugin options
|
74 |
* Optimized: General code optimizations
|
|
|
75 |
= 1.0 =
|
76 |
* Initial release
|
1 |
+
=== Simple Lightbox ===
|
2 |
+
Contributors: Archetyped
|
3 |
+
Donate link: http://mycharitywater.org/archetyped-2012-fall
|
4 |
+
Tags: lightbox, gallery, photography, images, theme, template, style
|
5 |
+
Requires at least: 3.3.2
|
6 |
+
Tested up to: 3.4
|
7 |
+
License: GPLv2 or later
|
8 |
Stable tag: trunk
|
9 |
|
10 |
+
A simple, themeable, and highly customizable Lightbox for Wordpress
|
11 |
|
12 |
== Description ==
|
13 |
|
14 |
+
#### Simple Lightbox 2.0 Beta!
|
15 |
+
The next generation of Simple Lightbox is here and ready for brave beta testers.
|
16 |
+
[Sign up for SLB 2.0 beta now](http://archetyped.com/lab/simple-lightbox-2-0-beta/) while there's still space available!
|
17 |
|
18 |
+
Simple Lightbox is a very simple and highly customizable lightbox that is easy to add to your Wordpress website. It also [supports skins](http://archetyped.com/lab/slb-registering-themes/), so it can be fully integrated with your site's theme.
|
19 |
+
|
20 |
+
#### Features
|
21 |
Options for customizing the lightbox behavior are located in the **Settings > Media** admin menu in the **Lightbox Settings** section (or just click the **Settings** link below the plugin's name when viewing the list of installed plugins)
|
22 |
|
23 |
+
* **Supports links in Widgets (New!)**
|
24 |
+
* **Supports Image Attachment links**
|
25 |
+
* **Display image metadata (caption, description, etc.) in lightbox**
|
26 |
+
* Automatically activate links (no manual coding required)
|
27 |
+
* Keyboard Navigation
|
28 |
+
* Link Validation (optional)
|
29 |
+
* User-customizable skin (template) support
|
30 |
* Enable Lightbox depending on Page Type (Home, Pages, Archive, etc.)
|
31 |
+
* Group image links (play as a slideshow)
|
32 |
+
* Group image links by Post (e.g. separate slideshow for each post on home page)
|
33 |
+
* UI/Animation Customization
|
34 |
+
* Slideshow Customization
|
35 |
+
* Backwards-compatibility with legacy lightbox links
|
|
|
|
|
36 |
|
37 |
#### Usage
|
38 |
+
1. Insert links to images/image attachments into your posts/pages
|
39 |
+
|
40 |
+
**That's it! The image will be displayed in a lightbox automatically.**
|
41 |
+
|
42 |
+
* For more usage tips, go to [Simple Lightbox's official page](http://archetyped.com/tools/simple-lightbox/)
|
43 |
|
44 |
== Installation ==
|
45 |
|
46 |
+
1. Install and activate SLB
|
47 |
+
1. Verify that your site's theme uses the `wp_head()`, `wp_footer()`, & `the_content()` template tags (standard in any professional theme)
|
|
|
|
|
48 |
|
49 |
== Upgrade Notice ==
|
50 |
|
52 |
|
53 |
== Frequently Asked Questions ==
|
54 |
|
55 |
+
Post your questions and comments on [Simple Lightbox's official page](http://archetyped.com/tools/simple-lightbox/)
|
56 |
|
57 |
== Screenshots ==
|
58 |
|
60 |
2. Customized UI Text
|
61 |
|
62 |
== Changelog ==
|
63 |
+
|
64 |
+
= 1.6.3.1 =
|
65 |
+
* Fix: Backward compatibility restored (Backward Genius)
|
66 |
+
|
67 |
+
= 1.6.3 =
|
68 |
+
* Optimize: Improved lightbox overlay display
|
69 |
+
|
70 |
+
= 1.6.2 =
|
71 |
+
* Update: Rebuild JS code
|
72 |
+
* Optimize: Improved compatibility with PHP 5+
|
73 |
+
* Optimize: Improved utility code
|
74 |
+
* Fix: Some elements can overlap lightbox
|
75 |
+
* Fix: Slideshow not automatically starting (Laurence of Autoplay)
|
76 |
+
|
77 |
+
= 1.6.1 =
|
78 |
+
* Optimize: Handle repeated initializations of lightbox on client-side
|
79 |
+
* Fix: Localization not properly loaded (Mustafa Lingo)
|
80 |
+
|
81 |
+
= 1.6 =
|
82 |
+
* Add: Widget support
|
83 |
+
* Add: WordPress 3.3 support
|
84 |
+
* Add: Localization support
|
85 |
+
* Add: Option to group gallery links separately (supports WordPress & NextGen galleries)
|
86 |
+
* Add: Upgrade notice
|
87 |
+
* Optimize: WP 3.3 compatibility
|
88 |
+
* Optimize: Improved compatibility with URI case-sensitivity
|
89 |
+
* Optimize: Activation processing
|
90 |
+
* Optimize: Image grouping
|
91 |
+
* Optimize: Image metadata loading performance
|
92 |
+
* Optimize: File loading
|
93 |
+
* Optimize: Improved safeguards against interference by bugs in other plugins
|
94 |
+
* Optimize: Link processing performance
|
95 |
+
* Optimize: Lightbox styling isolated from site styles
|
96 |
+
* Optimize: Improved link processing performance
|
97 |
+
* Optimize: Improved image metadata support
|
98 |
+
* Optimize: Improved support for HTTP/HTTPS requests
|
99 |
+
* Fix: SLB is not defined in JS (Jezz Hands)
|
100 |
+
* Fix: Boolean case-sensitivity (78 Truths)
|
101 |
+
* Fix: YouTube embed using iFrame overlaps lightbox (Elena in Hiding)
|
102 |
+
* Fix: Issue when scanning links without valid URLs (McCloskey Iteration)
|
103 |
+
* Fix: Image activation is case-sensitive (Sensitive Tanya)
|
104 |
+
* Fix: Visible lightbox overlay edges when image larger than browser window (Chibi Overlay)
|
105 |
+
* Fix: Options availability for some users
|
106 |
+
* Fix: Inconsistent loading of image metadata
|
107 |
+
* Fix: Links not fully processed when group is set manually
|
108 |
+
|
109 |
+
= 1.5.6 =
|
110 |
+
* Add: Display image description in lightbox (with HTML support)
|
111 |
+
* Add: Support for W3 Total Cache plugin
|
112 |
+
* Add: Initial support for NextGEN galleries
|
113 |
+
* Update: **Important:** [System Requirements](http://wordpress.org/about/requirements/) aligned with WP 3.2.1
|
114 |
+
* Optimize: Improved support for small images in default template
|
115 |
+
* Optimize: Support for non-English text in user options
|
116 |
+
* Optimize: Improved IE compatibility
|
117 |
+
* Optimize: Improved data handling
|
118 |
+
* Optimize: Skin loading performance
|
119 |
+
* Optimize: Skin CSS Cleanup
|
120 |
+
* Optimize: Caption support for galleries
|
121 |
+
* Optimize: Options code cleanup (Juga Sweep)
|
122 |
+
* Fix: User-defined UI text not used (Ivan gets Even (cooler))
|
123 |
+
* Fix: Options reset after update (KRazy Donna)
|
124 |
+
|
125 |
+
= 1.5.5.1 =
|
126 |
+
* Fix: Disabled links not being disabled (Disabling Sascha)
|
127 |
+
|
128 |
+
= 1.5.5 =
|
129 |
+
* Add: Distinct link activation (will not affect other lightboxes)
|
130 |
+
* Add: Backwards compatibility with legacy lightbox links (optional)
|
131 |
+
* Add: Support for WordPress 3.2
|
132 |
+
* Add: Support for links added after page load (e.g. via AJAX, etc.)
|
133 |
+
* Add: Admin option to enable/disable attachment links
|
134 |
+
* Add: Support for image attachment links
|
135 |
+
* Update: Options management overhaul
|
136 |
+
* Update: Additional WordPress 3.2 support (Gallery)
|
137 |
+
* Update: Cache-management for enqueued files
|
138 |
+
* Update: Improved UI consistency
|
139 |
+
* Update: Improved compatibility for older versions of PHP
|
140 |
+
* Update: Internal optimizations
|
141 |
+
* Update: Improved URL handling
|
142 |
+
* Fix: Improved options migration from old versions (Hutchison Migration)
|
143 |
+
* Fix: XHTML Validation (Hajo Validation)
|
144 |
+
|
145 |
+
= 1.5.4 =
|
146 |
+
* Add: Optional Link validation
|
147 |
+
* Add: Keyboard Navigation
|
148 |
+
* Add: Option to enable/disable image caption
|
149 |
+
* Add: `rel` attribute supported again
|
150 |
+
* Add: Use `slb_off` in link's `rel` attribute to disable automatic activation for link
|
151 |
+
* Fix: HTTPS compatibility (Jürgen Protocol)
|
152 |
+
* Fix: Enabling SLB on Pages issue
|
153 |
+
* Fix: Zmanu is_single
|
154 |
+
* Fix: Image order is sometimes incorrect
|
155 |
+
* Optimize: Filter double clicks
|
156 |
+
* Optimize: Separate options to enable/disable SLB on Posts and Pages
|
157 |
+
* Optimize: Better grouping support
|
158 |
+
|
159 |
+
= 1.5.3 =
|
160 |
+
* Fix: Caption may not display under certain circumstances (Caption Erin)
|
161 |
+
* Fix: Images not grouped when "separate by post" option is activated (Logical Ross)
|
162 |
+
* Update: Lightbox will not be activated for links that already have `rel` attribute set
|
163 |
+
|
164 |
+
= 1.5.2 =
|
165 |
+
* Fix: Slideshow loops out of control (Mirage of Wallentin)
|
166 |
+
* Fix: Lightbox fails when group by posts disabled (Lange Find)
|
167 |
+
* Add: Option to use the image's URI as caption when link title not set (Under UI options)
|
168 |
+
|
169 |
+
= 1.5.1 =
|
170 |
+
* Add: WP Gallery support
|
171 |
+
* Fix: Navigation hidden when only one image
|
172 |
+
* Fix: Use user-defined UI text
|
173 |
+
|
174 |
+
= 1.5 =
|
175 |
+
* Add: Theme support
|
176 |
+
* Optimize: Javascript cleanup and file size reductions
|
177 |
+
* Optimize: CSS cleanup
|
178 |
+
|
179 |
+
= 1.4 =
|
180 |
+
* Update: Integrated with jQuery
|
181 |
+
* Optimize: Javascript filesize 9x smaller
|
182 |
+
* Add: Close lightbox by clicking to left/right outside of image (an oft-requested feature)
|
183 |
+
|
184 |
+
= 1.3.2 =
|
185 |
+
* Add: Option to enable/disable lightbox resizing animation (thanks Maria!)
|
186 |
+
|
187 |
= 1.3.1 =
|
188 |
+
* Update: Utilities code (internal)
|
189 |
+
|
190 |
= 1.3 =
|
191 |
+
* Add: Customizable UI label text (close, next, and prev button images can be replaced in `images` directory)
|
192 |
+
* Add: Group image links by Post (separate slideshow for each post)
|
193 |
+
* Add: Reset settings link on plugin listings page
|
194 |
+
* Optimize: Organized settings page
|
195 |
|
196 |
= 1.2.1 =
|
197 |
* Fixed: Image title given higher precedence than Image alt (more compatible w/WP workflow)
|
207 |
* Optimized: Options menu field building
|
208 |
* Optimized: Loading of default values for plugin options
|
209 |
* Optimized: General code optimizations
|
210 |
+
|
211 |
= 1.0 =
|
212 |
* Initial release
|
templates/default/layout.html
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div id="slb_container">
|
2 |
+
<div id="slb_content">
|
3 |
+
{slbContent}
|
4 |
+
<div id="slb_nav_hover">
|
5 |
+
{navPrev}
|
6 |
+
{navNext}
|
7 |
+
</div>
|
8 |
+
<div id="slb_loading">
|
9 |
+
{slbLoading}
|
10 |
+
</div>
|
11 |
+
</div>
|
12 |
+
</div>
|
13 |
+
<div id="slb_details">
|
14 |
+
<div id="slb_data">
|
15 |
+
<div id="slb_data_content">
|
16 |
+
{dataCaption}
|
17 |
+
<span id="slb_data_desc">
|
18 |
+
{dataDescription}
|
19 |
+
</span>
|
20 |
+
{dataNumber}
|
21 |
+
<span id="slb_nav">
|
22 |
+
{navPrev}
|
23 |
+
{navNext}
|
24 |
+
{navSlideControl}
|
25 |
+
</span>
|
26 |
+
</div>
|
27 |
+
<div id="slb_close">
|
28 |
+
{slbClose}
|
29 |
+
</div>
|
30 |
+
</div>
|
31 |
+
</div>
|