Commit e8c06b21cda3af868a7f2acbf254e7a7e72b24f5
1 parent
0fc64633
Exists in
master
Ajuste para visualizar campos read-only
Showing
19 changed files
with
2822 additions
and
30 deletions
Show diff stats
Kernel/Config/Files/NewTicketWizard.xml
@@ -23,6 +23,7 @@ | @@ -23,6 +23,7 @@ | ||
23 | <JavaScript>thirdparty/alpaca/alpaca-full.min.js</JavaScript> | 23 | <JavaScript>thirdparty/alpaca/alpaca-full.min.js</JavaScript> |
24 | <JavaScript>thirdparty/alpaca/jquery.sumoselect.js</JavaScript> | 24 | <JavaScript>thirdparty/alpaca/jquery.sumoselect.js</JavaScript> |
25 | <JavaScript>thirdparty/alpaca/datatables.js</JavaScript> | 25 | <JavaScript>thirdparty/alpaca/datatables.js</JavaScript> |
26 | + <JavaScript>thirdparty/maskedinput/jquery.maskedinput.min.js</JavaScript> | ||
26 | <JavaScript>thirdparty/jquery-validate-1.13.0/jquery.validate.js</JavaScript> | 27 | <JavaScript>thirdparty/jquery-validate-1.13.0/jquery.validate.js</JavaScript> |
27 | <CSS>alpaca/alpaca-newticketwizard.css</CSS> | 28 | <CSS>alpaca/alpaca-newticketwizard.css</CSS> |
28 | <CSS>alpaca/sumoselect.css</CSS> | 29 | <CSS>alpaca/sumoselect.css</CSS> |
@@ -43,6 +44,13 @@ | @@ -43,6 +44,13 @@ | ||
43 | <Description>Admin</Description> | 44 | <Description>Admin</Description> |
44 | <Title>Service forms</Title> | 45 | <Title>Service forms</Title> |
45 | <NavBarName>Admin</NavBarName> | 46 | <NavBarName>Admin</NavBarName> |
47 | + <Loader> | ||
48 | + <CSS>jquery.jsonview.css</CSS> | ||
49 | + <JavaScript>jquery.jsonview.js</JavaScript> | ||
50 | + <JavaScript>jquery.chili.js</JavaScript> | ||
51 | + <JavaScript>jquery.chili.recipes.javascript.js</JavaScript> | ||
52 | + <JavaScript>jquery.chili.recipes.js</JavaScript> | ||
53 | + </Loader> | ||
46 | <NavBarModule> | 54 | <NavBarModule> |
47 | <Module>Kernel::Output::HTML::NavBarModuleAdmin</Module> | 55 | <Module>Kernel::Output::HTML::NavBarModuleAdmin</Module> |
48 | <Name>Service forms</Name> | 56 | <Name>Service forms</Name> |
@@ -267,6 +275,7 @@ | @@ -267,6 +275,7 @@ | ||
267 | <JavaScript>thirdparty/alpaca/jquery.sumoselect.js</JavaScript> | 275 | <JavaScript>thirdparty/alpaca/jquery.sumoselect.js</JavaScript> |
268 | <JavaScript>thirdparty/alpaca/datatables.js</JavaScript> | 276 | <JavaScript>thirdparty/alpaca/datatables.js</JavaScript> |
269 | <JavaScript>thirdparty/jquery-validate-1.13.0/jquery.validate.js</JavaScript> | 277 | <JavaScript>thirdparty/jquery-validate-1.13.0/jquery.validate.js</JavaScript> |
278 | + <JavaScript>thirdparty/maskedinput/jquery.maskedinput.min.js</JavaScript> | ||
270 | <CSS>alpaca/alpaca-newticketwizard.css</CSS> | 279 | <CSS>alpaca/alpaca-newticketwizard.css</CSS> |
271 | <CSS>alpaca/sumoselect.css</CSS> | 280 | <CSS>alpaca/sumoselect.css</CSS> |
272 | <CSS>alpaca/alpaca-jqueryui-newticketwizard.css</CSS> | 281 | <CSS>alpaca/alpaca-jqueryui-newticketwizard.css</CSS> |
Kernel/Modules/NewTicketWizard.pm
@@ -158,6 +158,8 @@ sub Run { | @@ -158,6 +158,8 @@ sub Run { | ||
158 | } | 158 | } |
159 | elsif ( $ParamObject->GetParam( Param => "Subaction" ) eq "GetFormJSON" ) { | 159 | elsif ( $ParamObject->GetParam( Param => "Subaction" ) eq "GetFormJSON" ) { |
160 | return $Self->GetFormJSON( ServiceID => $ParamObject->GetParam( Param => "ServiceID" ) ); | 160 | return $Self->GetFormJSON( ServiceID => $ParamObject->GetParam( Param => "ServiceID" ) ); |
161 | + } elsif ( $ParamObject->GetParam( Param => "Subaction" ) eq "GetFormCustomProps" ) { | ||
162 | + return $Self->GetFormCustomProps( ServiceID => $ParamObject->GetParam( Param => "ServiceID" ) ); | ||
161 | } | 163 | } |
162 | } | 164 | } |
163 | else { | 165 | else { |
@@ -227,6 +229,31 @@ sub GetFormJSON { | @@ -227,6 +229,31 @@ sub GetFormJSON { | ||
227 | ); | 229 | ); |
228 | } | 230 | } |
229 | 231 | ||
232 | +sub GetFormCustomProps { | ||
233 | + my ( $Self, %Param ) = @_; | ||
234 | + my %serviceForm; | ||
235 | + | ||
236 | + my $ServiceFormObject = $Kernel::OM->Get("Kernel::System::ServiceForm"); | ||
237 | + my $LayoutObject = $Kernel::OM->Get("Kernel::Output::HTML::Layout"); | ||
238 | + my $ParamObject = $Kernel::OM->Get("Kernel::System::Web::Request"); | ||
239 | + | ||
240 | + my $QueueID = $ParamObject->GetParam( Param => "QueueID" ); | ||
241 | + | ||
242 | + if ( $Param{ServiceID} ) { | ||
243 | + %serviceForm = $ServiceFormObject->GetServiceFormForQueue( ServiceID => $Param{ServiceID}, QueueID => $QueueID ); | ||
244 | + if (! $serviceForm{ServiceID}) { | ||
245 | + %serviceForm = $ServiceFormObject->GetServiceForm( ServiceID => $Param{ServiceID} ); | ||
246 | + } | ||
247 | + } | ||
248 | + | ||
249 | + return $LayoutObject->Attachment( | ||
250 | + ContentType => 'text/plain; charset=' . $LayoutObject->{Charset}, | ||
251 | + Content => $serviceForm{CustomProps} || "/**/", | ||
252 | + Type => 'inline', | ||
253 | + NoCache => 1, | ||
254 | + ); | ||
255 | +} | ||
256 | + | ||
230 | sub GetForm { | 257 | sub GetForm { |
231 | my ( $Self, %Param ) = @_; | 258 | my ( $Self, %Param ) = @_; |
232 | 259 |
Kernel/Modules/NewTicketWizardPublic.pm
@@ -163,7 +163,10 @@ sub Run { | @@ -163,7 +163,10 @@ sub Run { | ||
163 | } | 163 | } |
164 | elsif ( $ParamObject->GetParam( Param => "Subaction" ) eq "GetFormJSON" ) { | 164 | elsif ( $ParamObject->GetParam( Param => "Subaction" ) eq "GetFormJSON" ) { |
165 | return $Self->GetFormJSON( ServiceID => $ParamObject->GetParam( Param => "ServiceID" ) ); | 165 | return $Self->GetFormJSON( ServiceID => $ParamObject->GetParam( Param => "ServiceID" ) ); |
166 | + } elsif ( $ParamObject->GetParam( Param => "Subaction" ) eq "GetFormCustomProps" ) { | ||
167 | + return $Self->GetFormCustomProps( ServiceID => $ParamObject->GetParam( Param => "ServiceID" ) ); | ||
166 | } | 168 | } |
169 | + | ||
167 | } | 170 | } |
168 | else { | 171 | else { |
169 | my ( $schema, $fields ) = $Self->GetForm(); | 172 | my ( $schema, $fields ) = $Self->GetForm(); |
@@ -203,6 +206,32 @@ sub Run { | @@ -203,6 +206,32 @@ sub Run { | ||
203 | } | 206 | } |
204 | } | 207 | } |
205 | 208 | ||
209 | +sub GetFormCustomProps { | ||
210 | + my ( $Self, %Param ) = @_; | ||
211 | + my %serviceForm; | ||
212 | + | ||
213 | + my $ServiceFormObject = $Kernel::OM->Get("Kernel::System::ServiceForm"); | ||
214 | + my $LayoutObject = $Kernel::OM->Get("Kernel::Output::HTML::Layout"); | ||
215 | + my $ParamObject = $Kernel::OM->Get("Kernel::System::Web::Request"); | ||
216 | + | ||
217 | + my $QueueID = $ParamObject->GetParam( Param => "QueueID" ); | ||
218 | + | ||
219 | + if ( $Param{ServiceID} ) { | ||
220 | + %serviceForm = $ServiceFormObject->GetServiceFormForQueue( ServiceID => $Param{ServiceID}, QueueID => $QueueID ); | ||
221 | + if (! $serviceForm{ServiceID}) { | ||
222 | + %serviceForm = $ServiceFormObject->GetServiceForm( ServiceID => $Param{ServiceID} ); | ||
223 | + } | ||
224 | + } | ||
225 | + | ||
226 | + return $LayoutObject->Attachment( | ||
227 | + ContentType => 'text/plain; charset=' . $LayoutObject->{Charset}, | ||
228 | + Content => $serviceForm{CustomProps} || "/**/", | ||
229 | + Type => 'inline', | ||
230 | + NoCache => 1, | ||
231 | + ); | ||
232 | +} | ||
233 | + | ||
234 | + | ||
206 | sub GetFormJSON { | 235 | sub GetFormJSON { |
207 | my ( $Self, %Param ) = @_; | 236 | my ( $Self, %Param ) = @_; |
208 | my %serviceForm; | 237 | my %serviceForm; |
Kernel/Modules/NewTicketWizardServiceForm.pm
@@ -67,6 +67,7 @@ sub Run { | @@ -67,6 +67,7 @@ sub Run { | ||
67 | $Data{Form} = $serviceForm{Form}; | 67 | $Data{Form} = $serviceForm{Form}; |
68 | $Data{Schema} = $serviceForm{Schema}; | 68 | $Data{Schema} = $serviceForm{Schema}; |
69 | $Data{FixedValues} = $serviceForm{FixedValues}; | 69 | $Data{FixedValues} = $serviceForm{FixedValues}; |
70 | + $Data{CustomProps} = $serviceForm{CustomProps}; | ||
70 | $Data{ServiceID} = $ParamObject->GetParam( Param => "ServiceID" ); | 71 | $Data{ServiceID} = $ParamObject->GetParam( Param => "ServiceID" ); |
71 | $Data{QueueID} = $ParamObject->GetParam( Param => "QueueID" ); | 72 | $Data{QueueID} = $ParamObject->GetParam( Param => "QueueID" ); |
72 | 73 | ||
@@ -94,6 +95,7 @@ sub Run { | @@ -94,6 +95,7 @@ sub Run { | ||
94 | Introduction => $ParamObject->GetParam( Param => "Introduction" ), | 95 | Introduction => $ParamObject->GetParam( Param => "Introduction" ), |
95 | Form => $ParamObject->GetParam( Param => "Form" ), | 96 | Form => $ParamObject->GetParam( Param => "Form" ), |
96 | Schema => $ParamObject->GetParam( Param => "Schema" ), | 97 | Schema => $ParamObject->GetParam( Param => "Schema" ), |
98 | + CustomProps => $ParamObject->GetParam( Param => "CustomProps" ), | ||
97 | FixedValues => $ParamObject->GetParam( Param => "FixedValues" ), | 99 | FixedValues => $ParamObject->GetParam( Param => "FixedValues" ), |
98 | ); | 100 | ); |
99 | } else { | 101 | } else { |
@@ -102,6 +104,7 @@ sub Run { | @@ -102,6 +104,7 @@ sub Run { | ||
102 | Introduction => $ParamObject->GetParam( Param => "Introduction" ), | 104 | Introduction => $ParamObject->GetParam( Param => "Introduction" ), |
103 | Form => $ParamObject->GetParam( Param => "Form" ), | 105 | Form => $ParamObject->GetParam( Param => "Form" ), |
104 | Schema => $ParamObject->GetParam( Param => "Schema" ), | 106 | Schema => $ParamObject->GetParam( Param => "Schema" ), |
107 | + CustomProps => $ParamObject->GetParam( Param => "CustomProps" ), | ||
105 | FixedValues => $ParamObject->GetParam( Param => "FixedValues" ), | 108 | FixedValues => $ParamObject->GetParam( Param => "FixedValues" ), |
106 | ); | 109 | ); |
107 | } | 110 | } |
Kernel/Output/HTML/Standard/CustomerFooterNTWUFSC.tt
@@ -7,7 +7,7 @@ | @@ -7,7 +7,7 @@ | ||
7 | # did not receive this file, see http://www.gnu.org/licenses/agpl.txt. | 7 | # did not receive this file, see http://www.gnu.org/licenses/agpl.txt. |
8 | # -- | 8 | # -- |
9 | 9 | ||
10 | -<div id="footerF" align="center" style="position: absolute; bottom: 10px; width: 100%; margin-top: 18px; margin-bottom: 8px;" class="noPrint"> | 10 | +<div id="footerF" align="center" style="bottom: 10px; width: 100%; margin-top: 18px; margin-bottom: 8px;" class="noPrint"> |
11 | 11 | ||
12 | <div style="font-size: 0px;"> | 12 | <div style="font-size: 0px;"> |
13 | <div style="height: 2px; width: 100%; background-image: url('/otrs-web/skins/Customer/default/images/queues-panel/separador.gif'); background-repeat: repeat-x; background-position: 0 50%;"></div> | 13 | <div style="height: 2px; width: 100%; background-image: url('/otrs-web/skins/Customer/default/images/queues-panel/separador.gif'); background-repeat: repeat-x; background-position: 0 50%;"></div> |
Kernel/Output/HTML/Standard/NewTicketWizardServiceFormEdit.tt
@@ -31,15 +31,21 @@ | @@ -31,15 +31,21 @@ | ||
31 | </div> | 31 | </div> |
32 | <div class="Clear"></div> | 32 | <div class="Clear"></div> |
33 | 33 | ||
34 | - <label for="Form">[% Translate("Form") | html %]: </label> | 34 | + <label for="FormUI">[% Translate("Form") | html %]: </label> |
35 | <div class="Field"> | 35 | <div class="Field"> |
36 | - <textarea name="Form" id="Form" class="W50pc " rows="20">[% Data.Form | html %]</textarea> | 36 | + |
37 | + <textarea name="Form" id="FormUI" style="width: 50%" class="W50pc " rows="20">[% Data.Form | html %]</textarea> | ||
38 | + <button type="button" onclick='mostraEsconde("FormUI"); return false;'>Exibir JSON</button> | ||
39 | + <div id="jsonFormUIDlg" style="height: 300px; overflow: auto; border-style: solid; border-width: 1px;"><div id="jsonForm"></div></div> | ||
40 | + | ||
37 | </div> | 41 | </div> |
38 | <div class="Clear"></div> | 42 | <div class="Clear"></div> |
39 | 43 | ||
40 | <label for="Schema">[% Translate("Schema") | html %]: </label> | 44 | <label for="Schema">[% Translate("Schema") | html %]: </label> |
41 | <div class="Field"> | 45 | <div class="Field"> |
42 | <textarea name="Schema" id="Schema" class="W50pc " rows="20">[% Data.Schema | html %]</textarea> | 46 | <textarea name="Schema" id="Schema" class="W50pc " rows="20">[% Data.Schema | html %]</textarea> |
47 | + <button type="button" onclick='mostraEsconde("Schema"); return false;'>Exibir JSON</button> | ||
48 | + <div id="jsonSchemaDlg" style="height: 300px; overflow: auto; border-style: solid; border-width: 1px;"><div id="jsonSchema"></div></div> | ||
43 | </div> | 49 | </div> |
44 | <div class="Clear"></div> | 50 | <div class="Clear"></div> |
45 | 51 | ||
@@ -49,6 +55,16 @@ | @@ -49,6 +55,16 @@ | ||
49 | </div> | 55 | </div> |
50 | <div class="Clear"></div> | 56 | <div class="Clear"></div> |
51 | 57 | ||
58 | + <label for="CustomProps">[% Translate("Custom Properties for basic schema. <BR/>S_xxxxx=yyyy => Schema<BR/>F_xxxxx=yyyy => Form") %]: </label> | ||
59 | + <div class="Field"> | ||
60 | + <textarea name="CustomProps" id="CustomProps" class="W50pc " rows="20">[% Data.CustomProps | html %]</textarea> | ||
61 | + <button type="button" onclick='mostraEsconde("CustomProps"); return false;'>Exibir JSON</button> | ||
62 | + <div id="jsonCustomPropsDlg" style="height: 300px; overflow: auto; border-style: solid; border-width: 1px;"> | ||
63 | + <code class="chili-lang-javascript" id='jsCode'></code> | ||
64 | + </div> | ||
65 | + </div> | ||
66 | + <div class="Clear"></div> | ||
67 | + | ||
52 | <div class="Field SpacingTop"> | 68 | <div class="Field SpacingTop"> |
53 | <button class="Primary" type="submit" value="[% Translate("Submit") | html %]">[% Translate("Submit") | html %]</button> | 69 | <button class="Primary" type="submit" value="[% Translate("Submit") | html %]">[% Translate("Submit") | html %]</button> |
54 | [% Translate("or") | html %] | 70 | [% Translate("or") | html %] |
@@ -59,3 +75,51 @@ | @@ -59,3 +75,51 @@ | ||
59 | 75 | ||
60 | </form> | 76 | </form> |
61 | </div> | 77 | </div> |
78 | + | ||
79 | + | ||
80 | +<script type="text/javascript"> | ||
81 | + function mostraEsconde(id) { | ||
82 | + idJSON = "#json" + id + "Dlg"; | ||
83 | + id = "#" + id; | ||
84 | + $(idJSON).toggle(); | ||
85 | + $(idJSON).width($(id).width()); | ||
86 | + } | ||
87 | + | ||
88 | +</script> | ||
89 | + | ||
90 | +[% WRAPPER JSOnDocumentComplete %] | ||
91 | +<script type="text/javascript"> | ||
92 | + | ||
93 | + | ||
94 | + $("#jsonFormUIDlg").toggle(); | ||
95 | + $("#jsonSchemaDlg").toggle(); | ||
96 | + $("#jsonCustomPropsDlg").toggle(); | ||
97 | + | ||
98 | + setInterval(function() { | ||
99 | + var code = $("#CustomProps").val(); | ||
100 | + $("#jsCode").html(code); | ||
101 | + $("#jsCode").chili(); | ||
102 | + }, 1000); | ||
103 | + | ||
104 | + | ||
105 | + setInterval(function() { | ||
106 | + var json = "{" + $("#Schema").val() + "}"; | ||
107 | + try { | ||
108 | + json = JSON.parse(json); | ||
109 | + $("#jsonSchema").JSONView(json); | ||
110 | + } catch(err) { | ||
111 | + $("#jsonSchema").JSONView({error: "Invalid JSON!"}); | ||
112 | + } | ||
113 | + }, 1000); | ||
114 | + | ||
115 | + setInterval(function() { | ||
116 | + var json = "{" + $("#FormUI").val() + "}"; | ||
117 | + try { | ||
118 | + json = JSON.parse(json); | ||
119 | + $("#jsonForm").JSONView(json); | ||
120 | + } catch(err) { | ||
121 | + $("#jsonForm").JSONView({error: "Invalid JSON!"}); | ||
122 | + } | ||
123 | + }, 1000); | ||
124 | +</script> | ||
125 | +[% END %] | ||
62 | \ No newline at end of file | 126 | \ No newline at end of file |
Kernel/System/ServiceForm.pm
@@ -44,7 +44,7 @@ sub GetServiceForm { | @@ -44,7 +44,7 @@ sub GetServiceForm { | ||
44 | 44 | ||
45 | # get service form from db | 45 | # get service form from db |
46 | $DBObject->Prepare( | 46 | $DBObject->Prepare( |
47 | - SQL => 'SELECT service_id, introduction, form, form_schema, fixed_values FROM service_form WHERE service_id = ? and queue_id is null', | 47 | + SQL => 'SELECT service_id, introduction, form, form_schema, fixed_values, custom_props FROM service_form WHERE service_id = ? and queue_id is null', |
48 | Bind => [ \$Param{ServiceID} ], | 48 | Bind => [ \$Param{ServiceID} ], |
49 | Limit => 1, | 49 | Limit => 1, |
50 | ); | 50 | ); |
@@ -57,6 +57,7 @@ sub GetServiceForm { | @@ -57,6 +57,7 @@ sub GetServiceForm { | ||
57 | $ServiceData{Form} = $Row[2]; | 57 | $ServiceData{Form} = $Row[2]; |
58 | $ServiceData{Schema} = $Row[3]; | 58 | $ServiceData{Schema} = $Row[3]; |
59 | $ServiceData{FixedValues} = $Row[4]; | 59 | $ServiceData{FixedValues} = $Row[4]; |
60 | + $ServiceData{CustomProps} = $Row[5]; | ||
60 | } | 61 | } |
61 | 62 | ||
62 | return %ServiceData; | 63 | return %ServiceData; |
@@ -76,7 +77,7 @@ sub GetServiceFormForQueue { | @@ -76,7 +77,7 @@ sub GetServiceFormForQueue { | ||
76 | 77 | ||
77 | # get service form from db | 78 | # get service form from db |
78 | $DBObject->Prepare( | 79 | $DBObject->Prepare( |
79 | - SQL => 'SELECT service_id, introduction, form, form_schema, fixed_values FROM service_form WHERE service_id = ? and queue_id = ? ', | 80 | + SQL => 'SELECT service_id, introduction, form, form_schema, fixed_values, custom_props FROM service_form WHERE service_id = ? and queue_id = ? ', |
80 | Bind => [ \$Param{ServiceID}, \$Param{QueueID} ], | 81 | Bind => [ \$Param{ServiceID}, \$Param{QueueID} ], |
81 | Limit => 1, | 82 | Limit => 1, |
82 | ); | 83 | ); |
@@ -89,6 +90,7 @@ sub GetServiceFormForQueue { | @@ -89,6 +90,7 @@ sub GetServiceFormForQueue { | ||
89 | $ServiceData{Form} = $Row[2]; | 90 | $ServiceData{Form} = $Row[2]; |
90 | $ServiceData{Schema} = $Row[3]; | 91 | $ServiceData{Schema} = $Row[3]; |
91 | $ServiceData{FixedValues} = $Row[4]; | 92 | $ServiceData{FixedValues} = $Row[4]; |
93 | + $ServiceData{CustomProps} = $Row[5]; | ||
92 | } | 94 | } |
93 | 95 | ||
94 | return %ServiceData; | 96 | return %ServiceData; |
@@ -119,14 +121,14 @@ sub SaveServiceForm { | @@ -119,14 +121,14 @@ sub SaveServiceForm { | ||
119 | my $update = ($serviceForm{ServiceID}); | 121 | my $update = ($serviceForm{ServiceID}); |
120 | 122 | ||
121 | if ($update) { | 123 | if ($update) { |
122 | - $DBObject->Do(SQL => 'UPDATE service_form SET introduction=?,form=?,form_schema=?,fixed_values=? where service_id=? and queue_id is null', | 124 | + $DBObject->Do(SQL => 'UPDATE service_form SET introduction=?,form=?,form_schema=?,fixed_values=?,custom_props=? where service_id=? and queue_id is null', |
123 | Bind => [ | 125 | Bind => [ |
124 | - \$Param{Introduction}, \$Param{Form}, \$Param{Schema}, \$Param{FixedValues}, \$Param{ServiceID} | 126 | + \$Param{Introduction}, \$Param{Form}, \$Param{Schema}, \$Param{FixedValues}, \$Param{CustomProps}, \$Param{ServiceID} |
125 | ]); | 127 | ]); |
126 | } else { | 128 | } else { |
127 | - $DBObject->Do(SQL => 'INSERT INTO service_form(service_id,introduction,form,form_schema,fixed_values) VALUES (?,?,?,?,?)', | 129 | + $DBObject->Do(SQL => 'INSERT INTO service_form(service_id,introduction,form,form_schema,fixed_values,custom_props) VALUES (?,?,?,?,?,?)', |
128 | Bind => [ | 130 | Bind => [ |
129 | - \$Param{ServiceID}, \$Param{Introduction}, \$Param{Form}, \$Param{Schema}, \$Param{FixedValues} | 131 | + \$Param{ServiceID}, \$Param{Introduction}, \$Param{Form}, \$Param{Schema}, \$Param{FixedValues}, \$Param{CustomProps} |
130 | ]); | 132 | ]); |
131 | } | 133 | } |
132 | 134 | ||
@@ -160,14 +162,14 @@ sub SaveServiceFormForQueue { | @@ -160,14 +162,14 @@ sub SaveServiceFormForQueue { | ||
160 | my $update = ($serviceForm{ServiceID}); | 162 | my $update = ($serviceForm{ServiceID}); |
161 | 163 | ||
162 | if ($update) { | 164 | if ($update) { |
163 | - $DBObject->Do(SQL => 'UPDATE service_form SET introduction=?,form=?,form_schema=?,fixed_values=? where service_id=? and queue_id=? ', | 165 | + $DBObject->Do(SQL => 'UPDATE service_form SET introduction=?,form=?,form_schema=?,fixed_values=?,custom_props=? where service_id=? and queue_id=? ', |
164 | Bind => [ | 166 | Bind => [ |
165 | - \$Param{Introduction}, \$Param{Form}, \$Param{Schema}, \$Param{FixedValues}, \$Param{ServiceID}, \$Param{QueueID} | 167 | + \$Param{Introduction}, \$Param{Form}, \$Param{Schema}, \$Param{FixedValues}, \$Param{CustomProps}, \$Param{ServiceID}, \$Param{QueueID} |
166 | ]); | 168 | ]); |
167 | } else { | 169 | } else { |
168 | - $DBObject->Do(SQL => 'INSERT INTO service_form(service_id,introduction,form,form_schema,queue_id,fixed_values) VALUES (?,?,?,?,?,?)', | 170 | + $DBObject->Do(SQL => 'INSERT INTO service_form(service_id,introduction,form,form_schema,queue_id,fixed_values,custom_props) VALUES (?,?,?,?,?,?,?)', |
169 | Bind => [ | 171 | Bind => [ |
170 | - \$Param{ServiceID}, \$Param{Introduction}, \$Param{Form}, \$Param{Schema}, \$Param{QueueID}, \$Param{FixedValues} | 172 | + \$Param{ServiceID}, \$Param{Introduction}, \$Param{Form}, \$Param{Schema}, \$Param{QueueID}, \$Param{FixedValues}, \$Param{CustomProps} |
171 | ]); | 173 | ]); |
172 | } | 174 | } |
173 | 175 |
NewTicketWizard.sopm
1 | <?xml version="1.0" encoding="utf-8" ?> | 1 | <?xml version="1.0" encoding="utf-8" ?> |
2 | <otrs_package version="1.0"> | 2 | <otrs_package version="1.0"> |
3 | <Name>NewTicketWizard</Name> | 3 | <Name>NewTicketWizard</Name> |
4 | - <Version>1.9.3</Version> | 4 | + <Version>1.9.11</Version> |
5 | <Framework>4.0.x</Framework> | 5 | <Framework>4.0.x</Framework> |
6 | <Vendor>SeTIC</Vendor> | 6 | <Vendor>SeTIC</Vendor> |
7 | <URL>http://www.setic.ufsc.br</URL> | 7 | <URL>http://www.setic.ufsc.br</URL> |
@@ -18,7 +18,12 @@ | @@ -18,7 +18,12 @@ | ||
18 | <ChangeLog version="1.8.1">Layout bug fix</ChangeLog> | 18 | <ChangeLog version="1.8.1">Layout bug fix</ChangeLog> |
19 | <ChangeLog version="1.8.2">Multiselect component</ChangeLog> | 19 | <ChangeLog version="1.8.2">Multiselect component</ChangeLog> |
20 | <ChangeLog version="1.9.0">Table support</ChangeLog> | 20 | <ChangeLog version="1.9.0">Table support</ChangeLog> |
21 | - <ChangeLog version="1.9.3">Support for custom template</ChangeLog> | 21 | + <ChangeLog version="1.9.4">Support for custom template</ChangeLog> |
22 | + <ChangeLog version="1.9.5">Shows and validates JSON in form editing</ChangeLog> | ||
23 | + <ChangeLog version="1.9.6">Support for custom javascript in forms</ChangeLog> | ||
24 | + <ChangeLog version="1.9.7">Fix for datatables instalation</ChangeLog> | ||
25 | + <ChangeLog version="1.9.9">Fix for date fields</ChangeLog> | ||
26 | + <ChangeLog version="1.9.11">Fix for public interface custom properties</ChangeLog> | ||
22 | <IntroInstall Type="post" Title="Thank you">New Ticket Wizard module installed successfully!</IntroInstall> | 27 | <IntroInstall Type="post" Title="Thank you">New Ticket Wizard module installed successfully!</IntroInstall> |
23 | <BuildDate>?</BuildDate> | 28 | <BuildDate>?</BuildDate> |
24 | <BuildHost>?</BuildHost> | 29 | <BuildHost>?</BuildHost> |
@@ -46,8 +51,15 @@ | @@ -46,8 +51,15 @@ | ||
46 | 51 | ||
47 | <File Permission="644" Location="var/httpd/htdocs/js/thirdparty/alpaca/alpaca-full.min.js"></File> | 52 | <File Permission="644" Location="var/httpd/htdocs/js/thirdparty/alpaca/alpaca-full.min.js"></File> |
48 | <File Permission="644" Location="var/httpd/htdocs/js/thirdparty/alpaca/jquery.sumoselect.js"></File> | 53 | <File Permission="644" Location="var/httpd/htdocs/js/thirdparty/alpaca/jquery.sumoselect.js"></File> |
49 | - <File Permission="644" Location="var/httpd/htdocs/js/thirdparty/handlebars/handlebars.js"></File> | 54 | + <File Permission="644" Location="var/httpd/htdocs/js/thirdparty/alpaca/datatables.js"></File> |
55 | + <File Permission="644" Location="var/httpd/htdocs/js/thirdparty/handlebars/handlebars.js"></File> | ||
56 | + <File Permission="644" Location="var/httpd/htdocs/js/jquery.jsonview.js"></File> | ||
50 | <File Permission="644" Location="var/httpd/htdocs/js/NewTicketWizard.js"></File> | 57 | <File Permission="644" Location="var/httpd/htdocs/js/NewTicketWizard.js"></File> |
58 | + | ||
59 | + <File Permission="644" Location="var/httpd/htdocs/js/jquery.chili.js"></File> | ||
60 | + <File Permission="644" Location="var/httpd/htdocs/js/jquery.chili.recipes.javascript.js"></File> | ||
61 | + <File Permission="644" Location="var/httpd/htdocs/js/jquery.chili.recipes.js"></File> | ||
62 | + | ||
51 | 63 | ||
52 | <File Permission="644" Location="var/httpd/htdocs/skins/Customer/default/css/alpaca/images/alpaca-icons.png"></File> | 64 | <File Permission="644" Location="var/httpd/htdocs/skins/Customer/default/css/alpaca/images/alpaca-icons.png"></File> |
53 | <File Permission="644" Location="var/httpd/htdocs/skins/Customer/default/css/alpaca/images/date.png"></File> | 65 | <File Permission="644" Location="var/httpd/htdocs/skins/Customer/default/css/alpaca/images/date.png"></File> |
@@ -61,6 +73,10 @@ | @@ -61,6 +73,10 @@ | ||
61 | <File Permission="644" Location="var/httpd/htdocs/skins/Customer/default/css/alpaca/alpaca-jqueryui-newticketwizard.css"></File> | 73 | <File Permission="644" Location="var/httpd/htdocs/skins/Customer/default/css/alpaca/alpaca-jqueryui-newticketwizard.css"></File> |
62 | <File Permission="644" Location="var/httpd/htdocs/skins/Customer/default/css/alpaca/alpaca-newticketwizard.css"></File> | 74 | <File Permission="644" Location="var/httpd/htdocs/skins/Customer/default/css/alpaca/alpaca-newticketwizard.css"></File> |
63 | <File Permission="644" Location="var/httpd/htdocs/skins/Customer/default/css/alpaca/sumoselect.css"></File> | 75 | <File Permission="644" Location="var/httpd/htdocs/skins/Customer/default/css/alpaca/sumoselect.css"></File> |
76 | + <File Permission="644" Location="var/httpd/htdocs/skins/Customer/default/css/alpaca/datatables.css"></File> | ||
77 | + | ||
78 | + <File Permission="644" Location="var/httpd/htdocs/skins/Agent/default/css/jquery.jsonview.css"></File> | ||
79 | + | ||
64 | 80 | ||
65 | 81 | ||
66 | </Filelist> | 82 | </Filelist> |
NewTicketWizardUFSC.sopm
1 | <?xml version="1.0" encoding="utf-8" ?> | 1 | <?xml version="1.0" encoding="utf-8" ?> |
2 | <otrs_package version="1.0"> | 2 | <otrs_package version="1.0"> |
3 | <Name>NewTicketWizardUFSC</Name> | 3 | <Name>NewTicketWizardUFSC</Name> |
4 | - <Version>1.0.0</Version> | 4 | + <Version>1.0.1</Version> |
5 | <Framework>4.0.x</Framework> | 5 | <Framework>4.0.x</Framework> |
6 | <Vendor>SeTIC</Vendor> | 6 | <Vendor>SeTIC</Vendor> |
7 | <URL>http://www.setic.ufsc.br</URL> | 7 | <URL>http://www.setic.ufsc.br</URL> |
8 | <License>GPLv2</License> | 8 | <License>GPLv2</License> |
9 | <Description>NewTicket Wizard Module Template for UFSC</Description> | 9 | <Description>NewTicket Wizard Module Template for UFSC</Description> |
10 | <ChangeLog version="1.0.0">First version</ChangeLog> | 10 | <ChangeLog version="1.0.0">First version</ChangeLog> |
11 | + <ChangeLog version="1.0.1">Fix for footer</ChangeLog> | ||
11 | <IntroInstall Type="post" Title="Thank you">New Ticket Wizard UFSC Template module installed successfully!</IntroInstall> | 12 | <IntroInstall Type="post" Title="Thank you">New Ticket Wizard UFSC Template module installed successfully!</IntroInstall> |
12 | <BuildDate>?</BuildDate> | 13 | <BuildDate>?</BuildDate> |
13 | <BuildHost>?</BuildHost> | 14 | <BuildHost>?</BuildHost> |
@@ -2,5 +2,7 @@ alter table service_form drop foreign key FK_service_form_service_id_id; | @@ -2,5 +2,7 @@ alter table service_form drop foreign key FK_service_form_service_id_id; | ||
2 | alter table service_form drop primary key; | 2 | alter table service_form drop primary key; |
3 | alter table service_form add id int auto_increment not null primary key; | 3 | alter table service_form add id int auto_increment not null primary key; |
4 | alter table service_form add queue_id int; | 4 | alter table service_form add queue_id int; |
5 | - | ||
6 | alter table service_form add fixed_values text; | 5 | alter table service_form add fixed_values text; |
6 | + | ||
7 | +alter table service_form add custom_props text; | ||
8 | + |
var/httpd/htdocs/js/NewTicketWizard.js
@@ -2,6 +2,7 @@ | @@ -2,6 +2,7 @@ | ||
2 | * Variables | 2 | * Variables |
3 | */ | 3 | */ |
4 | var formAlpaca; | 4 | var formAlpaca; |
5 | +var activeQueue; | ||
5 | 6 | ||
6 | 7 | ||
7 | /** | 8 | /** |
@@ -79,7 +80,78 @@ var postRenderCallback = function(form) { | @@ -79,7 +80,78 @@ var postRenderCallback = function(form) { | ||
79 | return false; | 80 | return false; |
80 | }); | 81 | }); |
81 | } | 82 | } |
83 | + | ||
84 | + carregaCustomProps(activeQueue); | ||
85 | +}; | ||
86 | + | ||
87 | + | ||
88 | +var postRenderCallbackPublic = function(form) { | ||
89 | + formOptions = form.options.fields; | ||
90 | + formAlpaca = form; | ||
91 | + | ||
92 | + Object.keys(formOptions).forEach(function (key) { | ||
93 | + var value = formOptions[key]; | ||
94 | + | ||
95 | + // Extension to set control width | ||
96 | + if (value["control_width"]) { | ||
97 | + $("[name='" + key + "']").width(value["control_width"]); | ||
98 | + } | ||
99 | + }); | ||
100 | + | ||
101 | + if (form) { | ||
102 | + $("[name='service']").val($("#ServiceID").val()); | ||
103 | + $("[name='submit']").css("font-size", "18px"); | ||
104 | + | ||
105 | + form.form.registerSubmitHandler(function(e, form) { | ||
106 | + // validate the entire form (top control + all children) | ||
107 | + form.validate(true); | ||
108 | + | ||
109 | + // draw the validation state (top control + all children) | ||
110 | + form.renderValidationState(true); | ||
111 | + | ||
112 | + // now display something | ||
113 | + if (form.isFormValid()) { | ||
114 | + return true; | ||
115 | + } else { | ||
116 | + alert("Dados inválidos!"); | ||
117 | + return false; | ||
118 | + } | ||
119 | + e.stopPropagation(); | ||
120 | + return false; | ||
121 | + }); | ||
122 | + } | ||
123 | + | ||
124 | + carregaCustomPropsPublic(activeQueue); | ||
82 | }; | 125 | }; |
126 | + | ||
127 | +function carregaCustomPropsPublic(queue) { | ||
128 | + if (! queue) { | ||
129 | + queue = ""; | ||
130 | + } | ||
131 | + | ||
132 | + var url = "/otrs/public.pl?Action=NewTicketWizardPublic;Subaction=GetFormCustomProps" + queue; | ||
133 | + | ||
134 | + url += ";ServiceID=" + $("#ServiceID").val(); | ||
135 | + | ||
136 | + $.getScript(url, function(data) { | ||
137 | + }).fail(function(jqXHR, textStatus, errorThrown) { | ||
138 | + alert(textStatus); | ||
139 | + }); | ||
140 | +} | ||
141 | + | ||
142 | +function carregaCustomProps(queue) { | ||
143 | + if (! queue) { | ||
144 | + queue = ""; | ||
145 | + } | ||
146 | + var url = "/otrs/customer.pl?Action=NewTicketWizard;Subaction=GetFormCustomProps" + queue; | ||
147 | + | ||
148 | + url += ";ServiceID=" + $("#ServiceID").val(); | ||
149 | + | ||
150 | + $.getScript(url, function(data) { | ||
151 | + }).fail(function(jqXHR, textStatus, errorThrown) { | ||
152 | + alert(textStatus); | ||
153 | + }); | ||
154 | +} | ||
83 | 155 | ||
84 | function carregaForm(dataForm, sendText, action, queue) { | 156 | function carregaForm(dataForm, sendText, action, queue) { |
85 | var url = "/otrs/customer.pl?Action=NewTicketWizard;Subaction=GetFormJSON" + queue; | 157 | var url = "/otrs/customer.pl?Action=NewTicketWizard;Subaction=GetFormJSON" + queue; |
@@ -88,6 +160,7 @@ function carregaForm(dataForm, sendText, action, queue) { | @@ -88,6 +160,7 @@ function carregaForm(dataForm, sendText, action, queue) { | ||
88 | formAlpaca.destroy(); | 160 | formAlpaca.destroy(); |
89 | } | 161 | } |
90 | 162 | ||
163 | + activeQueue = queue; | ||
91 | url += ";ServiceID=" + $("#ServiceID").val(); | 164 | url += ";ServiceID=" + $("#ServiceID").val(); |
92 | 165 | ||
93 | $.getJSON(url, function(data) { | 166 | $.getJSON(url, function(data) { |
@@ -109,9 +182,11 @@ function carregaForm(dataForm, sendText, action, queue) { | @@ -109,9 +182,11 @@ function carregaForm(dataForm, sendText, action, queue) { | ||
109 | 182 | ||
110 | $("[name='submit']").css("font-size", "18px"); | 183 | $("[name='submit']").css("font-size", "18px"); |
111 | 184 | ||
185 | + | ||
186 | + | ||
112 | 187 | ||
113 | }).fail(function(jqXHR, textStatus, errorThrown) { | 188 | }).fail(function(jqXHR, textStatus, errorThrown) { |
114 | - alert(textStatus); | 189 | + alert("Erro ao recuperar: " + url + " => " + textStatus); |
115 | }); | 190 | }); |
116 | } | 191 | } |
117 | 192 | ||
@@ -143,6 +218,7 @@ function carregaFormPublic(dataForm, sendText, action, queue) { | @@ -143,6 +218,7 @@ function carregaFormPublic(dataForm, sendText, action, queue) { | ||
143 | //$("#formTicket").find("select").val(""); | 218 | //$("#formTicket").find("select").val(""); |
144 | } | 219 | } |
145 | 220 | ||
221 | + activeQueue = queue; | ||
146 | url += ";ServiceID=" + $("#ServiceID").val(); | 222 | url += ";ServiceID=" + $("#ServiceID").val(); |
147 | 223 | ||
148 | $.getJSON(url, function(data) { | 224 | $.getJSON(url, function(data) { |
@@ -154,14 +230,14 @@ function carregaFormPublic(dataForm, sendText, action, queue) { | @@ -154,14 +230,14 @@ function carregaFormPublic(dataForm, sendText, action, queue) { | ||
154 | "data": dataForm, | 230 | "data": dataForm, |
155 | "schema": buildSchema(data[0]), | 231 | "schema": buildSchema(data[0]), |
156 | "options": buildOptions(data[1], sendText, action), | 232 | "options": buildOptions(data[1], sendText, action), |
157 | - "postRender": postRenderCallback, | 233 | + "postRender": postRenderCallbackPublic, |
158 | "view": "jqueryui-create", | 234 | "view": "jqueryui-create", |
159 | "ui": "jquery-ui" | 235 | "ui": "jquery-ui" |
160 | }); | 236 | }); |
161 | 237 | ||
162 | 238 | ||
163 | }).fail(function(jqXHR, textStatus, errorThrown) { | 239 | }).fail(function(jqXHR, textStatus, errorThrown) { |
164 | - alert(textStatus); | 240 | + alert("Erro ao recuperar: " + url + " => " + textStatus); |
165 | }); | 241 | }); |
166 | } | 242 | } |
167 | 243 |
@@ -0,0 +1,1810 @@ | @@ -0,0 +1,1810 @@ | ||
1 | +/*! | ||
2 | + * Chili - the jQuery plugin for highlighting code | ||
3 | + * http://noteslog.com/chili/ | ||
4 | + * | ||
5 | + * Copyright 2010 Andrea Ercolino | ||
6 | + * Dual licensed under the MIT and GPL licenses. | ||
7 | + * http://docs.jquery.com/License | ||
8 | + * | ||
9 | + * VERSION: NEXT - 20151204 1106 | ||
10 | + */ | ||
11 | + | ||
12 | +(function( $ ) | ||
13 | +{ | ||
14 | + | ||
15 | + $.extend({ | ||
16 | + chili: { | ||
17 | + options: { | ||
18 | + whiteSpace: { | ||
19 | + tabWidth: 4, //spaces | ||
20 | + no1stLine: true //if empty | ||
21 | + }, | ||
22 | + automatic: { | ||
23 | + active: true, | ||
24 | + selector: "code", | ||
25 | + context: document | ||
26 | + }, | ||
27 | + dynamic: { | ||
28 | + active: true, | ||
29 | + origin: '' //used like: recipeFolder + recipeName + '.js' | ||
30 | + }, | ||
31 | + decoration: { | ||
32 | + lineNumbers: !true | ||
33 | + }, | ||
34 | + selection: { | ||
35 | + active: true, | ||
36 | + box: { | ||
37 | + style: [ | ||
38 | + "position:absolute; z-index:3000; overflow:scroll;", | ||
39 | + "width:16em;", | ||
40 | + "height:9em;", | ||
41 | + "border:1px solid gray;", | ||
42 | + "padding:1em;", | ||
43 | + "background-color:white;" | ||
44 | + ].join(' '), | ||
45 | + top: function(pageX, pageY, width, height) | ||
46 | + { | ||
47 | + var result = pageY - Math.round( height / 2 ); | ||
48 | + return result; | ||
49 | + }, | ||
50 | + left: function(pageX, pageY, width, height) | ||
51 | + { | ||
52 | + var result = pageX /*- Math.round( width / 2 )*/; | ||
53 | + return result; | ||
54 | + } | ||
55 | + } | ||
56 | + } | ||
57 | + } | ||
58 | + } | ||
59 | + }); | ||
60 | + | ||
61 | + | ||
62 | + $(function() | ||
63 | + { | ||
64 | + $.chili.loadStylesheetInline('.chili-ln-off {list-style-type: none;}'); | ||
65 | + $.extend($.chili, $.chili.options); | ||
66 | + | ||
67 | + if ($.chili.automatic.active) | ||
68 | + { | ||
69 | + $($.chili.automatic.selector, $.chili.automatic.context).chili(); | ||
70 | + } | ||
71 | + }); | ||
72 | + | ||
73 | + | ||
74 | + $.extend($.chili, { | ||
75 | + version: "next", // development started on 2010-01-06 | ||
76 | + | ||
77 | + /** | ||
78 | + * Returns the language piece of data for the given dom_element | ||
79 | + * | ||
80 | + * @param {Element} dom_element | ||
81 | + * | ||
82 | + * @return String | ||
83 | + */ | ||
84 | + codeLanguage: function( dom_element ) { | ||
85 | + var classes = $(dom_element).attr('class'); | ||
86 | + var matches = classes.match(/\bchili-lang-(\w+)/); | ||
87 | + var result = matches ? matches[1] : ''; | ||
88 | + return result; | ||
89 | + }, | ||
90 | + | ||
91 | + /** | ||
92 | + * Returns the line numbers data for the given dom_element | ||
93 | + * | ||
94 | + * @param {Element} dom_element | ||
95 | + * | ||
96 | + * @return Array | ||
97 | + */ | ||
98 | + codeLineNumbers: function( dom_element ) { | ||
99 | + var classes = $(dom_element).attr('class'); | ||
100 | + var matches = classes.match(/\bchili-ln-(\d+)-([\w][\w\-]*)|\bchili-ln-(\d+)/); | ||
101 | + var result = ! matches | ||
102 | + ? null | ||
103 | + : matches[3] | ||
104 | + ? [ matches[0], matches[3], '' ] | ||
105 | + : [ matches[0], matches[1], matches[2] ]; | ||
106 | + return result; | ||
107 | + }, | ||
108 | + | ||
109 | + /** | ||
110 | + * Returns the codes of any character of the given text | ||
111 | + * (Used for developing Chili) | ||
112 | + * | ||
113 | + * @param {String} text | ||
114 | + * | ||
115 | + * @return String | ||
116 | + */ | ||
117 | + revealChars: function ( text ) | ||
118 | + { | ||
119 | + var result = []; | ||
120 | + for (var i=0, iTop=text.length; i<iTop; i++) | ||
121 | + { | ||
122 | + result.push(text[i] + ' <- ' + text.charCodeAt(i)); | ||
123 | + } | ||
124 | + result = result.join('\n'); | ||
125 | + return result; | ||
126 | + }, | ||
127 | + | ||
128 | + /** | ||
129 | + * Loads the given CSS code as a new style element of head | ||
130 | + * | ||
131 | + * @param {string} sourceCode | ||
132 | + */ | ||
133 | + loadStylesheetInline: function ( sourceCode ) | ||
134 | + { | ||
135 | + if ( document.createElement ) | ||
136 | + { | ||
137 | + var style_element = document.createElement( "style" ); | ||
138 | + style_element.type = "text/css"; | ||
139 | + if ( style_element.styleSheet ) | ||
140 | + { | ||
141 | + style_element.styleSheet.cssText = sourceCode; // IE | ||
142 | + } | ||
143 | + else | ||
144 | + { | ||
145 | + var t = document.createTextNode( sourceCode ); | ||
146 | + style_element.appendChild( t ); | ||
147 | + } | ||
148 | + var head = document.getElementsByTagName( "head" )[0]; | ||
149 | + head.appendChild( style_element ); | ||
150 | + } | ||
151 | + }, | ||
152 | + | ||
153 | + queue: {}, | ||
154 | + | ||
155 | + recipes: {}, | ||
156 | + | ||
157 | + filters: { | ||
158 | + off: function() { | ||
159 | + return this.text; | ||
160 | + } | ||
161 | + } | ||
162 | + }); | ||
163 | + | ||
164 | + | ||
165 | + /** | ||
166 | + * Highlights currently selected elements accordingly to the given options | ||
167 | + * | ||
168 | + * @param {Object} options | ||
169 | + */ | ||
170 | + $.fn.chili = function( options ) | ||
171 | + { | ||
172 | + var globals = $.extend({}, $.chili); | ||
173 | + $.chili = $.extend( true, $.chili, options || {} ); | ||
174 | + this.each(function() | ||
175 | + { | ||
176 | + askDish( this ); | ||
177 | + }); | ||
178 | + $.chili = globals; | ||
179 | + return this; | ||
180 | + }; | ||
181 | + | ||
182 | + /** | ||
183 | + * Returns the recipe path from the given recipeName | ||
184 | + * | ||
185 | + * @param {String} recipeName | ||
186 | + * | ||
187 | + * @return String | ||
188 | + */ | ||
189 | + function getRecipePath( recipeName ) | ||
190 | + { | ||
191 | + var result = $.chili.dynamic.origin + 'jquery.chili.recipes.' + recipeName + '.js'; | ||
192 | + return result; | ||
193 | + } | ||
194 | + | ||
195 | + /** | ||
196 | + * Returns the recipe name from the given recipePath | ||
197 | + * | ||
198 | + * @param {String} recipePath | ||
199 | + * | ||
200 | + * @return String | ||
201 | + */ | ||
202 | + function getRecipeName( recipePath ) | ||
203 | + { | ||
204 | + var matches = recipePath.match(/\bjquery\.chili\.recipes\.([\w-]+)\.js$/i); | ||
205 | + var result = matches[1]; | ||
206 | + return result; | ||
207 | + } | ||
208 | + | ||
209 | + /** | ||
210 | + * Detects the recipe to use for highlighting the given DOM element and | ||
211 | + * makes it happen, for static and dynamic setups | ||
212 | + * | ||
213 | + * @param {Element} dom_element | ||
214 | + */ | ||
215 | + function askDish( dom_element ) | ||
216 | + { | ||
217 | + var recipeName = $.chili.codeLanguage( dom_element ); | ||
218 | + if ( '' == recipeName ) | ||
219 | + return; | ||
220 | + var path = getRecipePath( recipeName ); | ||
221 | + if ( $.chili.dynamic.active && ! $.chili.recipes[ recipeName ] ) | ||
222 | + { | ||
223 | + // dynamic setups come here | ||
224 | + if ( ! $.chili.queue[ path ] ) | ||
225 | + { | ||
226 | + downloadRecipe(path, makeDish, [path]); | ||
227 | + } | ||
228 | + $.chili.queue[ path ].push( dom_element ); | ||
229 | + } | ||
230 | + else | ||
231 | + { | ||
232 | + // static setups come here | ||
233 | + $(dom_element).trigger( 'chili.before_coloring', [recipeName] ); | ||
234 | + makeDish.apply( dom_element, [path] ); | ||
235 | + $(dom_element).trigger( 'chili.after_coloring', [recipeName] ); | ||
236 | + } | ||
237 | + } | ||
238 | + | ||
239 | + /** | ||
240 | + * Highlights the current DOM element using the recipe identified by the | ||
241 | + * given recipePath | ||
242 | + */ | ||
243 | + function makeDish( recipePath ) | ||
244 | + { | ||
245 | + var recipeName = getRecipeName(recipePath); | ||
246 | + var recipe = $.chili.recipes[ recipeName ]; | ||
247 | + if (! recipe) | ||
248 | + return; | ||
249 | + var ingredients = $( this ).text(); | ||
250 | + if (! ingredients) | ||
251 | + return; | ||
252 | + ingredients = fixWhiteSpaceAfterReading(ingredients); | ||
253 | + replaceElement.apply({ | ||
254 | + selector: this, | ||
255 | + subject: ingredients, | ||
256 | + module: recipeName, | ||
257 | + context: {} | ||
258 | + }); | ||
259 | + fixTextSelection(this); | ||
260 | + checkLineNumbers(this); | ||
261 | + } | ||
262 | + | ||
263 | + /** | ||
264 | + * Replaces source code in the given DOM element with its highlighted | ||
265 | + * version | ||
266 | + */ | ||
267 | + function replaceElement() | ||
268 | + { | ||
269 | + filtersPrepare(this); | ||
270 | + var replacement = applyModule( this.subject, this.module, this.context ); | ||
271 | + replacement = filtersProcess(this, replacement); | ||
272 | + | ||
273 | + replacement = fixWhiteSpaceBeforeWriting( replacement ); | ||
274 | + | ||
275 | + var dom_element = $( this.selector )[0]; | ||
276 | + dom_element.innerHTML = replacement; | ||
277 | + } | ||
278 | + | ||
279 | + | ||
280 | + /** | ||
281 | + * Returns the requested action according to the empty configuration of | ||
282 | + * the given values | ||
283 | + * | ||
284 | + * @param {String} recipeName | ||
285 | + * @param {String} blockName | ||
286 | + * @param {String} stepName | ||
287 | + * | ||
288 | + * @return String | ||
289 | + */ | ||
290 | + function requestedAction( recipeName, blockName, stepName ) | ||
291 | + { | ||
292 | + if ( '' != stepName ) return 'applyStep'; | ||
293 | + if ( '' != blockName ) return 'applyBlock'; | ||
294 | + if ( '' != recipeName ) return 'applyRecipe'; | ||
295 | + return ''; | ||
296 | + } | ||
297 | + | ||
298 | + /** | ||
299 | + * Returns the interpretation of the given module into the given context | ||
300 | + * | ||
301 | + * @param {String} module | ||
302 | + * @param {Object} context | ||
303 | + * | ||
304 | + * @return Object | ||
305 | + */ | ||
306 | + function detectAction( module, context ) | ||
307 | + { | ||
308 | + if (! module) return; | ||
309 | + var re = new RegExp('^(?!(?:/$|.+/$|.+//$|.+//.))([^/]*)(?:/([^/]*)(?:/([^/]+))?)?$'); | ||
310 | + var matches = (module || '').match(re); | ||
311 | + if (! matches) return; // Expected recipe[/block[/step]] module format | ||
312 | + var recipeName = matches[1] || ''; | ||
313 | + var blockName = matches[2] || ''; | ||
314 | + var stepName = matches[3] || ''; | ||
315 | + var action = requestedAction( recipeName, blockName, stepName ); | ||
316 | + var recipe = getRecipe( recipeName, context ); | ||
317 | + var result = { | ||
318 | + action: action | ||
319 | + , recipeName: recipeName | ||
320 | + , blockName: blockName | ||
321 | + , stepName: stepName | ||
322 | + , recipe: recipe | ||
323 | + , module: module | ||
324 | + , context: context | ||
325 | + }; | ||
326 | + return result; | ||
327 | + } | ||
328 | + | ||
329 | + /** | ||
330 | + * Returns the cached recipe with the given recipeName if recipeName is | ||
331 | + * not empty, else the recipe from context | ||
332 | + * | ||
333 | + * @param {String} recipeName | ||
334 | + * @param {Object} context | ||
335 | + * | ||
336 | + * @return Object | ||
337 | + */ | ||
338 | + function getRecipe( recipeName, context ) | ||
339 | + { | ||
340 | + var recipe = null; | ||
341 | + if ( '' == recipeName ) | ||
342 | + { | ||
343 | + recipe = context.recipe; | ||
344 | + } | ||
345 | + else | ||
346 | + { | ||
347 | + recipe = $.chili.recipes[ recipeName ]; | ||
348 | + } | ||
349 | + return recipe; | ||
350 | + } | ||
351 | + | ||
352 | + /** | ||
353 | + * Downloads a recipe by means of an ajax call and, on success, applies | ||
354 | + * the cbFunction callback, passing it all cbData array elements as | ||
355 | + * arguments, to any element waiting for being highlighted on the queue | ||
356 | + * of the recipe identified by path | ||
357 | + * | ||
358 | + * @param {String} path | ||
359 | + * @param {Function} cbFunction | ||
360 | + * @param {Array} cbData | ||
361 | + */ | ||
362 | + function downloadRecipe( path, cbFunction, cbData ) | ||
363 | + { | ||
364 | + $.chili.queue[ path ] = []; | ||
365 | + $.getScript( path, function( recipeLoaded ) | ||
366 | + { | ||
367 | + var recipeName = getRecipeName( path ); | ||
368 | + var q = $.chili.queue[ path ]; | ||
369 | + for( var i = 0, iTop = q.length; i < iTop; i++ ) | ||
370 | + { | ||
371 | + var el = q[ i ]; | ||
372 | + if ('undefined' != typeof el.selector) | ||
373 | + { | ||
374 | + el = $(el.selector)[0]; | ||
375 | + } | ||
376 | + $(el).trigger( 'chili.before_coloring', [recipeName] ); | ||
377 | + cbFunction.apply(q[ i ], cbData); | ||
378 | + $(el).trigger( 'chili.after_coloring', [recipeName] ); | ||
379 | + } | ||
380 | + } ); | ||
381 | + } | ||
382 | + | ||
383 | + /** | ||
384 | + * Returns the result of applying the given detected recipe to the given | ||
385 | + * subject | ||
386 | + * | ||
387 | + * @param {String} subject | ||
388 | + * @param {Object} detected | ||
389 | + * | ||
390 | + * @return String | ||
391 | + */ | ||
392 | + function applyRecipe( subject, detected ) | ||
393 | + { | ||
394 | + var recipe = detected.recipe; | ||
395 | + result = cook(subject, recipe); | ||
396 | + return result; | ||
397 | + } | ||
398 | + | ||
399 | + /** | ||
400 | + * Returns the result of applying the given detected block to the given | ||
401 | + * subject | ||
402 | + * | ||
403 | + * @param {String} subject | ||
404 | + * @param {Object} detected | ||
405 | + * | ||
406 | + * @return String | ||
407 | + */ | ||
408 | + function applyBlock( subject, detected ) | ||
409 | + { | ||
410 | + var blockName = detected.blockName; | ||
411 | + var recipe = detected.recipe; | ||
412 | + if (! (blockName in recipe)) | ||
413 | + { | ||
414 | + result = escapeHtmlSpecialChars(subject); | ||
415 | + } | ||
416 | + else | ||
417 | + { | ||
418 | + result = cook(subject, recipe, blockName); | ||
419 | + } | ||
420 | + return result; | ||
421 | + } | ||
422 | + | ||
423 | + /** | ||
424 | + * Returns the result of applying the given detected step to the given | ||
425 | + * subject | ||
426 | + * | ||
427 | + * @param {String} subject | ||
428 | + * @param {Object} detected | ||
429 | + * | ||
430 | + * @return String | ||
431 | + */ | ||
432 | + function applyStep( subject, detected ) | ||
433 | + { | ||
434 | + var recipeName = detected.recipeName; | ||
435 | + var blockName = detected.blockName; | ||
436 | + var stepName = detected.stepName; | ||
437 | + var recipe = detected.recipe; | ||
438 | + var context = detected.context; | ||
439 | + if ('' == blockName) | ||
440 | + { | ||
441 | + blockName = context.blockName; | ||
442 | + } | ||
443 | + if (false | ||
444 | + || ! (blockName in recipe) | ||
445 | + || ! (stepName in recipe[blockName])) | ||
446 | + { | ||
447 | + result = escapeHtmlSpecialChars(subject); | ||
448 | + } | ||
449 | + else | ||
450 | + { | ||
451 | + result = cook(subject, recipe, blockName, stepName); | ||
452 | + } | ||
453 | + return result; | ||
454 | + } | ||
455 | + | ||
456 | + /** | ||
457 | + * Returns the result of applying the given detected action to the given | ||
458 | + * subject | ||
459 | + * | ||
460 | + * @param {String} subject | ||
461 | + * @param {Object} detected | ||
462 | + * | ||
463 | + * @return String | ||
464 | + */ | ||
465 | + function applyAction( subject, detected ) | ||
466 | + { | ||
467 | + var result = ''; | ||
468 | + var action = detected.action; | ||
469 | + switch (action) | ||
470 | + { | ||
471 | + case 'applyRecipe': | ||
472 | + result = applyRecipe(subject, detected); | ||
473 | + break; | ||
474 | + case 'applyBlock': | ||
475 | + result = applyBlock(subject, detected); | ||
476 | + break; | ||
477 | + case 'applyStep': | ||
478 | + result = applyStep(subject, detected); | ||
479 | + break; | ||
480 | + default: | ||
481 | + //nothing to do | ||
482 | + break; | ||
483 | + } | ||
484 | + return result; | ||
485 | + } | ||
486 | + | ||
487 | + /** | ||
488 | + * Returns the result of applying the given detected action to the given | ||
489 | + * subject | ||
490 | + * | ||
491 | + * @param {String} subject | ||
492 | + * @param {Object} detected | ||
493 | + * | ||
494 | + * @return String | ||
495 | + */ | ||
496 | + function applyDeferred( subject, detected ) | ||
497 | + { | ||
498 | + // dynamic setups come here too | ||
499 | + var path = getRecipePath(detected.recipeName); | ||
500 | + if (! $.chili.queue[ path ]) | ||
501 | + { | ||
502 | + downloadRecipe(path, replaceElement); | ||
503 | + } | ||
504 | + var cue = 'chili_' + unique(); | ||
505 | + $.chili.queue[ path ].push( { | ||
506 | + selector: '#' + cue, | ||
507 | + subject: subject, | ||
508 | + module: detected.module, | ||
509 | + context: detected.context | ||
510 | + } ); | ||
511 | + result = '<span id="' + cue + '">' + result + '</span>'; | ||
512 | + return result; | ||
513 | + } | ||
514 | + | ||
515 | + /** | ||
516 | + * Returns the result of applying the given module to the given subject | ||
517 | + * into the given context | ||
518 | + * | ||
519 | + * @param {String} subject | ||
520 | + * @param {String} module | ||
521 | + * @param {Object} context | ||
522 | + * | ||
523 | + * @return String | ||
524 | + */ | ||
525 | + function applyModule( subject, module, context ) | ||
526 | + { | ||
527 | + var result = ''; | ||
528 | + var detected = detectAction(module, context); | ||
529 | + if (typeof detected == 'undefined') | ||
530 | + { | ||
531 | + result = escapeHtmlSpecialChars(subject); | ||
532 | + } | ||
533 | + else if (detected.recipe) | ||
534 | + { | ||
535 | + result = applyAction(subject, detected); | ||
536 | + } | ||
537 | + else if ( $.chili.dynamic.active ) | ||
538 | + { | ||
539 | + result = applyDeferred(subject, detected); | ||
540 | + } | ||
541 | + else | ||
542 | + { | ||
543 | + result = escapeHtmlSpecialChars(subject); | ||
544 | + } | ||
545 | + return result; | ||
546 | + } | ||
547 | + | ||
548 | + /** | ||
549 | + * Returns a unique number. If the given text is not undefined the | ||
550 | + * return value is guaranteed to be unique inside text | ||
551 | + * | ||
552 | + * @param {String} text | ||
553 | + * | ||
554 | + * @return Integer | ||
555 | + */ | ||
556 | + function unique( text ) | ||
557 | + { | ||
558 | + var result = (new Date()).valueOf(); | ||
559 | + while( text && text.indexOf( result ) > -1 ); | ||
560 | + { | ||
561 | + result = (new Date()).valueOf(); | ||
562 | + } | ||
563 | + return result; | ||
564 | + } | ||
565 | + | ||
566 | + | ||
567 | + /** | ||
568 | + * Returns all the steps of the given blockName of the given recipe | ||
569 | + * | ||
570 | + * @param {String} recipe | ||
571 | + * @param {String} blockName | ||
572 | + * | ||
573 | + * @return Array | ||
574 | + */ | ||
575 | + function prepareBlock( recipe, blockName ) | ||
576 | + { | ||
577 | + var steps = []; | ||
578 | + var block = recipe[ blockName ]; | ||
579 | + for( var stepName in block ) | ||
580 | + { | ||
581 | + var prepared = prepareStep( recipe, blockName, stepName ); | ||
582 | + steps.push( prepared ); | ||
583 | + } | ||
584 | + return steps; | ||
585 | + } | ||
586 | + | ||
587 | + /** | ||
588 | + * Returns the number of sub matches in the given regular expression (as | ||
589 | + * a string) | ||
590 | + * | ||
591 | + * @param {String} re | ||
592 | + * | ||
593 | + * @return integer | ||
594 | + */ | ||
595 | + function numberOfSubmatches( re ) | ||
596 | + { | ||
597 | + var submatches = re | ||
598 | + .replace( /\\./g, "%" ) // disable any escaped character | ||
599 | + .replace( /\[.*?\]/g, "%" ) // disable any character class | ||
600 | + .match( /\((?!\?)/g ) // match any open parenthesis, not followed by a ? | ||
601 | + ; | ||
602 | + var result = (submatches || []).length; | ||
603 | + return result; | ||
604 | + } | ||
605 | + | ||
606 | + /** | ||
607 | + * Returns a step built from the given stepName of the given blockName | ||
608 | + * of the given recipe | ||
609 | + * | ||
610 | + * @param {String} recipe | ||
611 | + * @param {String} blockName | ||
612 | + * @param {String} stepName | ||
613 | + * | ||
614 | + * @return Object | ||
615 | + */ | ||
616 | + function prepareStep( recipe, blockName, stepName ) | ||
617 | + { | ||
618 | + var step = recipe[ blockName ][ stepName ]; | ||
619 | + var exp = ( typeof step._match == "string" ) | ||
620 | + ? step._match | ||
621 | + : step._match.source; | ||
622 | + var replacement = step._replace | ||
623 | + ? step._replace | ||
624 | + : '<span class="$0">$$</span>'; | ||
625 | + var result = { | ||
626 | + recipe: recipe, | ||
627 | + blockName: blockName, | ||
628 | + stepName: stepName, | ||
629 | + exp: '(' + exp + ')', // new exp will have 1 more submatch | ||
630 | + length: numberOfSubmatches( exp ) + 1, | ||
631 | + replacement: replacement | ||
632 | + }; | ||
633 | + return result; | ||
634 | + } | ||
635 | + | ||
636 | + /** | ||
637 | + * Returns the given steps, with back references in the regular | ||
638 | + * expression of each step renumbered according to the number of back | ||
639 | + * references found in any previous step | ||
640 | + * | ||
641 | + * @param {Array} steps | ||
642 | + * | ||
643 | + * @return Array | ||
644 | + */ | ||
645 | + function adjustBackReferences( steps ) | ||
646 | + { | ||
647 | + var prevLength = 1; | ||
648 | + var exps = []; | ||
649 | + for (var i = 0, iTop = steps.length; i < iTop; i++) { | ||
650 | + var exp = steps[ i ].exp; | ||
651 | + exp = exp.replace( /\\\\|\\(\d+)/g, | ||
652 | + function( m, aNum ) | ||
653 | + { | ||
654 | + return !aNum ? m : "\\" + ( prevLength + 1 + parseInt( aNum, 10 ) ); | ||
655 | + } | ||
656 | + ); | ||
657 | + exps.push( exp ); | ||
658 | + prevLength += steps[ i ].length; | ||
659 | + } | ||
660 | + return exps; | ||
661 | + } | ||
662 | + | ||
663 | + /** | ||
664 | + * Returns a regular expression built from all the given steps | ||
665 | + * | ||
666 | + * @param {Array} steps | ||
667 | + * | ||
668 | + * @return RegExp | ||
669 | + */ | ||
670 | + function knowHow( steps, flags ) | ||
671 | + { | ||
672 | + var prolog = '((?:\\s|\\S)*?)'; | ||
673 | + var epilog = '((?:\\s|\\S)+)'; | ||
674 | + var exps = adjustBackReferences( steps ); | ||
675 | + var source = '(?:' + exps.join( '|' ) + ')'; | ||
676 | + source = prolog + source + '|' + epilog; | ||
677 | + return new RegExp( source, flags ); | ||
678 | + } | ||
679 | + | ||
680 | + /** | ||
681 | + * Returns the given replacement, after adding the given prefix to all | ||
682 | + * classes of all SPANs | ||
683 | + * | ||
684 | + * @param {String} prefix | ||
685 | + * @param {String} replacement | ||
686 | + * | ||
687 | + * @return String | ||
688 | + */ | ||
689 | + function addPrefix( prefix, replacement ) | ||
690 | + { | ||
691 | + var lookFor = /(<span\s+class\s*=\s*(["']))((?:(?!__)\w)+\2\s*>)/ig; | ||
692 | + var replaceWith = '$1' + prefix + '__$3'; | ||
693 | + var aux = replacement.replace( lookFor, replaceWith ); | ||
694 | + return aux; | ||
695 | + } | ||
696 | + | ||
697 | + /** | ||
698 | + * Returns the step in the given steps and its matches in the given | ||
699 | + * allMatches | ||
700 | + * | ||
701 | + * @param {Object} steps the steps of a recipe | ||
702 | + * @param {Array} allMatches the corresponding matches | ||
703 | + * | ||
704 | + * @return Object | ||
705 | + */ | ||
706 | + function locateStepMatches( steps, allMatches ) | ||
707 | + { | ||
708 | + var matchesIndex = 2; | ||
709 | + for (var i = 0, iTop = steps.length; i < iTop; i++) | ||
710 | + { | ||
711 | + var step = steps[ i ]; | ||
712 | + var stepMatches = allMatches[ matchesIndex ]; | ||
713 | + if (stepMatches) break; | ||
714 | + matchesIndex += step.length; | ||
715 | + } | ||
716 | + var matches = allMatches.slice(matchesIndex, matchesIndex + step.length); | ||
717 | + matches.push( allMatches.index ); | ||
718 | + matches.push( allMatches.input ); | ||
719 | + return {step: step, matches: matches}; | ||
720 | + } | ||
721 | + | ||
722 | + /** | ||
723 | + * Returns the replacement for the given stepMatches, based on the | ||
724 | + * function in stepMatches.step.replacement | ||
725 | + * | ||
726 | + * @param {Object} stepMatches | ||
727 | + * | ||
728 | + * @return String | ||
729 | + */ | ||
730 | + function functionReplacement( stepMatches ) | ||
731 | + { | ||
732 | + var that = | ||
733 | + { | ||
734 | + x: function( subject, module ) | ||
735 | + { | ||
736 | + var result = applyModule( subject, module, stepMatches.step ); | ||
737 | + return result; | ||
738 | + } | ||
739 | + }; | ||
740 | + var result = stepMatches.step.replacement.apply(that, stepMatches.matches); | ||
741 | + return result; | ||
742 | + } | ||
743 | + | ||
744 | + /** | ||
745 | + * Returns the replacement for the given stepMatches, based on the | ||
746 | + * template in stepMatches.step.replacement | ||
747 | + * | ||
748 | + * @param {Object} stepMatches | ||
749 | + * | ||
750 | + * @return String | ||
751 | + */ | ||
752 | + function templateReplacement( stepMatches ) | ||
753 | + { | ||
754 | + var re = /(\\\$)|(?:\$\$)|(?:\$(\d+))/g; | ||
755 | + var substitution = function( m, escaped, K ) | ||
756 | + { | ||
757 | + var result = ''; | ||
758 | + if ( escaped ) /* \$ */ | ||
759 | + { | ||
760 | + result = "$"; | ||
761 | + } | ||
762 | + else if ( !K ) /* $$ */ | ||
763 | + { | ||
764 | + result = escapeHtmlSpecialChars( stepMatches.matches[ 0 ] ); //stepMatches | ||
765 | + } | ||
766 | + else if ( K == "0" ) /* $0 */ | ||
767 | + { | ||
768 | + result = stepMatches.step.stepName; | ||
769 | + } | ||
770 | + else /* $K */ | ||
771 | + { | ||
772 | + result = escapeHtmlSpecialChars( stepMatches.matches[ K ] ); | ||
773 | + } | ||
774 | + return result; | ||
775 | + }; | ||
776 | + var result = stepMatches.step.replacement.replace(re, substitution); | ||
777 | + return result; | ||
778 | + } | ||
779 | + | ||
780 | + /** | ||
781 | + * Returns the replacement for any match found. This is a callback | ||
782 | + * function passed to String.replace() | ||
783 | + * | ||
784 | + * @return String | ||
785 | + */ | ||
786 | + function chef( steps, replaceArgs ) | ||
787 | + { | ||
788 | + var result = ''; | ||
789 | + var anyMatch = replaceArgs[ 0 ]; | ||
790 | + if (! anyMatch) return result; | ||
791 | + | ||
792 | + var epilog = replaceArgs[ replaceArgs.length - 1 ]; | ||
793 | + if (epilog) { | ||
794 | + result = escapeHtmlSpecialChars( epilog ); | ||
795 | + return result; | ||
796 | + } | ||
797 | + var stepMatches = locateStepMatches( steps, replaceArgs ); | ||
798 | + result = $.isFunction(stepMatches.step.replacement) | ||
799 | + ? functionReplacement(stepMatches) | ||
800 | + : templateReplacement(stepMatches) | ||
801 | + ; | ||
802 | + var prolog = replaceArgs[ 1 ]; | ||
803 | + prolog = escapeHtmlSpecialChars( prolog ); | ||
804 | + result = addPrefix( stepMatches.step.recipe._name, result ); | ||
805 | + result = prolog + result; | ||
806 | + return result; | ||
807 | + } | ||
808 | + | ||
809 | + /** | ||
810 | + * Returns the given subject, after replacing all the matches of the | ||
811 | + * given steps, of the given recipe | ||
812 | + * | ||
813 | + * @param {String} subject | ||
814 | + * @param {Object} recipe | ||
815 | + * @param {Array} steps | ||
816 | + * | ||
817 | + * @return String | ||
818 | + */ | ||
819 | + function applySteps( subject, recipe, steps ) | ||
820 | + { | ||
821 | + var flags = recipe._case | ||
822 | + ? "g" | ||
823 | + : "gi"; | ||
824 | + var expr = knowHow( steps, flags ); | ||
825 | + var result = []; | ||
826 | + var matches; | ||
827 | + while ((matches = expr.exec(subject)) != null && matches[0] != '') | ||
828 | + { | ||
829 | + var element = chef(steps, matches); | ||
830 | + result.push(element); | ||
831 | + } | ||
832 | + result = result.join(''); | ||
833 | + return result; | ||
834 | + } | ||
835 | + | ||
836 | + /** | ||
837 | + * Returns the given ingredients, after applying the given steName of | ||
838 | + * the given blockName of the given recipe to it | ||
839 | + * | ||
840 | + * @param {String} ingredients | ||
841 | + * @param {Object} recipe | ||
842 | + * @param {String} blockName | ||
843 | + * @param {String} stepName | ||
844 | + * | ||
845 | + * @return String | ||
846 | + */ | ||
847 | + function cook( ingredients, recipe, blockName, stepName ) | ||
848 | + { | ||
849 | + if (stepName) | ||
850 | + { | ||
851 | + var step = prepareStep(recipe, blockName, stepName); | ||
852 | + var steps = [step]; | ||
853 | + } | ||
854 | + else | ||
855 | + { | ||
856 | + if (! blockName) | ||
857 | + { | ||
858 | + blockName = '_main'; | ||
859 | + checkSpices( recipe ); | ||
860 | + } | ||
861 | + if (! blockName in recipe) | ||
862 | + { | ||
863 | + return escapeHtmlSpecialChars( ingredients ); | ||
864 | + } | ||
865 | + var steps = prepareBlock(recipe, blockName); | ||
866 | + } | ||
867 | + var result = applySteps(ingredients, recipe, steps); | ||
868 | + return result; | ||
869 | + } | ||
870 | + | ||
871 | + | ||
872 | + /** | ||
873 | + * Returns a CSS class definition with the given className and the given | ||
874 | + * classStyle | ||
875 | + * | ||
876 | + * @param {String} className | ||
877 | + * @param {String} classStyle | ||
878 | + * | ||
879 | + * @return String | ||
880 | + */ | ||
881 | + function cssClassDefinition( className, classStyle ) | ||
882 | + { | ||
883 | + var result = '' | ||
884 | + + '.' + className + '\n' | ||
885 | + + '{\n' | ||
886 | + + '\t' + classStyle + '\n' | ||
887 | + + '}\n' | ||
888 | + ; | ||
889 | + return result; | ||
890 | + } | ||
891 | + | ||
892 | + /** | ||
893 | + * Returns the style sheet of the given recipe | ||
894 | + * | ||
895 | + * @param {Object} recipe | ||
896 | + * | ||
897 | + * @return string | ||
898 | + */ | ||
899 | + function makeStylesheet( recipe ) | ||
900 | + { | ||
901 | + var name = recipe._name; | ||
902 | + var content = ['/* Chili -- ' + name + ' */']; | ||
903 | + for (var blockName in recipe) | ||
904 | + { | ||
905 | + if ( blockName.search( /^_(?!main\b)/ ) >= 0 ) | ||
906 | + continue; // if _bar but not _main nor foo | ||
907 | + var block = recipe[ blockName ]; | ||
908 | + for (var stepName in block) | ||
909 | + { | ||
910 | + var step = block[ stepName ]; | ||
911 | + if (! '_style' in step) | ||
912 | + continue; | ||
913 | + var style_def = step[ '_style' ]; | ||
914 | + if ( typeof style_def == 'string' ) | ||
915 | + { | ||
916 | + var oStyle = {}; | ||
917 | + oStyle[ stepName ] = style_def; | ||
918 | + style_def = oStyle; | ||
919 | + } | ||
920 | + for (var className in style_def) | ||
921 | + { | ||
922 | + var stepClass = name + '__' + className; | ||
923 | + var stepStyle = style_def[ className ]; | ||
924 | + var def = cssClassDefinition( stepClass, stepStyle ); | ||
925 | + content.push(def); | ||
926 | + } | ||
927 | + } | ||
928 | + } | ||
929 | + var result = content.join('\n'); | ||
930 | + return result; | ||
931 | + } | ||
932 | + | ||
933 | + /** | ||
934 | + * If needed, generates and loads the style sheet of the given recipe | ||
935 | + * into the current page | ||
936 | + * | ||
937 | + * @param {Object} recipe | ||
938 | + */ | ||
939 | + function checkSpices( recipe ) | ||
940 | + { | ||
941 | + var name = recipe._name; | ||
942 | + if ( ! $.chili.queue[ name ] ) | ||
943 | + { | ||
944 | + var stylesheet = makeStylesheet(recipe); | ||
945 | + $.chili.loadStylesheetInline(stylesheet); | ||
946 | + $.chili.queue[ name ] = true; | ||
947 | + } | ||
948 | + } | ||
949 | + | ||
950 | + | ||
951 | + /** | ||
952 | + * Returns the given sting padded to itself the given times | ||
953 | + * | ||
954 | + * @param {String} string | ||
955 | + * @param {Number} times | ||
956 | + */ | ||
957 | + function repeat( string, times ) | ||
958 | + { | ||
959 | + var result = ''; | ||
960 | + for (var i = 0; i < times; i++) | ||
961 | + { | ||
962 | + result += string; | ||
963 | + } | ||
964 | + return result; | ||
965 | + } | ||
966 | + | ||
967 | + /** | ||
968 | + * Returns the given text, with all &, <, and > replaced by their HTML | ||
969 | + * entities | ||
970 | + * | ||
971 | + * @param {String} text | ||
972 | + * | ||
973 | + * @return String | ||
974 | + */ | ||
975 | + function escapeHtmlSpecialChars( text ) | ||
976 | + { | ||
977 | + var result = text | ||
978 | + .replace( /&/g, "&" ) | ||
979 | + .replace( /</g, "<" ) | ||
980 | + .replace( />/g, ">" ) | ||
981 | + ; | ||
982 | + return result; | ||
983 | + } | ||
984 | + | ||
985 | + /** | ||
986 | + * Returns the given text, with all &, <, and > replaced to their HTML | ||
987 | + * entities | ||
988 | + * | ||
989 | + * @param {String} text | ||
990 | + * | ||
991 | + * @return String | ||
992 | + */ | ||
993 | + function unescapeHtmlSpecialChars( text ) | ||
994 | + { | ||
995 | + var result = text | ||
996 | + .replace( /&/g, "&" ) | ||
997 | + .replace( /</g, "<" ) | ||
998 | + .replace( />/g, ">" ) | ||
999 | + ; | ||
1000 | + return result; | ||
1001 | + } | ||
1002 | + | ||
1003 | + /** | ||
1004 | + * Scans the given subject and calls the given callback, passing along | ||
1005 | + * the given args, for each piece of text or html tag it finds | ||
1006 | + * | ||
1007 | + * @param {String} subject | ||
1008 | + * @param {Function} callback | ||
1009 | + * @param {Array} args | ||
1010 | + */ | ||
1011 | + function scan( subject, callback, args ) | ||
1012 | + { | ||
1013 | + args = args || []; | ||
1014 | + var expr = /([\w\W]*?)(?:(<\w+[^>]*\/>)|(<\w+[^>]*>)|(<\/\w+[^>]*>))|([\w\W]+)/ig; | ||
1015 | + var func = function(all, prolog, tag_empty, tag_open, tag_close, epilog) | ||
1016 | + { | ||
1017 | + var realOffset = matches.index; | ||
1018 | + var token; | ||
1019 | + if (epilog) | ||
1020 | + { | ||
1021 | + token = tokenMake('text', epilog, realOffset); | ||
1022 | + callback.apply(token, args); | ||
1023 | + } | ||
1024 | + else | ||
1025 | + { | ||
1026 | + token = tokenMake('text', prolog, realOffset); | ||
1027 | + callback.apply(token, args); | ||
1028 | + | ||
1029 | + realOffset += prolog.length; | ||
1030 | + if (tag_empty) | ||
1031 | + { | ||
1032 | + token = tokenMake('empty', tag_empty, realOffset); | ||
1033 | + } | ||
1034 | + else if(tag_open) | ||
1035 | + { | ||
1036 | + token = tokenMake('open', tag_open, realOffset); | ||
1037 | + } | ||
1038 | + else if(tag_close) | ||
1039 | + { | ||
1040 | + token = tokenMake('close', tag_close, realOffset); | ||
1041 | + } | ||
1042 | + callback.apply(token, args); | ||
1043 | + } | ||
1044 | + }; | ||
1045 | + var matches; | ||
1046 | + while ((matches = expr.exec(subject)) != null && matches[0] != '') | ||
1047 | + { | ||
1048 | + func.apply({}, matches); | ||
1049 | + } | ||
1050 | + } | ||
1051 | + | ||
1052 | + /** | ||
1053 | + * Returns the given text, with all spaces replaced by the writingSpace | ||
1054 | + * string | ||
1055 | + * | ||
1056 | + * @param {String} text | ||
1057 | + * | ||
1058 | + * @return String | ||
1059 | + */ | ||
1060 | + function escapeSpaces( text ) | ||
1061 | + { | ||
1062 | + var writingSpace = $.chili.whiteSpace.writingSpace; | ||
1063 | + var result = text.replace(/ /g, writingSpace); | ||
1064 | + return result; | ||
1065 | + } | ||
1066 | + | ||
1067 | + /** | ||
1068 | + * Returns the given text, with all tabs replaced by the writingTab | ||
1069 | + * string | ||
1070 | + * | ||
1071 | + * @param {String} text | ||
1072 | + * | ||
1073 | + * @return String | ||
1074 | + */ | ||
1075 | + function escapeTabs( text ) | ||
1076 | + { | ||
1077 | + var writingTab = $.chili.whiteSpace.writingTab; | ||
1078 | + var result = text.replace(/\t/g, writingTab); | ||
1079 | + return result; | ||
1080 | + } | ||
1081 | + | ||
1082 | + /** | ||
1083 | + * Returns the given text, with all '\n' replaced by the browser new | ||
1084 | + * line string | ||
1085 | + * | ||
1086 | + * @param {String} text | ||
1087 | + * | ||
1088 | + * @return String | ||
1089 | + */ | ||
1090 | + function lineFeedsToNewLines( text ) | ||
1091 | + { | ||
1092 | + var writingNewLine = $.chili.whiteSpace.writingNewLine; | ||
1093 | + var result = text.replace(/\n/g, writingNewLine); | ||
1094 | + return result; | ||
1095 | + } | ||
1096 | + | ||
1097 | + /** | ||
1098 | + * Returns the given text, with all the browser new line strings | ||
1099 | + * replaced by '\n' | ||
1100 | + * | ||
1101 | + * @param {String} text | ||
1102 | + * | ||
1103 | + * @return String | ||
1104 | + */ | ||
1105 | + function newLinesToLineFeeds( text ) | ||
1106 | + { | ||
1107 | + var result = text; | ||
1108 | + result = result.replace(/ <BR>/ig, '\n'); | ||
1109 | + result = result.replace(/\r\n?/g, '\n'); | ||
1110 | + return result; | ||
1111 | + } | ||
1112 | + | ||
1113 | + /** | ||
1114 | + * Sets white space constants into $.chili | ||
1115 | + * | ||
1116 | + * @param {String} html | ||
1117 | + */ | ||
1118 | + function setWhiteSpaceConstants( html ) | ||
1119 | + { | ||
1120 | + $.chili.whiteSpace.writingSpace = ' '; | ||
1121 | + $.chili.whiteSpace.writingTab = repeat(' ', $.chili.whiteSpace.tabWidth); | ||
1122 | + $.chili.whiteSpace.writingNewLine = '\n'; | ||
1123 | + if (/\r\n?/.test(html)) | ||
1124 | + { | ||
1125 | + if ($.browser.msie) | ||
1126 | + { | ||
1127 | + $.chili.whiteSpace.writingNewLine = ' <br>'; | ||
1128 | + } | ||
1129 | + else | ||
1130 | + { | ||
1131 | + $.chili.whiteSpace.writingNewLine = /\r\n/.test(html) | ||
1132 | + ? '\r\n' | ||
1133 | + : '\r'; | ||
1134 | + } | ||
1135 | + } | ||
1136 | + } | ||
1137 | + | ||
1138 | + /** | ||
1139 | + * Returns the given text after making new lines uniform across | ||
1140 | + * all browsers | ||
1141 | + * | ||
1142 | + * @param {String} text | ||
1143 | + * | ||
1144 | + * @return String | ||
1145 | + */ | ||
1146 | + function fixWhiteSpaceAfterReading( html ) | ||
1147 | + { | ||
1148 | + setWhiteSpaceConstants(html); | ||
1149 | + var result = newLinesToLineFeeds(html); | ||
1150 | + if ( $.chili.whiteSpace.no1stLine ) | ||
1151 | + { | ||
1152 | + result = result.replace(/^\n/, ''); | ||
1153 | + } | ||
1154 | + return result; | ||
1155 | + } | ||
1156 | + | ||
1157 | + /** | ||
1158 | + * Returns the given text after making new lines uniform across | ||
1159 | + * all browsers | ||
1160 | + * | ||
1161 | + * @param {String} html | ||
1162 | + * | ||
1163 | + * @return String | ||
1164 | + */ | ||
1165 | + function fixWhiteSpaceBeforeWriting( html ) | ||
1166 | + { | ||
1167 | + var result = []; | ||
1168 | + scan(html, function () | ||
1169 | + { | ||
1170 | + var value = this.value; | ||
1171 | + if (this.type == 'text') | ||
1172 | + { | ||
1173 | + value = escapeSpaces( value ); | ||
1174 | + value = escapeTabs( value ); | ||
1175 | + value = lineFeedsToNewLines( value ); | ||
1176 | + } | ||
1177 | + result.push(value); | ||
1178 | + }); | ||
1179 | + result = result.join(''); | ||
1180 | + return result; | ||
1181 | + } | ||
1182 | + | ||
1183 | + | ||
1184 | + /** | ||
1185 | + * Wraps a given line into well formed open and close tags, based on the | ||
1186 | + * given open stack | ||
1187 | + * | ||
1188 | + * @param {String} line | ||
1189 | + * @param {Array} open | ||
1190 | + * | ||
1191 | + * @return Object | ||
1192 | + */ | ||
1193 | + function well_form( line, open ) | ||
1194 | + { | ||
1195 | + var close = []; | ||
1196 | + var open_start = open.join(''); | ||
1197 | + scan(line, function() | ||
1198 | + { | ||
1199 | + if (this.type == 'open') | ||
1200 | + { | ||
1201 | + open.push(this.value); | ||
1202 | + } | ||
1203 | + else if (this.type == 'close') | ||
1204 | + { | ||
1205 | + open.pop(); | ||
1206 | + } | ||
1207 | + }); | ||
1208 | + for (var i = 0, iTop = open.length; i < iTop; i++) | ||
1209 | + { | ||
1210 | + var tag_open = open[i]; | ||
1211 | + var tag_close = tag_open.replace(/^<(\w+)[^>]*>$/, '</$1>'); | ||
1212 | + close.unshift(tag_close); | ||
1213 | + } | ||
1214 | + var close_end = close.join(''); | ||
1215 | + line = open_start + line + close_end; | ||
1216 | + return { | ||
1217 | + line: line, | ||
1218 | + open: open | ||
1219 | + }; | ||
1220 | + } | ||
1221 | + | ||
1222 | + /** | ||
1223 | + * Converts lines inside the given dom_element to list items into an | ||
1224 | + * ordered list element | ||
1225 | + * | ||
1226 | + * @param {Element} dom_element | ||
1227 | + * | ||
1228 | + * @return String | ||
1229 | + */ | ||
1230 | + function makeOrderedList( html ) | ||
1231 | + { | ||
1232 | + var open = []; | ||
1233 | + var expr = /(.*)\n/g; | ||
1234 | + var func = function ( all, line ) | ||
1235 | + { | ||
1236 | + var well_formed = well_form(line, open); | ||
1237 | + open = well_formed.open; | ||
1238 | + line = well_formed.line | ||
1239 | + ? '<li>' + well_formed.line + '</li>' | ||
1240 | + : '<li> </li>'; //leave a space in empty lines | ||
1241 | + return line; | ||
1242 | + }; | ||
1243 | + var result = html.replace(expr, func); | ||
1244 | + result = '<ol>' + result + '</ol>'; | ||
1245 | + return result; | ||
1246 | + } | ||
1247 | + | ||
1248 | + /** | ||
1249 | + * Sets the start of the ol tag of the current DOM element | ||
1250 | + * | ||
1251 | + * @param {String} groupStart | ||
1252 | + * @param {String} groupId | ||
1253 | + * @param {String} start | ||
1254 | + */ | ||
1255 | + function setLineNumbersStart( all, groupStart, groupId ) | ||
1256 | + { | ||
1257 | + var start = parseInt( groupStart, 10 ); | ||
1258 | + if ( groupId ) | ||
1259 | + { | ||
1260 | + var $pieces = $( '.' + all ); | ||
1261 | + var pos = $pieces.index( this ); | ||
1262 | + $pieces | ||
1263 | + .slice( 0, pos ) | ||
1264 | + .each( | ||
1265 | + function() | ||
1266 | + { | ||
1267 | + start += $( this ).find( 'li' ).length; | ||
1268 | + } | ||
1269 | + ) | ||
1270 | + ; | ||
1271 | + } | ||
1272 | + $(this).find( 'ol' ).attr('start', start); | ||
1273 | + // refresh the window | ||
1274 | + $('body') | ||
1275 | + .width( $('body').width() - 1 ) | ||
1276 | + .width( $('body').width() + 1 ) | ||
1277 | + ; | ||
1278 | + } | ||
1279 | + | ||
1280 | + /** | ||
1281 | + * Make line numbers appear into the given dom_element | ||
1282 | + * | ||
1283 | + * @param {Element} dom_element | ||
1284 | + */ | ||
1285 | + function addLineNumbers( dom_element ) | ||
1286 | + { | ||
1287 | + var html = $(dom_element).html(); | ||
1288 | + html = fixWhiteSpaceAfterReading(html); | ||
1289 | + html = makeOrderedList( html ); | ||
1290 | + html = fixWhiteSpaceBeforeWriting(html); | ||
1291 | + dom_element.innerHTML = html; | ||
1292 | + } | ||
1293 | + | ||
1294 | + /** | ||
1295 | + * If needed, adds line numbers with a proper start to the given | ||
1296 | + * dom_element | ||
1297 | + * | ||
1298 | + * @param {Element} dom_element | ||
1299 | + */ | ||
1300 | + function checkLineNumbers( dom_element ) | ||
1301 | + { | ||
1302 | + var ln = $.chili.codeLineNumbers(dom_element); | ||
1303 | + if (ln) | ||
1304 | + { | ||
1305 | + addLineNumbers(dom_element); | ||
1306 | + setLineNumbersStart.apply(dom_element, ln); | ||
1307 | + } | ||
1308 | + else if ($.chili.decoration.lineNumbers) | ||
1309 | + { | ||
1310 | + addLineNumbers(dom_element); | ||
1311 | + } | ||
1312 | + } | ||
1313 | + | ||
1314 | + | ||
1315 | + /** | ||
1316 | + * Makes filters from tags into that.subject, adds those filters to that | ||
1317 | + * and cleans up that.subject | ||
1318 | + * | ||
1319 | + * @param {Object} that | ||
1320 | + */ | ||
1321 | + function filtersPrepare( that ) | ||
1322 | + { | ||
1323 | + var subject = that.subject; | ||
1324 | + if (! /{:\w+\(/.test(subject)) | ||
1325 | + { | ||
1326 | + return; | ||
1327 | + } | ||
1328 | + var format = 0; | ||
1329 | + var expr = /({:(\w+)\((|(?:(['"])[^\4\n]*(?:\\.[^\4\n]*)*\4)(?:\s*,\s*((['"])[^\6\n]*(?:\\.[^\6\n]*)*\6))*)\)\[)((?:.|\n)*?)(\]\2:})/g; | ||
1330 | + var func = function(all, tag_open, callback, args, ignore4, ignore5, ignore6, target, tag_close, offset) | ||
1331 | + { | ||
1332 | + eval('args = [' + args + '];'); | ||
1333 | + var filter = { | ||
1334 | + original: target, | ||
1335 | + start: offset - format, | ||
1336 | + count: target.length, | ||
1337 | + callback: callback, | ||
1338 | + args: args | ||
1339 | + }; | ||
1340 | + format += tag_open.length + tag_close.length; | ||
1341 | + if ($.isArray(that.filters)) | ||
1342 | + { | ||
1343 | + that.filters.push(filter); | ||
1344 | + } | ||
1345 | + else | ||
1346 | + { | ||
1347 | + that.filters = [filter]; | ||
1348 | + } | ||
1349 | + return target; | ||
1350 | + }; | ||
1351 | + subject = escapeHtmlSpecialChars(subject); | ||
1352 | + subject = subject.replace(expr, func); | ||
1353 | + subject = unescapeHtmlSpecialChars(subject); | ||
1354 | + that.subject = subject; | ||
1355 | + } | ||
1356 | + | ||
1357 | + /** | ||
1358 | + * Makes up a token object based on the given type, value and start | ||
1359 | + * | ||
1360 | + * @param {String} type | ||
1361 | + * @param {String} value | ||
1362 | + * @param {Integer} start | ||
1363 | + * | ||
1364 | + * @return Object | ||
1365 | + */ | ||
1366 | + function tokenMake( type, value, start ) | ||
1367 | + { | ||
1368 | + var result = { | ||
1369 | + type: type, | ||
1370 | + value: value, | ||
1371 | + start: start | ||
1372 | + }; | ||
1373 | + return result; | ||
1374 | + } | ||
1375 | + | ||
1376 | + /** | ||
1377 | + * Splits the given html into its tags and texts | ||
1378 | + * | ||
1379 | + * @param {String} html | ||
1380 | + * | ||
1381 | + * @return Array | ||
1382 | + */ | ||
1383 | + function tokenSplit( html ) | ||
1384 | + { | ||
1385 | + var result = []; | ||
1386 | + var format = 0; | ||
1387 | + scan(html, function() | ||
1388 | + { | ||
1389 | + switch (this.type) | ||
1390 | + { | ||
1391 | + case 'empty': | ||
1392 | + case 'open': | ||
1393 | + case 'close': | ||
1394 | + format += this.value.length; | ||
1395 | + break; | ||
1396 | + case 'text': | ||
1397 | + this.start -= format; | ||
1398 | + this.end = this.start + this.value.length; | ||
1399 | + break; | ||
1400 | + default: | ||
1401 | + throw "no type case for '" + this.type + "'"; | ||
1402 | + break; | ||
1403 | + } | ||
1404 | + result.push(this); | ||
1405 | + }); | ||
1406 | + return result; | ||
1407 | + } | ||
1408 | + | ||
1409 | + /** | ||
1410 | + * Strips empty span tags from the given html | ||
1411 | + * | ||
1412 | + * @param {String} html | ||
1413 | + * | ||
1414 | + * @return String | ||
1415 | + */ | ||
1416 | + function stripEmpties( html ) | ||
1417 | + { | ||
1418 | + var result = html.replace(/<span[^>]+><\/span>/g, ''); | ||
1419 | + return result; | ||
1420 | + } | ||
1421 | + | ||
1422 | + /** | ||
1423 | + * Joins values of all tokens | ||
1424 | + * | ||
1425 | + * @param {Array} tokens | ||
1426 | + * | ||
1427 | + * @return String | ||
1428 | + */ | ||
1429 | + function tokenJoin( tokens ) | ||
1430 | + { | ||
1431 | + var result = []; | ||
1432 | + for (var i = 0, iTop = tokens.length; i < iTop; i++) | ||
1433 | + { | ||
1434 | + result.push(tokens[i].value); | ||
1435 | + } | ||
1436 | + result = result.join(''); | ||
1437 | + result = stripEmpties(result); | ||
1438 | + return result; | ||
1439 | + } | ||
1440 | + | ||
1441 | + /** | ||
1442 | + * Finds beginning and ending tokens in the given tokens that contain the | ||
1443 | + * begin and end of the string that starts at the given start and whose | ||
1444 | + * length is the given count | ||
1445 | + * | ||
1446 | + * @param {Array} tokens | ||
1447 | + * @param {Integer} start | ||
1448 | + * @param {Integer} count | ||
1449 | + * | ||
1450 | + * @return {Object} | ||
1451 | + */ | ||
1452 | + function tokenFind( tokens, start, count ) | ||
1453 | + { | ||
1454 | + var end = start + count; | ||
1455 | + var firstPos = -1; | ||
1456 | + var lastPos = -1; | ||
1457 | + var previousSpan = ''; | ||
1458 | + var firstSpan = ''; | ||
1459 | + var lastSpan = ''; | ||
1460 | + for (var i = 0, iTop = tokens.length; i < iTop; i++) | ||
1461 | + { | ||
1462 | + var token = tokens[i]; | ||
1463 | + if (token.type == 'open') | ||
1464 | + { | ||
1465 | + previousSpan = token.value; | ||
1466 | + } | ||
1467 | + else if (token.type == 'close') | ||
1468 | + { | ||
1469 | + previousSpan = ''; | ||
1470 | + } | ||
1471 | + else | ||
1472 | + { | ||
1473 | + if (token.start <= start && start < token.end) | ||
1474 | + { | ||
1475 | + firstPos = i; | ||
1476 | + firstSpan = previousSpan; | ||
1477 | + } | ||
1478 | + if (token.start <= end && end < token.end) | ||
1479 | + { | ||
1480 | + lastPos = i; | ||
1481 | + lastSpan = previousSpan; | ||
1482 | + } | ||
1483 | + if (firstPos != -1 && lastPos != -1) | ||
1484 | + { | ||
1485 | + break; | ||
1486 | + } | ||
1487 | + } | ||
1488 | + } | ||
1489 | + var result = { | ||
1490 | + first: { | ||
1491 | + position: firstPos, | ||
1492 | + span: firstSpan | ||
1493 | + }, | ||
1494 | + last: { | ||
1495 | + position: lastPos, | ||
1496 | + span: lastSpan | ||
1497 | + } | ||
1498 | + }; | ||
1499 | + return result; | ||
1500 | + } | ||
1501 | + | ||
1502 | + /** | ||
1503 | + * Returns the tokens that result from breaking in two given token at the | ||
1504 | + * given position; if the given span is not empty, two additional tokens are | ||
1505 | + * returned to leave the sequence well formed | ||
1506 | + * | ||
1507 | + * @param {Object} token | ||
1508 | + * @param {Integer} position | ||
1509 | + * @param {String} span | ||
1510 | + * | ||
1511 | + * @return {Object} | ||
1512 | + */ | ||
1513 | + function tokenBreak( token, position, span ) | ||
1514 | + { | ||
1515 | + var firstText = token.value.substr(0, position); | ||
1516 | + var firstToken = tokenMake('text', firstText, token.start); | ||
1517 | + firstToken.end = token.start + firstText.length; | ||
1518 | + | ||
1519 | + var secondText = token.value.substr(position); | ||
1520 | + var secondToken = tokenMake('text', secondText, token.start + position); | ||
1521 | + secondToken.end = token.start + position + secondText.length; | ||
1522 | + | ||
1523 | + var result = { | ||
1524 | + first: [firstToken], | ||
1525 | + second: [secondToken] | ||
1526 | + }; | ||
1527 | + if (span) | ||
1528 | + { | ||
1529 | + result.first.push(tokenMake('close', '</span>')); | ||
1530 | + result.second.unshift(tokenMake('open', span)); | ||
1531 | + } | ||
1532 | + return result; | ||
1533 | + } | ||
1534 | + | ||
1535 | + /** | ||
1536 | + * Creates a new html token out of the given tokens and insert it at the | ||
1537 | + * right position into them. The token contains all the string that starts | ||
1538 | + * at the given start and whose length is the given count. | ||
1539 | + * Resulting tokens are well formed. | ||
1540 | + * | ||
1541 | + * @param {Array} tokens | ||
1542 | + * @param {Integer} start | ||
1543 | + * @param {Integer} count | ||
1544 | + * | ||
1545 | + * @return {Object} | ||
1546 | + */ | ||
1547 | + function tokenExtract( tokens, start, count ) | ||
1548 | + { | ||
1549 | + var end = start + count; | ||
1550 | + | ||
1551 | + var found = tokenFind(tokens, start, count); | ||
1552 | + var beforeTokens = tokens.slice(0, found.first.position); | ||
1553 | + var firstToken = tokens[found.first.position]; | ||
1554 | + var middleTokens = tokens.slice(found.first.position + 1, found.last.position); | ||
1555 | + var lastToken = tokens[found.last.position]; | ||
1556 | + var afterTokens = tokens.slice(found.last.position + 1); | ||
1557 | + | ||
1558 | + var firstTokens = tokenBreak(firstToken, start - firstToken.start, found.first.span); | ||
1559 | + var lastTokens = tokenBreak(lastToken, end - lastToken.start, found.last.span); | ||
1560 | + | ||
1561 | + var newValue = [].concat( | ||
1562 | + firstTokens.second, | ||
1563 | + middleTokens, | ||
1564 | + lastTokens.first | ||
1565 | + ); | ||
1566 | + newValue = tokenJoin(newValue); | ||
1567 | + var newToken = tokenMake('html', newValue, start); | ||
1568 | + | ||
1569 | + tokens = [].concat( | ||
1570 | + beforeTokens, | ||
1571 | + firstTokens.first, | ||
1572 | + newToken, | ||
1573 | + lastTokens.second, | ||
1574 | + afterTokens | ||
1575 | + ); | ||
1576 | + var result = { | ||
1577 | + tokens: tokens, | ||
1578 | + position: beforeTokens.length + firstTokens.first.length | ||
1579 | + }; | ||
1580 | + return result; | ||
1581 | + } | ||
1582 | + | ||
1583 | + /** | ||
1584 | + * Applies all the filters of the given that to the given html | ||
1585 | + * | ||
1586 | + * @param {Object} that | ||
1587 | + * @param {String} html | ||
1588 | + * | ||
1589 | + * @return String | ||
1590 | + */ | ||
1591 | + function filtersProcess( that, html ) | ||
1592 | + { | ||
1593 | + var result = html; | ||
1594 | + if (! that.filters) | ||
1595 | + { | ||
1596 | + return result; | ||
1597 | + } | ||
1598 | + var tokens = []; | ||
1599 | + for (var i = 0, iTop = that.filters.length; i < iTop; i++ ) | ||
1600 | + { | ||
1601 | + var filter = that.filters[i]; | ||
1602 | + var callback = $.chili.filters && $.chili.filters[ filter.callback ]; | ||
1603 | + if (! (callback && $.isFunction(callback))) | ||
1604 | + { | ||
1605 | + continue; | ||
1606 | + } | ||
1607 | + if (0 == tokens.length) | ||
1608 | + { | ||
1609 | + tokens = tokenSplit(html); | ||
1610 | + } | ||
1611 | + var extraction = tokenExtract(tokens, filter.start, filter.count); | ||
1612 | + tokens = extraction.tokens; | ||
1613 | + var position = extraction.position; | ||
1614 | + var filterInput = { | ||
1615 | + text: filter.original, | ||
1616 | + html: tokens[ position ].value | ||
1617 | + }; | ||
1618 | + var args = filter.args; | ||
1619 | + var filterOutput = callback.apply(filterInput, args); | ||
1620 | + tokens[ position ].value = filterOutput; | ||
1621 | + } | ||
1622 | + if (0 < tokens.length) | ||
1623 | + { | ||
1624 | + result = tokenJoin(tokens); | ||
1625 | + } | ||
1626 | + return result; | ||
1627 | + } | ||
1628 | + | ||
1629 | + | ||
1630 | + /** | ||
1631 | + * Clears anything that was selected before | ||
1632 | + */ | ||
1633 | + function clearPreviousSelection() | ||
1634 | + { | ||
1635 | + if ($.browser.msie) | ||
1636 | + { | ||
1637 | + document.selection.empty(); | ||
1638 | + } | ||
1639 | + else | ||
1640 | + { | ||
1641 | + window.getSelection().removeAllRanges(); | ||
1642 | + } | ||
1643 | + } | ||
1644 | + | ||
1645 | + /** | ||
1646 | + * Resets the currently selected element | ||
1647 | + * | ||
1648 | + * This is later used to check that the user selected text from | ||
1649 | + * the same element | ||
1650 | + */ | ||
1651 | + function resetSelectedTextElement() | ||
1652 | + { | ||
1653 | + element = this; | ||
1654 | + clearPreviousSelection(); | ||
1655 | + } | ||
1656 | + | ||
1657 | + /** | ||
1658 | + * Returns the text selected by the user | ||
1659 | + */ | ||
1660 | + function getSelectedText() | ||
1661 | + { | ||
1662 | + var result; | ||
1663 | + if ($.browser.msie) | ||
1664 | + { | ||
1665 | + result = document.selection.createRange().htmlText; | ||
1666 | + } | ||
1667 | + else | ||
1668 | + { | ||
1669 | + var selection = window.getSelection(); | ||
1670 | + var range = selection.getRangeAt(0); | ||
1671 | + selection = selection.toString(); | ||
1672 | + range = range.toString(); | ||
1673 | + //selection works for line numbers on, range otherwise | ||
1674 | + result = /\n/.test(selection) ? selection : range; | ||
1675 | + } | ||
1676 | + return result; | ||
1677 | + } | ||
1678 | + | ||
1679 | + /** | ||
1680 | + * Returns the given html after replacing any HTML break and block by a | ||
1681 | + * new line | ||
1682 | + * | ||
1683 | + * @param {String} html | ||
1684 | + * | ||
1685 | + * @return String | ||
1686 | + */ | ||
1687 | + function preserveNewLines( html ) | ||
1688 | + { | ||
1689 | + var newline_flag = unique(html); | ||
1690 | + var text = ''; | ||
1691 | + if (/<br\b/i.test(html) || /<li\b/i.test(html)) | ||
1692 | + { | ||
1693 | + if (/<br\b/i.test(html)) | ||
1694 | + { | ||
1695 | + html = html.replace( /\<br[^>]*?\>/ig, newline_flag ); | ||
1696 | + } | ||
1697 | + else if (/<li\b/i.test(html)) | ||
1698 | + { | ||
1699 | + html = html.replace( /<ol[^>]*?>|<\/ol>|<li[^>]*?>/ig, '' ).replace( /<\/li>/ig, newline_flag ); | ||
1700 | + } | ||
1701 | + var el = $( '<pre>' ).appendTo( 'body' ).hide()[0]; | ||
1702 | + el.innerHTML = html; | ||
1703 | + text = $( el ).text().replace( new RegExp( newline_flag, "g" ), '\r\n' ); | ||
1704 | + $( el ).remove(); | ||
1705 | + } | ||
1706 | + return text; | ||
1707 | + } | ||
1708 | + | ||
1709 | + /** | ||
1710 | + * Returns the given text, after removing garbage characters | ||
1711 | + */ | ||
1712 | + function cleanText( text ) | ||
1713 | + { | ||
1714 | + var result = $.browser.msie | ||
1715 | + ? preserveNewLines(text) | ||
1716 | + : text | ||
1717 | + .replace( /\r/g, '' ) | ||
1718 | + .replace( /^# ?/g, '' ) | ||
1719 | + .replace( /\n# ?/g, '\n' ); | ||
1720 | + return result; | ||
1721 | + } | ||
1722 | + | ||
1723 | + /** | ||
1724 | + * Shows a dialog containing the given text | ||
1725 | + */ | ||
1726 | + function makeDialog( selected, event ) | ||
1727 | + { | ||
1728 | + var boxOptions = $.chili.selection.box; | ||
1729 | + var boxTag = $.browser.msie | ||
1730 | + ? ('<textarea style="' + boxOptions.style + '">') | ||
1731 | + : ('<pre style="' + boxOptions.style + '">'); | ||
1732 | + | ||
1733 | + var boxElement = $(boxTag) | ||
1734 | + .appendTo( 'body' ) | ||
1735 | + .text( selected ) | ||
1736 | + .attr( 'id', 'chili_selection' ) | ||
1737 | + .click( function() { $(this).remove(); } ) | ||
1738 | + ; | ||
1739 | + var top = boxOptions.top(event.pageX, event.pageY, | ||
1740 | + boxElement.width(), boxElement.height()); | ||
1741 | + var left = boxOptions.left(event.pageX, event.pageY, | ||
1742 | + boxElement.width(), boxElement.height()); | ||
1743 | + boxElement.css( { top: top, left: left } ); | ||
1744 | + | ||
1745 | + return boxElement; | ||
1746 | + } | ||
1747 | + | ||
1748 | + /** | ||
1749 | + * Selects the text in the given $container | ||
1750 | + */ | ||
1751 | + function selectTextAgain($container) | ||
1752 | + { | ||
1753 | + if ($.browser.msie) | ||
1754 | + { | ||
1755 | + $container[0].focus(); | ||
1756 | + $container[0].select(); | ||
1757 | + } | ||
1758 | + else | ||
1759 | + { | ||
1760 | + var s = window.getSelection(); | ||
1761 | + s.removeAllRanges(); | ||
1762 | + var r = document.createRange(); | ||
1763 | + r.selectNodeContents( $container[0] ); | ||
1764 | + s.addRange( r ); | ||
1765 | + } | ||
1766 | + } | ||
1767 | + | ||
1768 | + /** | ||
1769 | + * Shows a dialog containing the text selected by the user | ||
1770 | + */ | ||
1771 | + function displaySelectedTextDialog( event ) | ||
1772 | + { | ||
1773 | + if (! (element && element == this)) | ||
1774 | + { | ||
1775 | + return; | ||
1776 | + } | ||
1777 | + element = null; | ||
1778 | + | ||
1779 | + var selectedText = getSelectedText(); | ||
1780 | + if ( '' == selectedText ) | ||
1781 | + { | ||
1782 | + return; | ||
1783 | + } | ||
1784 | + selectedText = cleanText(selectedText); | ||
1785 | + | ||
1786 | + var $container = makeDialog(selectedText, event); | ||
1787 | + selectTextAgain($container); | ||
1788 | + } | ||
1789 | + | ||
1790 | + /** | ||
1791 | + * When a user selects highlighted text, IE and FF returns a mess: this | ||
1792 | + * function displays a minimal dialog with the selected text, cleaned up | ||
1793 | + */ | ||
1794 | + function fixTextSelection( dom_element ) | ||
1795 | + { | ||
1796 | + //chrome, opera, and safari select PRE text correctly | ||
1797 | + if ($.chili.selection.active && ($.browser.msie || $.browser.mozilla)) | ||
1798 | + { | ||
1799 | + var element = null; | ||
1800 | + $(dom_element) | ||
1801 | + .parents() | ||
1802 | + .filter("pre") | ||
1803 | + .bind("mousedown", resetSelectedTextElement) | ||
1804 | + .bind("mouseup", displaySelectedTextDialog) | ||
1805 | + ; | ||
1806 | + } | ||
1807 | + } | ||
1808 | + | ||
1809 | + } | ||
1810 | +)(jQuery); |
@@ -0,0 +1,65 @@ | @@ -0,0 +1,65 @@ | ||
1 | +jQuery.chili.recipes.javascript = | ||
2 | +{ | ||
3 | + _name: 'js' | ||
4 | + , _case: true | ||
5 | + , _main: { | ||
6 | + ml_comment: { | ||
7 | + _match: /\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\// | ||
8 | + , _style: 'color: gray;' | ||
9 | + } | ||
10 | + , sl_comment: { | ||
11 | + _match: /\/\/.*/ | ||
12 | + , _style: 'color: green;' | ||
13 | + } | ||
14 | + , string: { | ||
15 | + _match: /(?:\'[^\'\\\n]*(?:\\.[^\'\\\n]*)*\')|(?:\"[^\"\\\n]*(?:\\.[^\"\\\n]*)*\")/ | ||
16 | + , _style: 'color: teal;' | ||
17 | + } | ||
18 | + , num: { | ||
19 | + _match: /\b[+-]?(?:\d*\.?\d+|\d+\.?\d*)(?:[eE][+-]?\d+)?\b/ | ||
20 | + , _style: 'color: red;' | ||
21 | + } | ||
22 | + , reg_not: { //this prevents "a / b / c" to be interpreted as a reg_exp | ||
23 | + _match: /(?:\w+\s*)\/[^\/\\\n]*(?:\\.[^\/\\\n]*)*\/[gim]*(?:\s*\w+)/ | ||
24 | + , _replace: function( all ) { | ||
25 | + return this.x( all, '//num' ); | ||
26 | + } | ||
27 | + } | ||
28 | + , reg_exp: { | ||
29 | + _match: /\/[^\/\\\n]*(?:\\.[^\/\\\n]*)*\/[gim]*/ | ||
30 | + , _style: 'color: maroon;' | ||
31 | + } | ||
32 | + , brace: { | ||
33 | + _match: /[\{\}]/ | ||
34 | + , _style: 'color: red; font-weight: bold;' | ||
35 | + } | ||
36 | + , statement: { | ||
37 | + _match: /\b(with|while|var|try|throw|switch|return|if|for|finally|else|do|default|continue|const|catch|case|break)\b/ | ||
38 | + , _style: 'color: navy; font-weight: bold;' | ||
39 | + } | ||
40 | + , error: { | ||
41 | + _match: /\b(URIError|TypeError|SyntaxError|ReferenceError|RangeError|EvalError|Error)\b/ | ||
42 | + , _style: 'color: Coral;' | ||
43 | + } | ||
44 | + , object: { | ||
45 | + _match: /\b(String|RegExp|Object|Number|Math|Function|Date|Boolean|Array)\b/ | ||
46 | + , _style: 'color: DeepPink;' | ||
47 | + } | ||
48 | + , property: { | ||
49 | + _match: /\b(undefined|arguments|NaN|Infinity)\b/ | ||
50 | + , _style: 'color: Purple; font-weight: bold;' | ||
51 | + } | ||
52 | + , 'function': { | ||
53 | + _match: /\b(parseInt|parseFloat|isNaN|isFinite|eval|encodeURIComponent|encodeURI|decodeURIComponent|decodeURI)\b/ | ||
54 | + , _style: 'color: olive;' | ||
55 | + } | ||
56 | + , operator: { | ||
57 | + _match: /\b(void|typeof|this|new|instanceof|in|function|delete)\b/ | ||
58 | + , _style: 'color: RoyalBlue; font-weight: bold;' | ||
59 | + } | ||
60 | + , liveconnect: { | ||
61 | + _match: /\b(sun|netscape|java|Packages|JavaPackage|JavaObject|JavaClass|JavaArray|JSObject|JSException)\b/ | ||
62 | + , _style: 'text-decoration: overline;' | ||
63 | + } | ||
64 | + } | ||
65 | +}; | ||
0 | \ No newline at end of file | 66 | \ No newline at end of file |
@@ -0,0 +1,347 @@ | @@ -0,0 +1,347 @@ | ||
1 | +jQuery.chili.options.dynamic.active = false; | ||
2 | + | ||
3 | + | ||
4 | + | ||
5 | +/* this recipe uses a little trick for highlighting php code | ||
6 | + * 1: replace each php snippet with a placeholder | ||
7 | + * 2: highlight html without php and php snippets apart | ||
8 | + * 3: replace each placeholder with its highlighted php snippet | ||
9 | + * | ||
10 | + * the trick is not perfect | ||
11 | + */ | ||
12 | +jQuery.chili.recipes.php = | ||
13 | +{ | ||
14 | + _name: "php" | ||
15 | + , _case: true | ||
16 | + , _main: { | ||
17 | + all: { | ||
18 | + _match: /[\w\W]*/ | ||
19 | + , _replace: function( all ) { | ||
20 | + var placeholder = String.fromCharCode(0); | ||
21 | + var blocks = []; | ||
22 | + var that = this; | ||
23 | + var no_php_1 = all.replace( /<\?[^?]*\?+(?:[^>][^?]*\?+)*>/g, function( block ) { | ||
24 | + blocks.push( that.x( block, '/block/php_1' ) ); | ||
25 | + return placeholder; | ||
26 | + } ); | ||
27 | + var no_php_2 = no_php_1.replace( /^[^?]*\?+(?:[^>][^?]*\?+)*>|<\?[\w\W]*$/g, function( block ) { | ||
28 | + blocks.push( that.x( block, '/block/php_2' ) ); | ||
29 | + return placeholder; | ||
30 | + } ); | ||
31 | + if( blocks.length ) { | ||
32 | + var html = this.x( no_php_2, 'html' ); | ||
33 | + var count = 0; | ||
34 | + return html.replace( new RegExp( placeholder, "g" ), function() { | ||
35 | + return blocks[ count++ ]; | ||
36 | + } ); | ||
37 | + } | ||
38 | + else { | ||
39 | + return this.x( all, '/php' ); | ||
40 | + } | ||
41 | + } | ||
42 | + } | ||
43 | + } | ||
44 | + , block: { | ||
45 | + php_1: { // --- <? +++ ?> --- | ||
46 | + _match: /(<\?(?:php\b)?)([^?]*\?+(?:[^>][^?]*\?+)*>)/ | ||
47 | + , _replace: function( all, open, content ) { | ||
48 | + return "<span class='start'>" + this.x( open ) + "</span>" | ||
49 | + + this.x( content.replace( /\?>$/, '' ), '/php' ) | ||
50 | + + "<span class='end'>" + this.x( '?>' ) + "</span>"; | ||
51 | + } | ||
52 | + , _style: { | ||
53 | + start: "color: red; font-weight: bold" | ||
54 | + , end: "color: red;" | ||
55 | + } | ||
56 | + } | ||
57 | + , php_2: { // +++ ?> --- <? +++ | ||
58 | + _match: /([^?]*\?+(?:[^>][^?]*\?+)*>)|(<\?(?:php\b)?)([\w\W]*)/ | ||
59 | + , _replace: function( all, content, open2, content2 ) { | ||
60 | + if( open2 ) { | ||
61 | + return "<span class='start'>" + this.x( open2 ) + "</span>" | ||
62 | + + this.x( content2, '/php' ); | ||
63 | + } | ||
64 | + else { | ||
65 | + return this.x( content.replace( /\?>$/, '' ), '/php' ) | ||
66 | + + "<span class='end'>" + this.x( '?>' ) + "</span>"; | ||
67 | + } | ||
68 | + } | ||
69 | + , _style: { | ||
70 | + start: "color: red; font-weight: bold" | ||
71 | + , end: "color: red;" | ||
72 | + } | ||
73 | + } | ||
74 | + } | ||
75 | + , php: { | ||
76 | + mlcom: { | ||
77 | + _match: /\/\*[^*]*\*+([^\/][^*]*\*+)*\// | ||
78 | + , _style: "color: gray;" | ||
79 | + } | ||
80 | + , com: { | ||
81 | + _match: /(?:\/\/.*)|(?:[^\\]\#.*)/ | ||
82 | + , _style: "color: green;" | ||
83 | + } | ||
84 | + , string1: { | ||
85 | + _match: /\'[^\'\\]*(?:\\.[^\'\\]*)*\'/ | ||
86 | + , _style: "color: purple;" | ||
87 | + } | ||
88 | + , string2: { | ||
89 | + _match: /\"[^\"\\]*(?:\\.[^\"\\]*)*\"/ | ||
90 | + , _style: "color: fuchsia;" | ||
91 | + } | ||
92 | + , value: { | ||
93 | + _match: /\b(?:[Nn][Uu][Ll][Ll]|[Tt][Rr][Uu][Ee]|[Ff][Aa][Ll][Ss][Ee])\b/ | ||
94 | + , _style: "color: gray; font-weight: bold;" | ||
95 | + } | ||
96 | + , number: { | ||
97 | + _match: /\b[+-]?(\d*\.?\d+|\d+\.?\d*)([eE][+-]?\d+)?\b/ | ||
98 | + , _style: "color: red;" | ||
99 | + } | ||
100 | + , const1: { | ||
101 | + _match: /\b(?:DEFAULT_INCLUDE_PATH|E_(?:ALL|CO(?:MPILE_(?:ERROR|WARNING)|RE_(?:ERROR|WARNING))|ERROR|NOTICE|PARSE|STRICT|USER_(?:ERROR|NOTICE|WARNING)|WARNING)|P(?:EAR_(?:EXTENSION_DIR|INSTALL_DIR)|HP_(?:BINDIR|CONFIG_FILE_(?:PATH|SCAN_DIR)|DATADIR|E(?:OL|XTENSION_DIR)|INT_(?:MAX|SIZE)|L(?:IBDIR|OCALSTATEDIR)|O(?:S|UTPUT_HANDLER_(?:CONT|END|START))|PREFIX|S(?:API|HLIB_SUFFIX|YSCONFDIR)|VERSION))|__COMPILER_HALT_OFFSET__)\b/ | ||
102 | + , _style: "color: red;" | ||
103 | + } | ||
104 | + , const2: { | ||
105 | + _match: /\b(?:A(?:B(?:DAY_(?:1|2|3|4|5|6|7)|MON_(?:1(?:0|1|2|)|2|3|4|5|6|7|8|9))|LT_DIGITS|M_STR|SSERT_(?:ACTIVE|BAIL|CALLBACK|QUIET_EVAL|WARNING))|C(?:ASE_(?:LOWER|UPPER)|HAR_MAX|O(?:DESET|NNECTION_(?:ABORTED|NORMAL|TIMEOUT)|UNT_(?:NORMAL|RECURSIVE))|R(?:EDITS_(?:ALL|DOCS|FULLPAGE|G(?:ENERAL|ROUP)|MODULES|QA|SAPI)|NCYSTR|YPT_(?:BLOWFISH|EXT_DES|MD5|S(?:ALT_LENGTH|TD_DES)))|URRENCY_SYMBOL)|D(?:AY_(?:1|2|3|4|5|6|7)|ECIMAL_POINT|IRECTORY_SEPARATOR|_(?:FMT|T_FMT))|E(?:NT_(?:COMPAT|NOQUOTES|QUOTES)|RA(?:_(?:D_(?:FMT|T_FMT)|T_FMT|YEAR)|)|XTR_(?:IF_EXISTS|OVERWRITE|PREFIX_(?:ALL|I(?:F_EXISTS|NVALID)|SAME)|SKIP))|FRAC_DIGITS|GROUPING|HTML_(?:ENTITIES|SPECIALCHARS)|IN(?:FO_(?:ALL|C(?:ONFIGURATION|REDITS)|ENVIRONMENT|GENERAL|LICENSE|MODULES|VARIABLES)|I_(?:ALL|PERDIR|SYSTEM|USER)|T_(?:CURR_SYMBOL|FRAC_DIGITS))|L(?:C_(?:ALL|C(?:OLLATE|TYPE)|M(?:ESSAGES|ONETARY)|NUMERIC|TIME)|O(?:CK_(?:EX|NB|SH|UN)|G_(?:A(?:LERT|UTH(?:PRIV|))|C(?:ONS|R(?:IT|ON))|D(?:AEMON|EBUG)|E(?:MERG|RR)|INFO|KERN|L(?:OCAL(?:0|1|2|3|4|5|6|7)|PR)|MAIL|N(?:DELAY|EWS|O(?:TICE|WAIT))|ODELAY|P(?:ERROR|ID)|SYSLOG|U(?:SER|UCP)|WARNING)))|M(?:ON_(?:1(?:0|1|2|)|2|3|4|5|6|7|8|9|DECIMAL_POINT|GROUPING|THOUSANDS_SEP)|_(?:1_PI|2_(?:PI|SQRTPI)|E|L(?:N(?:10|2)|OG(?:10E|2E))|PI(?:_(?:2|4)|)|SQRT(?:1_2|2)))|N(?:EGATIVE_SIGN|O(?:EXPR|STR)|_(?:CS_PRECEDES|S(?:EP_BY_SPACE|IGN_POSN)))|P(?:ATH(?:INFO_(?:BASENAME|DIRNAME|EXTENSION)|_SEPARATOR)|M_STR|OSITIVE_SIGN|_(?:CS_PRECEDES|S(?:EP_BY_SPACE|IGN_POSN)))|RADIXCHAR|S(?:EEK_(?:CUR|END|SET)|ORT_(?:ASC|DESC|NUMERIC|REGULAR|STRING)|TR_PAD_(?:BOTH|LEFT|RIGHT))|T(?:HOUS(?:ANDS_SEP|EP)|_FMT(?:_AMPM|))|YES(?:EXPR|STR))\b/ | ||
106 | + , _style: "color: red;" | ||
107 | + } | ||
108 | + , global: { | ||
109 | + _match: /(?:\$GLOBALS|\$_COOKIE|\$_ENV|\$_FILES|\$_GET|\$_POST|\$_REQUEST|\$_SERVER|\$_SESSION|\$php_errormsg)\b/ | ||
110 | + , _style: "color: red;" | ||
111 | + } | ||
112 | + , keyword: { | ||
113 | + _match: /\b(?:__CLASS__|__FILE__|__FUNCTION__|__LINE__|__METHOD__|abstract|and|array|as|break|case|catch|cfunction|class|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|eval|exception|exit|extends|extends|final|for|foreach|function|global|if|implements|include|include_once|interface|isset|list|new|old_function|or|php_user_filter|print|private|protected|public|require|require_once|return|static|switch|this|throw|try|unset|use|var|while|xor)\b/ | ||
114 | + , _style: "color: navy; font-weight: bold;" | ||
115 | + } | ||
116 | + , variable: { | ||
117 | + _match: /\$(\w+)/ | ||
118 | + , _replace: '<span class="keyword">$</span><span class="variable">$1</span>' | ||
119 | + , _style: "color: #4040c2;" | ||
120 | + } | ||
121 | + , heredoc: { | ||
122 | + _match: /(\<\<\<\s*)(\w+)((?:(?!\2).*\n)+)(\2)\b/ | ||
123 | + , _replace: '<span class="keyword">$1</span><span class="string1">$2</span><span class="string2">$3</span><span class="string1">$4</span>' | ||
124 | + } | ||
125 | + } | ||
126 | +}; | ||
127 | + | ||
128 | + | ||
129 | + | ||
130 | +jQuery.chili.recipes.html = | ||
131 | +{ | ||
132 | + _name: 'html' | ||
133 | + , _case: false | ||
134 | + , _main: { | ||
135 | + doctype: { | ||
136 | + _match: /<!DOCTYPE\b[\w\W]*?>/ | ||
137 | + , _style: "color: #CC6600;" | ||
138 | + } | ||
139 | + , ie_style: { | ||
140 | + _match: /(<!--\[[^\]]*\]>)([\w\W]*?)(<!\[[^\]]*\]-->)/ | ||
141 | + , _replace: function( all, open, content, close ) { | ||
142 | + return "<span class='ie_style'>" + this.x( open ) + "</span>" | ||
143 | + + this.x( content, '//style' ) | ||
144 | + + "<span class='ie_style'>" + this.x( close ) + "</span>"; | ||
145 | + } | ||
146 | + , _style: "color: DarkSlateGray; font-weight: bold;" | ||
147 | + } | ||
148 | + , comment: { | ||
149 | + _match: /<!--[\w\W]*?-->/ | ||
150 | + , _style: "color: #4040c2;" | ||
151 | + } | ||
152 | + , script: { | ||
153 | + _match: /(<script\s+[^>]*>)([\w\W]*?)(<\/script\s*>)/ | ||
154 | + , _replace: function( all, open, content, close ) { | ||
155 | + return this.x( open, '//tag_start' ) | ||
156 | + + this.x( content, 'javascript' ) | ||
157 | + + this.x( close, '//tag_end' ); | ||
158 | + } | ||
159 | + } | ||
160 | + , style: { | ||
161 | + _match: /(<style\s+[^>]*>)([\w\W]*?)(<\/style\s*>)/ | ||
162 | + , _replace: function( all, open, content, close ) { | ||
163 | + return this.x( open, '//tag_start' ) | ||
164 | + + this.x( content, 'css' ) | ||
165 | + + this.x( close, '//tag_end' ); | ||
166 | + } | ||
167 | + } | ||
168 | + // matches a starting tag of an element (with attrs) | ||
169 | + // like "<div ... >" or "<img ... />" | ||
170 | + , tag_start: { | ||
171 | + _match: /(<\w+)((?:[?%]>|[\w\W])*?)(\/>|>)/ | ||
172 | + , _replace: function( all, open, content, close ) { | ||
173 | + return "<span class='tag_start'>" + this.x( open ) + "</span>" | ||
174 | + + this.x( content, '/tag_attrs' ) | ||
175 | + + "<span class='tag_start'>" + this.x( close ) + "</span>"; | ||
176 | + } | ||
177 | + , _style: "color: navy; font-weight: bold;" | ||
178 | + } | ||
179 | + // matches an ending tag | ||
180 | + // like "</div>" | ||
181 | + , tag_end: { | ||
182 | + _match: /<\/\w+\s*>|\/>/ | ||
183 | + , _style: "color: navy;" | ||
184 | + } | ||
185 | + , entity: { | ||
186 | + _match: /&\w+?;/ | ||
187 | + , _style: "color: blue;" | ||
188 | + } | ||
189 | + } | ||
190 | + , tag_attrs: { | ||
191 | + // matches a name/value pair | ||
192 | + attr: { | ||
193 | + // before in $1, name in $2, between in $3, value in $4 | ||
194 | + _match: /(\W*?)([\w-]+)(\s*=\s*)((?:\'[^\']*(?:\\.[^\']*)*\')|(?:\"[^\"]*(?:\\.[^\"]*)*\"))/ | ||
195 | + , _replace: "$1<span class='attr_name'>$2</span>$3<span class='attr_value'>$4</span>" | ||
196 | + , _style: { attr_name: "color: green;", attr_value: "color: maroon;" } | ||
197 | + } | ||
198 | + } | ||
199 | +}; | ||
200 | + | ||
201 | + | ||
202 | + | ||
203 | +jQuery.chili.recipes.javascript = | ||
204 | +{ | ||
205 | + _name: 'js' | ||
206 | + , _case: true | ||
207 | + , _main: { | ||
208 | + ml_comment: { | ||
209 | + _match: /\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\// | ||
210 | + , _style: 'color: gray;' | ||
211 | + } | ||
212 | + , sl_comment: { | ||
213 | + _match: /\/\/.*/ | ||
214 | + , _style: 'color: green;' | ||
215 | + } | ||
216 | + , string: { | ||
217 | + _match: /(?:\'[^\'\\\n]*(?:\\.[^\'\\\n]*)*\')|(?:\"[^\"\\\n]*(?:\\.[^\"\\\n]*)*\")/ | ||
218 | + , _style: 'color: teal;' | ||
219 | + } | ||
220 | + , num: { | ||
221 | + _match: /\b[+-]?(?:\d*\.?\d+|\d+\.?\d*)(?:[eE][+-]?\d+)?\b/ | ||
222 | + , _style: 'color: red;' | ||
223 | + } | ||
224 | + , reg_not: { //this prevents "a / b / c" to be interpreted as a reg_exp | ||
225 | + _match: /(?:\w+\s*)\/[^\/\\\n]*(?:\\.[^\/\\\n]*)*\/[gim]*(?:\s*\w+)/ | ||
226 | + , _replace: function( all ) { | ||
227 | + return this.x( all, '//num' ); | ||
228 | + } | ||
229 | + } | ||
230 | + , reg_exp: { | ||
231 | + _match: /\/[^\/\\\n]*(?:\\.[^\/\\\n]*)*\/[gim]*/ | ||
232 | + , _style: 'color: maroon;' | ||
233 | + } | ||
234 | + , brace: { | ||
235 | + _match: /[\{\}]/ | ||
236 | + , _style: 'color: red; font-weight: bold;' | ||
237 | + } | ||
238 | + , statement: { | ||
239 | + _match: /\b(with|while|var|try|throw|switch|return|if|for|finally|else|do|default|continue|const|catch|case|break)\b/ | ||
240 | + , _style: 'color: navy; font-weight: bold;' | ||
241 | + } | ||
242 | + , error: { | ||
243 | + _match: /\b(URIError|TypeError|SyntaxError|ReferenceError|RangeError|EvalError|Error)\b/ | ||
244 | + , _style: 'color: Coral;' | ||
245 | + } | ||
246 | + , object: { | ||
247 | + _match: /\b(String|RegExp|Object|Number|Math|Function|Date|Boolean|Array)\b/ | ||
248 | + , _style: 'color: DeepPink;' | ||
249 | + } | ||
250 | + , property: { | ||
251 | + _match: /\b(undefined|arguments|NaN|Infinity)\b/ | ||
252 | + , _style: 'color: Purple; font-weight: bold;' | ||
253 | + } | ||
254 | + , 'function': { | ||
255 | + _match: /\b(parseInt|parseFloat|isNaN|isFinite|eval|encodeURIComponent|encodeURI|decodeURIComponent|decodeURI)\b/ | ||
256 | + , _style: 'color: olive;' | ||
257 | + } | ||
258 | + , operator: { | ||
259 | + _match: /\b(void|typeof|this|new|instanceof|in|function|delete)\b/ | ||
260 | + , _style: 'color: RoyalBlue; font-weight: bold;' | ||
261 | + } | ||
262 | + , liveconnect: { | ||
263 | + _match: /\b(sun|netscape|java|Packages|JavaPackage|JavaObject|JavaClass|JavaArray|JSObject|JSException)\b/ | ||
264 | + , _style: 'text-decoration: overline;' | ||
265 | + } | ||
266 | + } | ||
267 | +}; | ||
268 | + | ||
269 | + | ||
270 | + | ||
271 | +jQuery.chili.recipes.css = | ||
272 | +{ | ||
273 | + _name: 'css' | ||
274 | + , _case: true | ||
275 | + , _main: { | ||
276 | + comment: { | ||
277 | + _match: /\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\// | ||
278 | + , _style: "color: olive;" | ||
279 | + } | ||
280 | + , directive: { | ||
281 | + _match: /@\w+/ | ||
282 | + , _style: "color: fuchsia;" | ||
283 | + } | ||
284 | + , url: { | ||
285 | + _match: /\b(url\s*\()([^)]+)(\))/ | ||
286 | + , _replace: "<span class='url'>$1</span>$2<span class='url'>$3</span>" | ||
287 | + , _style: "color: fuchsia;" | ||
288 | + } | ||
289 | + , block: { | ||
290 | + _match: /\{([\w\W]*?)\}/ | ||
291 | + , _replace: function( all, pairs ) { | ||
292 | + return '{' + this.x( pairs, '/definition' ) + '}'; | ||
293 | + } | ||
294 | + } | ||
295 | + , 'class': { | ||
296 | + _match: /\.\w+/ | ||
297 | + , _style: "color: #CC0066; font-weight: bold;" | ||
298 | + } | ||
299 | + , id: { | ||
300 | + _match: /#\w+/ | ||
301 | + , _style: "color: IndianRed; font-weight: bold;" | ||
302 | + } | ||
303 | + , pseudo: { | ||
304 | + _match: /:\w+/ | ||
305 | + , _style: "color: #CC9900;" | ||
306 | + } | ||
307 | + , element: { | ||
308 | + _match: /\w+/ | ||
309 | + , _style: "color: Purple; font-weight: bold;" | ||
310 | + } | ||
311 | + } | ||
312 | + , definition: { | ||
313 | + comment: { | ||
314 | + _match: /\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\// | ||
315 | + } | ||
316 | + , property: { | ||
317 | + _match: /\b(?:zoom|z-index|writing-mode|word-wrap|word-spacing|word-break|width|widows|white-space|volume|voice-family|visibility|vertical-align|unicode-bidi|top|text-underline-position|text-transform|text-shadow|text-overflow|text-kashida-space|text-justify|text-indent|text-decoration|text-autospace|text-align-last|text-align|table-layout|stress|speech-rate|speak-punctuation|speak-numeral|speak-header|speak|size|scrollbar-track-color|scrollbar-shadow-color|scrollbar-highlight-color|scrollbar-face-color|scrollbar-dark-shadow-color|scrollbar-base-color|scrollbar-arrow-color|scrollbar-3d-light-color|ruby-position|ruby-overhang|ruby-align|right|richness|quotes|position|play-during|pitch-range|pitch|pause-before|pause-after|pause|page-break-inside|page-break-before|page-break-after|page|padding-top|padding-right|padding-left|padding-bottom|padding|overflow-Y|overflow-X|overflow|outline-width|outline-style|outline-color|outline|orphans|min-width|min-height|max-width|max-height|marks|marker-offset|margin-top|margin-right|margin-left|margin-bottom|margin|list-style-type|list-style-position|list-style-image|list-style|line-height|line-break|letter-spacing|left|layout-grid-type|layout-grid-mode|layout-grid-line|layout-grid-char-spacing|layout-grid-char|layout-grid|layout-flow|layer-background-image|layer-background-color|include-source|ime-mode|height|font-weight|font-variant|font-style|font-stretch|font-size-adjust|font-size|font-family|font|float|filter|empty-cells|elevation|display|direction|cursor|cue-before|cue-after|cue|counter-reset|counter-increment|content|color|clip|clear|caption-side|bottom|border-width|border-top-width|border-top-style|border-top-color|border-top|border-style|border-spacing|border-right-width|border-right-style|border-right-color|border-right|border-left-width|border-left-style|border-left-color|border-left|border-color|border-collapse|border-bottom-width|border-bottom-style|border-bottom-color|border-bottom|border|behavior|background-repeat|background-position-y|background-position-x|background-position|background-image|background-color|background-attachment|background|azimuth|accelerator)\s*:/ | ||
318 | + , _style: "color: #330066;" | ||
319 | + } | ||
320 | + , special: { | ||
321 | + _match: /\b(?:-use-link-source|-set-link-source|-replace|-moz-user-select|-moz-user-modify|-moz-user-input|-moz-user-focus|-moz-outline-width|-moz-outline-style|-moz-outline-color|-moz-outline|-moz-opacity|-moz-border-top-colors|-moz-border-right-colors|-moz-border-radius-topright|-moz-border-radius-topleft|-moz-border-radius-bottomright|-moz-border-radius-bottomleft|-moz-border-radius|-moz-border-left-colors|-moz-border-bottom-colors|-moz-binding)\s*:/ | ||
322 | + , _style: "color: #330066; text-decoration: underline;" | ||
323 | + } | ||
324 | + , url: { | ||
325 | + _match: /\b(url\s*\()([^)]+)(\))/ | ||
326 | + , _replace: "<span class='url'>$1</span>$2<span class='url'>$3</span>" | ||
327 | + } | ||
328 | + , value: { | ||
329 | + _match: /\b(?:xx-small|xx-large|x-soft|x-small|x-slow|x-low|x-loud|x-large|x-high|x-fast|wider|wait|w-resize|visible|url|uppercase|upper-roman|upper-latin|upper-alpha|underline|ultra-expanded|ultra-condensed|tv|tty|transparent|top|thin|thick|text-top|text-bottom|table-row-group|table-row|table-header-group|table-footer-group|table-column-group|table-column|table-cell|table-caption|sw-resize|super|sub|status-bar|static|square|spell-out|speech|solid|soft|smaller|small-caption|small-caps|small|slower|slow|silent|show|separate|semi-expanded|semi-condensed|se-resize|scroll|screen|s-resize|run-in|rtl|rightwards|right-side|right|ridge|rgb|repeat-y|repeat-x|repeat|relative|projection|print|pre|portrait|pointer|overline|outside|outset|open-quote|once|oblique|nw-resize|nowrap|normal|none|no-repeat|no-open-quote|no-close-quote|ne-resize|narrower|n-resize|move|mix|middle|message-box|medium|marker|ltr|lowercase|lower-roman|lower-latin|lower-greek|lower-alpha|lower|low|loud|local|list-item|line-through|lighter|level|leftwards|left-side|left|larger|large|landscape|justify|italic|invert|inside|inset|inline-table|inline|icon|higher|high|hide|hidden|help|hebrew|handheld|groove|format|fixed|faster|fast|far-right|far-left|fantasy|extra-expanded|extra-condensed|expanded|embossed|embed|e-resize|double|dotted|disc|digits|default|decimal-leading-zero|decimal|dashed|cursive|crosshair|cross|crop|counters|counter|continuous|condensed|compact|collapse|code|close-quote|circle|center-right|center-left|center|caption|capitalize|braille|bottom|both|bolder|bold|block|blink|bidi-override|below|behind|baseline|avoid|auto|aural|attr|armenian|always|all|absolute|above)\b/ | ||
330 | + , _style: "color: #3366FF;" | ||
331 | + } | ||
332 | + , string: { | ||
333 | + _match: /(?:\'[^\'\\\n]*(?:\\.[^\'\\\n]*)*\')|(?:\"[^\"\\\n]*(?:\\.[^\"\\\n]*)*\")/ | ||
334 | + , _style: "color: teal;" | ||
335 | + } | ||
336 | + , number: { | ||
337 | + _match: /(?:\b[+-]?(?:\d*\.?\d+|\d+\.?\d*))(?:%|(?:(?:px|pt|em|)\b))/ | ||
338 | + , _style: "color: red;" | ||
339 | + } | ||
340 | + , color : { | ||
341 | + _match: /(?:\#[a-fA-F0-9]{3,6})|\b(?:yellow|white|teal|silver|red|purple|olive|navy|maroon|lime|green|gray|fuchsia|blue|black|aqua|YellowGreen|Yellow|WhiteSmoke|White|Wheat|Violet|Turquoise|Tomato|Thistle|Teal|Tan|SteelBlue|SpringGreen|Snow|SlateGrey|SlateGray|SlateBlue|SkyBlue|Silver|Sienna|SeaShell|SeaGreen|SandyBrown|Salmon|SaddleBrown|RoyalBlue|RosyBrown|Red|Purple|PowderBlue|Plum|Pink|Peru|PeachPuff|PapayaWhip|PaleVioletRed|PaleTurquoise|PaleGreen|PaleGoldenRod|Orchid|OrangeRed|Orange|OliveDrab|Olive|OldLace|Navy|NavajoWhite|Moccasin|MistyRose|MintCream|MidnightBlue|MediumVioletRed|MediumTurquoise|MediumSpringGreen|MediumSlateBlue|MediumSeaGreen|MediumPurple|MediumOrchid|MediumBlue|MediumAquaMarine|Maroon|Magenta|Linen|LimeGreen|Lime|LightYellow|LightSteelBlue|LightSlateGrey|LightSlateGray|LightSkyBlue|LightSeaGreen|LightSalmon|LightPink|LightGrey|LightGreen|LightGray|LightGoldenRodYellow|LightCyan|LightCoral|LightBlue|LemonChiffon|LawnGreen|LavenderBlush|Lavender|Khaki|Ivory|Indigo|IndianRed|HotPink|HoneyDew|Grey|GreenYellow|Green|Gray|GoldenRod|Gold|GhostWhite|Gainsboro|Fuchsia|ForestGreen|FloralWhite|FireBrick|DodgerBlue|DimGrey|DimGray|DeepSkyBlue|DeepPink|Darkorange|DarkViolet|DarkTurquoise|DarkSlateGrey|DarkSlateGray|DarkSlateBlue|DarkSeaGreen|DarkSalmon|DarkRed|DarkOrchid|DarkOliveGreen|DarkMagenta|DarkKhaki|DarkGrey|DarkGreen|DarkGray|DarkGoldenRod|DarkCyan|DarkBlue|Cyan|Crimson|Cornsilk|CornflowerBlue|Coral|Chocolate|Chartreuse|CadetBlue|BurlyWood|Brown|BlueViolet|Blue|BlanchedAlmond|Black|Bisque|Beige|Azure|Aquamarine|Aqua|AntiqueWhite|AliceBlue)\b/ | ||
342 | + , _style: "color: green;" | ||
343 | + } | ||
344 | + } | ||
345 | +}; | ||
346 | + | ||
347 | + |
@@ -0,0 +1,284 @@ | @@ -0,0 +1,284 @@ | ||
1 | + | ||
2 | +/*! | ||
3 | +jQuery JSONView. | ||
4 | +Licensed under the MIT License. | ||
5 | + */ | ||
6 | +(function(jQuery) { | ||
7 | + var $, Collapser, JSONFormatter, JSONView; | ||
8 | + JSONFormatter = (function() { | ||
9 | + function JSONFormatter(options) { | ||
10 | + if (options == null) { | ||
11 | + options = {}; | ||
12 | + } | ||
13 | + this.options = options; | ||
14 | + } | ||
15 | + | ||
16 | + JSONFormatter.prototype.htmlEncode = function(html) { | ||
17 | + if (html !== null) { | ||
18 | + return html.toString().replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">"); | ||
19 | + } else { | ||
20 | + return ''; | ||
21 | + } | ||
22 | + }; | ||
23 | + | ||
24 | + JSONFormatter.prototype.jsString = function(s) { | ||
25 | + s = JSON.stringify(s).slice(1, -1); | ||
26 | + return this.htmlEncode(s); | ||
27 | + }; | ||
28 | + | ||
29 | + JSONFormatter.prototype.decorateWithSpan = function(value, className) { | ||
30 | + return "<span class=\"" + className + "\">" + (this.htmlEncode(value)) + "</span>"; | ||
31 | + }; | ||
32 | + | ||
33 | + JSONFormatter.prototype.valueToHTML = function(value, level) { | ||
34 | + var valueType; | ||
35 | + if (level == null) { | ||
36 | + level = 0; | ||
37 | + } | ||
38 | + valueType = Object.prototype.toString.call(value).match(/\s(.+)]/)[1].toLowerCase(); | ||
39 | + return this["" + valueType + "ToHTML"].call(this, value, level); | ||
40 | + }; | ||
41 | + | ||
42 | + JSONFormatter.prototype.nullToHTML = function(value) { | ||
43 | + return this.decorateWithSpan('null', 'null'); | ||
44 | + }; | ||
45 | + | ||
46 | + JSONFormatter.prototype.numberToHTML = function(value) { | ||
47 | + return this.decorateWithSpan(value, 'num'); | ||
48 | + }; | ||
49 | + | ||
50 | + JSONFormatter.prototype.stringToHTML = function(value) { | ||
51 | + var multilineClass, newLinePattern; | ||
52 | + if (/^(http|https|file):\/\/[^\s]+$/i.test(value)) { | ||
53 | + return "<a href=\"" + (this.htmlEncode(value)) + "\"><span class=\"q\">\"</span>" + (this.jsString(value)) + "<span class=\"q\">\"</span></a>"; | ||
54 | + } else { | ||
55 | + multilineClass = ''; | ||
56 | + value = this.jsString(value); | ||
57 | + if (this.options.nl2br) { | ||
58 | + newLinePattern = /([^>\\r\\n]?)(\\r\\n|\\n\\r|\\r|\\n)/g; | ||
59 | + if (newLinePattern.test(value)) { | ||
60 | + multilineClass = ' multiline'; | ||
61 | + value = (value + '').replace(newLinePattern, '$1' + '<br />'); | ||
62 | + } | ||
63 | + } | ||
64 | + return "<span class=\"string" + multilineClass + "\">\"" + value + "\"</span>"; | ||
65 | + } | ||
66 | + }; | ||
67 | + | ||
68 | + JSONFormatter.prototype.booleanToHTML = function(value) { | ||
69 | + return this.decorateWithSpan(value, 'bool'); | ||
70 | + }; | ||
71 | + | ||
72 | + JSONFormatter.prototype.arrayToHTML = function(array, level) { | ||
73 | + var collapsible, hasContents, index, numProps, output, value, _i, _len; | ||
74 | + if (level == null) { | ||
75 | + level = 0; | ||
76 | + } | ||
77 | + hasContents = false; | ||
78 | + output = ''; | ||
79 | + numProps = array.length; | ||
80 | + for (index = _i = 0, _len = array.length; _i < _len; index = ++_i) { | ||
81 | + value = array[index]; | ||
82 | + hasContents = true; | ||
83 | + output += '<li>' + this.valueToHTML(value, level + 1); | ||
84 | + if (numProps > 1) { | ||
85 | + output += ','; | ||
86 | + } | ||
87 | + output += '</li>'; | ||
88 | + numProps--; | ||
89 | + } | ||
90 | + if (hasContents) { | ||
91 | + collapsible = level === 0 ? '' : ' collapsible'; | ||
92 | + return "[<ul class=\"array level" + level + collapsible + "\">" + output + "</ul>]"; | ||
93 | + } else { | ||
94 | + return '[ ]'; | ||
95 | + } | ||
96 | + }; | ||
97 | + | ||
98 | + JSONFormatter.prototype.objectToHTML = function(object, level) { | ||
99 | + var collapsible, hasContents, key, numProps, output, prop, value; | ||
100 | + if (level == null) { | ||
101 | + level = 0; | ||
102 | + } | ||
103 | + hasContents = false; | ||
104 | + output = ''; | ||
105 | + numProps = 0; | ||
106 | + for (prop in object) { | ||
107 | + numProps++; | ||
108 | + } | ||
109 | + for (prop in object) { | ||
110 | + value = object[prop]; | ||
111 | + hasContents = true; | ||
112 | + key = this.options.escape ? this.jsString(prop) : prop; | ||
113 | + output += "<li><span class=\"prop\"><span class=\"q\">\"</span>" + key + "<span class=\"q\">\"</span></span>: " + (this.valueToHTML(value, level + 1)); | ||
114 | + if (numProps > 1) { | ||
115 | + output += ','; | ||
116 | + } | ||
117 | + output += '</li>'; | ||
118 | + numProps--; | ||
119 | + } | ||
120 | + if (hasContents) { | ||
121 | + collapsible = level === 0 ? '' : ' collapsible'; | ||
122 | + return "{<ul class=\"obj level" + level + collapsible + "\">" + output + "</ul>}"; | ||
123 | + } else { | ||
124 | + return '{ }'; | ||
125 | + } | ||
126 | + }; | ||
127 | + | ||
128 | + JSONFormatter.prototype.jsonToHTML = function(json) { | ||
129 | + return "<div class=\"jsonview\">" + (this.valueToHTML(json)) + "</div>"; | ||
130 | + }; | ||
131 | + | ||
132 | + return JSONFormatter; | ||
133 | + | ||
134 | + })(); | ||
135 | + (typeof module !== "undefined" && module !== null) && (module.exports = JSONFormatter); | ||
136 | + Collapser = (function() { | ||
137 | + function Collapser() {} | ||
138 | + | ||
139 | + Collapser.bindEvent = function(item, options) { | ||
140 | + var collapser; | ||
141 | + collapser = document.createElement('div'); | ||
142 | + collapser.className = 'collapser'; | ||
143 | + collapser.innerHTML = options.collapsed ? '+' : '-'; | ||
144 | + collapser.addEventListener('click', (function(_this) { | ||
145 | + return function(event) { | ||
146 | + return _this.toggle(event.target, options); | ||
147 | + }; | ||
148 | + })(this)); | ||
149 | + item.insertBefore(collapser, item.firstChild); | ||
150 | + if (options.collapsed) { | ||
151 | + return this.collapse(collapser); | ||
152 | + } | ||
153 | + }; | ||
154 | + | ||
155 | + Collapser.expand = function(collapser) { | ||
156 | + var ellipsis, target; | ||
157 | + target = this.collapseTarget(collapser); | ||
158 | + if (target.style.display === '') { | ||
159 | + return; | ||
160 | + } | ||
161 | + ellipsis = target.parentNode.getElementsByClassName('ellipsis')[0]; | ||
162 | + target.parentNode.removeChild(ellipsis); | ||
163 | + target.style.display = ''; | ||
164 | + return collapser.innerHTML = '-'; | ||
165 | + }; | ||
166 | + | ||
167 | + Collapser.collapse = function(collapser) { | ||
168 | + var ellipsis, target; | ||
169 | + target = this.collapseTarget(collapser); | ||
170 | + if (target.style.display === 'none') { | ||
171 | + return; | ||
172 | + } | ||
173 | + target.style.display = 'none'; | ||
174 | + ellipsis = document.createElement('span'); | ||
175 | + ellipsis.className = 'ellipsis'; | ||
176 | + ellipsis.innerHTML = ' … '; | ||
177 | + target.parentNode.insertBefore(ellipsis, target); | ||
178 | + return collapser.innerHTML = '+'; | ||
179 | + }; | ||
180 | + | ||
181 | + Collapser.toggle = function(collapser, options) { | ||
182 | + var action, collapsers, target, _i, _len, _results; | ||
183 | + if (options == null) { | ||
184 | + options = {}; | ||
185 | + } | ||
186 | + target = this.collapseTarget(collapser); | ||
187 | + action = target.style.display === 'none' ? 'expand' : 'collapse'; | ||
188 | + if (options.recursive_collapser) { | ||
189 | + collapsers = collapser.parentNode.getElementsByClassName('collapser'); | ||
190 | + _results = []; | ||
191 | + for (_i = 0, _len = collapsers.length; _i < _len; _i++) { | ||
192 | + collapser = collapsers[_i]; | ||
193 | + _results.push(this[action](collapser)); | ||
194 | + } | ||
195 | + return _results; | ||
196 | + } else { | ||
197 | + return this[action](collapser); | ||
198 | + } | ||
199 | + }; | ||
200 | + | ||
201 | + Collapser.collapseTarget = function(collapser) { | ||
202 | + var target, targets; | ||
203 | + targets = collapser.parentNode.getElementsByClassName('collapsible'); | ||
204 | + if (!targets.length) { | ||
205 | + return; | ||
206 | + } | ||
207 | + return target = targets[0]; | ||
208 | + }; | ||
209 | + | ||
210 | + return Collapser; | ||
211 | + | ||
212 | + })(); | ||
213 | + $ = jQuery; | ||
214 | + JSONView = { | ||
215 | + collapse: function(el) { | ||
216 | + if (el.innerHTML === '-') { | ||
217 | + return Collapser.collapse(el); | ||
218 | + } | ||
219 | + }, | ||
220 | + expand: function(el) { | ||
221 | + if (el.innerHTML === '+') { | ||
222 | + return Collapser.expand(el); | ||
223 | + } | ||
224 | + }, | ||
225 | + toggle: function(el) { | ||
226 | + return Collapser.toggle(el); | ||
227 | + } | ||
228 | + }; | ||
229 | + return $.fn.JSONView = function() { | ||
230 | + var args, defaultOptions, formatter, json, method, options, outputDoc; | ||
231 | + args = arguments; | ||
232 | + if (JSONView[args[0]] != null) { | ||
233 | + method = args[0]; | ||
234 | + return this.each(function() { | ||
235 | + var $this, level; | ||
236 | + $this = $(this); | ||
237 | + if (args[1] != null) { | ||
238 | + level = args[1]; | ||
239 | + return $this.find(".jsonview .collapsible.level" + level).siblings('.collapser').each(function() { | ||
240 | + return JSONView[method](this); | ||
241 | + }); | ||
242 | + } else { | ||
243 | + return $this.find('.jsonview > ul > li .collapsible').siblings('.collapser').each(function() { | ||
244 | + return JSONView[method](this); | ||
245 | + }); | ||
246 | + } | ||
247 | + }); | ||
248 | + } else { | ||
249 | + json = args[0]; | ||
250 | + options = args[1] || {}; | ||
251 | + defaultOptions = { | ||
252 | + collapsed: false, | ||
253 | + nl2br: false, | ||
254 | + recursive_collapser: false, | ||
255 | + escape: true | ||
256 | + }; | ||
257 | + options = $.extend(defaultOptions, options); | ||
258 | + formatter = new JSONFormatter({ | ||
259 | + nl2br: options.nl2br, | ||
260 | + escape: options.escape | ||
261 | + }); | ||
262 | + if (Object.prototype.toString.call(json) === '[object String]') { | ||
263 | + json = JSON.parse(json); | ||
264 | + } | ||
265 | + outputDoc = formatter.jsonToHTML(json); | ||
266 | + return this.each(function() { | ||
267 | + var $this, item, items, _i, _len, _results; | ||
268 | + $this = $(this); | ||
269 | + $this.html(outputDoc); | ||
270 | + items = $this[0].getElementsByClassName('collapsible'); | ||
271 | + _results = []; | ||
272 | + for (_i = 0, _len = items.length; _i < _len; _i++) { | ||
273 | + item = items[_i]; | ||
274 | + if (item.parentNode.nodeName === 'LI') { | ||
275 | + _results.push(Collapser.bindEvent(item.parentNode, options)); | ||
276 | + } else { | ||
277 | + _results.push(void 0); | ||
278 | + } | ||
279 | + } | ||
280 | + return _results; | ||
281 | + }); | ||
282 | + } | ||
283 | + }; | ||
284 | +})(jQuery); |
var/httpd/htdocs/js/thirdparty/alpaca/alpaca-full.min.js
@@ -22736,19 +22736,19 @@ this["HandlebarsPrecompiled"]["web-edit"]["wizard"] = Handlebars.template({"1":f | @@ -22736,19 +22736,19 @@ this["HandlebarsPrecompiled"]["web-edit"]["wizard"] = Handlebars.template({"1":f | ||
22736 | 22736 | ||
22737 | if (self.view.type !== "display") | 22737 | if (self.view.type !== "display") |
22738 | { | 22738 | { |
22739 | - if ($.fn.datetimepicker) | 22739 | + if ($.fn.datepicker) |
22740 | { | 22740 | { |
22741 | - self.getControlEl().datetimepicker(self.options.picker); | 22741 | + self.picker = self.getControlEl().datepicker(self.options.picker); |
22742 | 22742 | ||
22743 | - self.picker = self.getControlEl().data("DateTimePicker"); | 22743 | + //self.picker = self.getControlEl().data("DateTimePicker"); |
22744 | if (self.picker && self.options.dateFormat) | 22744 | if (self.picker && self.options.dateFormat) |
22745 | { | 22745 | { |
22746 | - self.picker.format(self.options.dateFormat); | ||
22747 | - } | ||
22748 | - if (self.picker) | ||
22749 | - { | ||
22750 | - self.options.dateFormat = self.picker.format(); | 22746 | + self.picker.datepicker( "option", "dateFormat", self.options.dateFormat ); |
22751 | } | 22747 | } |
22748 | + //if (self.picker) | ||
22749 | + //{ | ||
22750 | + // self.options.dateFormat = self.picker.format(); | ||
22751 | + //} | ||
22752 | 22752 | ||
22753 | // with date-time picker, trigger change using plugin | 22753 | // with date-time picker, trigger change using plugin |
22754 | self.getFieldEl().on("dp.change", function(e) { | 22754 | self.getFieldEl().on("dp.change", function(e) { |
@@ -29572,7 +29572,7 @@ this["HandlebarsPrecompiled"]["web-edit"]["wizard"] = Handlebars.template({"1":f | @@ -29572,7 +29572,7 @@ this["HandlebarsPrecompiled"]["web-edit"]["wizard"] = Handlebars.template({"1":f | ||
29572 | "parent": "jqueryui-edit", | 29572 | "parent": "jqueryui-edit", |
29573 | "type": "create", | 29573 | "type": "create", |
29574 | "title": "Create view for jQuery UI", | 29574 | "title": "Create view for jQuery UI", |
29575 | - "displayReadonly": false | 29575 | + "displayReadonly": true |
29576 | }); | 29576 | }); |
29577 | 29577 | ||
29578 | Alpaca.registerView({ | 29578 | Alpaca.registerView({ |
var/httpd/htdocs/skins/Agent/default/css/jquery.jsonview.css
0 → 100755
@@ -0,0 +1,52 @@ | @@ -0,0 +1,52 @@ | ||
1 | +@charset "UTF-8"; | ||
2 | +.jsonview { | ||
3 | + font-family: monospace; | ||
4 | + font-size: 1.1em; | ||
5 | + white-space: pre-wrap; } | ||
6 | + .jsonview .prop { | ||
7 | + font-weight: bold; } | ||
8 | + .jsonview .null { | ||
9 | + color: red; } | ||
10 | + .jsonview .bool { | ||
11 | + color: blue; } | ||
12 | + .jsonview .num { | ||
13 | + color: blue; } | ||
14 | + .jsonview .string { | ||
15 | + color: green; | ||
16 | + white-space: pre-wrap; } | ||
17 | + .jsonview .string.multiline { | ||
18 | + display: inline-block; | ||
19 | + vertical-align: text-top; } | ||
20 | + .jsonview .collapser { | ||
21 | + position: absolute; | ||
22 | + left: -1em; | ||
23 | + cursor: pointer; } | ||
24 | + .jsonview .collapsible { | ||
25 | + transition: height 1.2s; | ||
26 | + transition: width 1.2s; } | ||
27 | + .jsonview .collapsible.collapsed { | ||
28 | + height: .8em; | ||
29 | + width: 1em; | ||
30 | + display: inline-block; | ||
31 | + overflow: hidden; | ||
32 | + margin: 0; } | ||
33 | + .jsonview .collapsible.collapsed:before { | ||
34 | + content: "…"; | ||
35 | + width: 1em; | ||
36 | + margin-left: .2em; } | ||
37 | + .jsonview .collapser.collapsed { | ||
38 | + transform: rotate(0deg); } | ||
39 | + .jsonview .q { | ||
40 | + display: inline-block; | ||
41 | + width: 0px; | ||
42 | + color: transparent; } | ||
43 | + .jsonview li { | ||
44 | + position: relative; } | ||
45 | + .jsonview ul { | ||
46 | + list-style: none; | ||
47 | + margin: 0 0 0 2em; | ||
48 | + padding: 0; } | ||
49 | + .jsonview h1 { | ||
50 | + font-size: 1.2em; } | ||
51 | + | ||
52 | +/*# sourceMappingURL=jquery.jsonview.css.map */ |