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 | 23 | <JavaScript>thirdparty/alpaca/alpaca-full.min.js</JavaScript> |
24 | 24 | <JavaScript>thirdparty/alpaca/jquery.sumoselect.js</JavaScript> |
25 | 25 | <JavaScript>thirdparty/alpaca/datatables.js</JavaScript> |
26 | + <JavaScript>thirdparty/maskedinput/jquery.maskedinput.min.js</JavaScript> | |
26 | 27 | <JavaScript>thirdparty/jquery-validate-1.13.0/jquery.validate.js</JavaScript> |
27 | 28 | <CSS>alpaca/alpaca-newticketwizard.css</CSS> |
28 | 29 | <CSS>alpaca/sumoselect.css</CSS> |
... | ... | @@ -43,6 +44,13 @@ |
43 | 44 | <Description>Admin</Description> |
44 | 45 | <Title>Service forms</Title> |
45 | 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 | 54 | <NavBarModule> |
47 | 55 | <Module>Kernel::Output::HTML::NavBarModuleAdmin</Module> |
48 | 56 | <Name>Service forms</Name> |
... | ... | @@ -267,6 +275,7 @@ |
267 | 275 | <JavaScript>thirdparty/alpaca/jquery.sumoselect.js</JavaScript> |
268 | 276 | <JavaScript>thirdparty/alpaca/datatables.js</JavaScript> |
269 | 277 | <JavaScript>thirdparty/jquery-validate-1.13.0/jquery.validate.js</JavaScript> |
278 | + <JavaScript>thirdparty/maskedinput/jquery.maskedinput.min.js</JavaScript> | |
270 | 279 | <CSS>alpaca/alpaca-newticketwizard.css</CSS> |
271 | 280 | <CSS>alpaca/sumoselect.css</CSS> |
272 | 281 | <CSS>alpaca/alpaca-jqueryui-newticketwizard.css</CSS> | ... | ... |
Kernel/Modules/NewTicketWizard.pm
... | ... | @@ -158,6 +158,8 @@ sub Run { |
158 | 158 | } |
159 | 159 | elsif ( $ParamObject->GetParam( Param => "Subaction" ) eq "GetFormJSON" ) { |
160 | 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 | 165 | else { |
... | ... | @@ -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 | 257 | sub GetForm { |
231 | 258 | my ( $Self, %Param ) = @_; |
232 | 259 | ... | ... |
Kernel/Modules/NewTicketWizardPublic.pm
... | ... | @@ -163,7 +163,10 @@ sub Run { |
163 | 163 | } |
164 | 164 | elsif ( $ParamObject->GetParam( Param => "Subaction" ) eq "GetFormJSON" ) { |
165 | 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 | 171 | else { |
169 | 172 | my ( $schema, $fields ) = $Self->GetForm(); |
... | ... | @@ -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 | 235 | sub GetFormJSON { |
207 | 236 | my ( $Self, %Param ) = @_; |
208 | 237 | my %serviceForm; | ... | ... |
Kernel/Modules/NewTicketWizardServiceForm.pm
... | ... | @@ -67,6 +67,7 @@ sub Run { |
67 | 67 | $Data{Form} = $serviceForm{Form}; |
68 | 68 | $Data{Schema} = $serviceForm{Schema}; |
69 | 69 | $Data{FixedValues} = $serviceForm{FixedValues}; |
70 | + $Data{CustomProps} = $serviceForm{CustomProps}; | |
70 | 71 | $Data{ServiceID} = $ParamObject->GetParam( Param => "ServiceID" ); |
71 | 72 | $Data{QueueID} = $ParamObject->GetParam( Param => "QueueID" ); |
72 | 73 | |
... | ... | @@ -94,6 +95,7 @@ sub Run { |
94 | 95 | Introduction => $ParamObject->GetParam( Param => "Introduction" ), |
95 | 96 | Form => $ParamObject->GetParam( Param => "Form" ), |
96 | 97 | Schema => $ParamObject->GetParam( Param => "Schema" ), |
98 | + CustomProps => $ParamObject->GetParam( Param => "CustomProps" ), | |
97 | 99 | FixedValues => $ParamObject->GetParam( Param => "FixedValues" ), |
98 | 100 | ); |
99 | 101 | } else { |
... | ... | @@ -102,6 +104,7 @@ sub Run { |
102 | 104 | Introduction => $ParamObject->GetParam( Param => "Introduction" ), |
103 | 105 | Form => $ParamObject->GetParam( Param => "Form" ), |
104 | 106 | Schema => $ParamObject->GetParam( Param => "Schema" ), |
107 | + CustomProps => $ParamObject->GetParam( Param => "CustomProps" ), | |
105 | 108 | FixedValues => $ParamObject->GetParam( Param => "FixedValues" ), |
106 | 109 | ); |
107 | 110 | } | ... | ... |
Kernel/Output/HTML/Standard/CustomerFooterNTWUFSC.tt
... | ... | @@ -7,7 +7,7 @@ |
7 | 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 | 12 | <div style="font-size: 0px;"> |
13 | 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 | 31 | </div> |
32 | 32 | <div class="Clear"></div> |
33 | 33 | |
34 | - <label for="Form">[% Translate("Form") | html %]: </label> | |
34 | + <label for="FormUI">[% Translate("Form") | html %]: </label> | |
35 | 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 | 41 | </div> |
38 | 42 | <div class="Clear"></div> |
39 | 43 | |
40 | 44 | <label for="Schema">[% Translate("Schema") | html %]: </label> |
41 | 45 | <div class="Field"> |
42 | 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 | 49 | </div> |
44 | 50 | <div class="Clear"></div> |
45 | 51 | |
... | ... | @@ -49,6 +55,16 @@ |
49 | 55 | </div> |
50 | 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 | 68 | <div class="Field SpacingTop"> |
53 | 69 | <button class="Primary" type="submit" value="[% Translate("Submit") | html %]">[% Translate("Submit") | html %]</button> |
54 | 70 | [% Translate("or") | html %] |
... | ... | @@ -59,3 +75,51 @@ |
59 | 75 | |
60 | 76 | </form> |
61 | 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 | 126 | \ No newline at end of file | ... | ... |
Kernel/System/ServiceForm.pm
... | ... | @@ -44,7 +44,7 @@ sub GetServiceForm { |
44 | 44 | |
45 | 45 | # get service form from db |
46 | 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 | 48 | Bind => [ \$Param{ServiceID} ], |
49 | 49 | Limit => 1, |
50 | 50 | ); |
... | ... | @@ -57,6 +57,7 @@ sub GetServiceForm { |
57 | 57 | $ServiceData{Form} = $Row[2]; |
58 | 58 | $ServiceData{Schema} = $Row[3]; |
59 | 59 | $ServiceData{FixedValues} = $Row[4]; |
60 | + $ServiceData{CustomProps} = $Row[5]; | |
60 | 61 | } |
61 | 62 | |
62 | 63 | return %ServiceData; |
... | ... | @@ -76,7 +77,7 @@ sub GetServiceFormForQueue { |
76 | 77 | |
77 | 78 | # get service form from db |
78 | 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 | 81 | Bind => [ \$Param{ServiceID}, \$Param{QueueID} ], |
81 | 82 | Limit => 1, |
82 | 83 | ); |
... | ... | @@ -89,6 +90,7 @@ sub GetServiceFormForQueue { |
89 | 90 | $ServiceData{Form} = $Row[2]; |
90 | 91 | $ServiceData{Schema} = $Row[3]; |
91 | 92 | $ServiceData{FixedValues} = $Row[4]; |
93 | + $ServiceData{CustomProps} = $Row[5]; | |
92 | 94 | } |
93 | 95 | |
94 | 96 | return %ServiceData; |
... | ... | @@ -119,14 +121,14 @@ sub SaveServiceForm { |
119 | 121 | my $update = ($serviceForm{ServiceID}); |
120 | 122 | |
121 | 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 | 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 | 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 | 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 | 162 | my $update = ($serviceForm{ServiceID}); |
161 | 163 | |
162 | 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 | 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 | 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 | 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 | 1 | <?xml version="1.0" encoding="utf-8" ?> |
2 | 2 | <otrs_package version="1.0"> |
3 | 3 | <Name>NewTicketWizard</Name> |
4 | - <Version>1.9.3</Version> | |
4 | + <Version>1.9.11</Version> | |
5 | 5 | <Framework>4.0.x</Framework> |
6 | 6 | <Vendor>SeTIC</Vendor> |
7 | 7 | <URL>http://www.setic.ufsc.br</URL> |
... | ... | @@ -18,7 +18,12 @@ |
18 | 18 | <ChangeLog version="1.8.1">Layout bug fix</ChangeLog> |
19 | 19 | <ChangeLog version="1.8.2">Multiselect component</ChangeLog> |
20 | 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 | 27 | <IntroInstall Type="post" Title="Thank you">New Ticket Wizard module installed successfully!</IntroInstall> |
23 | 28 | <BuildDate>?</BuildDate> |
24 | 29 | <BuildHost>?</BuildHost> |
... | ... | @@ -46,8 +51,15 @@ |
46 | 51 | |
47 | 52 | <File Permission="644" Location="var/httpd/htdocs/js/thirdparty/alpaca/alpaca-full.min.js"></File> |
48 | 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 | 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 | 64 | <File Permission="644" Location="var/httpd/htdocs/skins/Customer/default/css/alpaca/images/alpaca-icons.png"></File> |
53 | 65 | <File Permission="644" Location="var/httpd/htdocs/skins/Customer/default/css/alpaca/images/date.png"></File> |
... | ... | @@ -61,6 +73,10 @@ |
61 | 73 | <File Permission="644" Location="var/httpd/htdocs/skins/Customer/default/css/alpaca/alpaca-jqueryui-newticketwizard.css"></File> |
62 | 74 | <File Permission="644" Location="var/httpd/htdocs/skins/Customer/default/css/alpaca/alpaca-newticketwizard.css"></File> |
63 | 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 | 82 | </Filelist> | ... | ... |
NewTicketWizardUFSC.sopm
1 | 1 | <?xml version="1.0" encoding="utf-8" ?> |
2 | 2 | <otrs_package version="1.0"> |
3 | 3 | <Name>NewTicketWizardUFSC</Name> |
4 | - <Version>1.0.0</Version> | |
4 | + <Version>1.0.1</Version> | |
5 | 5 | <Framework>4.0.x</Framework> |
6 | 6 | <Vendor>SeTIC</Vendor> |
7 | 7 | <URL>http://www.setic.ufsc.br</URL> |
8 | 8 | <License>GPLv2</License> |
9 | 9 | <Description>NewTicket Wizard Module Template for UFSC</Description> |
10 | 10 | <ChangeLog version="1.0.0">First version</ChangeLog> |
11 | + <ChangeLog version="1.0.1">Fix for footer</ChangeLog> | |
11 | 12 | <IntroInstall Type="post" Title="Thank you">New Ticket Wizard UFSC Template module installed successfully!</IntroInstall> |
12 | 13 | <BuildDate>?</BuildDate> |
13 | 14 | <BuildHost>?</BuildHost> | ... | ... |
... | ... | @@ -2,5 +2,7 @@ alter table service_form drop foreign key FK_service_form_service_id_id; |
2 | 2 | alter table service_form drop primary key; |
3 | 3 | alter table service_form add id int auto_increment not null primary key; |
4 | 4 | alter table service_form add queue_id int; |
5 | - | |
6 | 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 | 2 | * Variables |
3 | 3 | */ |
4 | 4 | var formAlpaca; |
5 | +var activeQueue; | |
5 | 6 | |
6 | 7 | |
7 | 8 | /** |
... | ... | @@ -79,7 +80,78 @@ var postRenderCallback = function(form) { |
79 | 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 | 156 | function carregaForm(dataForm, sendText, action, queue) { |
85 | 157 | var url = "/otrs/customer.pl?Action=NewTicketWizard;Subaction=GetFormJSON" + queue; |
... | ... | @@ -88,6 +160,7 @@ function carregaForm(dataForm, sendText, action, queue) { |
88 | 160 | formAlpaca.destroy(); |
89 | 161 | } |
90 | 162 | |
163 | + activeQueue = queue; | |
91 | 164 | url += ";ServiceID=" + $("#ServiceID").val(); |
92 | 165 | |
93 | 166 | $.getJSON(url, function(data) { |
... | ... | @@ -109,9 +182,11 @@ function carregaForm(dataForm, sendText, action, queue) { |
109 | 182 | |
110 | 183 | $("[name='submit']").css("font-size", "18px"); |
111 | 184 | |
185 | + | |
186 | + | |
112 | 187 | |
113 | 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 | 218 | //$("#formTicket").find("select").val(""); |
144 | 219 | } |
145 | 220 | |
221 | + activeQueue = queue; | |
146 | 222 | url += ";ServiceID=" + $("#ServiceID").val(); |
147 | 223 | |
148 | 224 | $.getJSON(url, function(data) { |
... | ... | @@ -154,14 +230,14 @@ function carregaFormPublic(dataForm, sendText, action, queue) { |
154 | 230 | "data": dataForm, |
155 | 231 | "schema": buildSchema(data[0]), |
156 | 232 | "options": buildOptions(data[1], sendText, action), |
157 | - "postRender": postRenderCallback, | |
233 | + "postRender": postRenderCallbackPublic, | |
158 | 234 | "view": "jqueryui-create", |
159 | 235 | "ui": "jquery-ui" |
160 | 236 | }); |
161 | 237 | |
162 | 238 | |
163 | 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 @@ |
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 @@ |
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 | 66 | \ No newline at end of file | ... | ... |
... | ... | @@ -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 @@ |
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 | 22736 | |
22737 | 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 | 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 | 22753 | // with date-time picker, trigger change using plugin |
22754 | 22754 | self.getFieldEl().on("dp.change", function(e) { |
... | ... | @@ -29572,7 +29572,7 @@ this["HandlebarsPrecompiled"]["web-edit"]["wizard"] = Handlebars.template({"1":f |
29572 | 29572 | "parent": "jqueryui-edit", |
29573 | 29573 | "type": "create", |
29574 | 29574 | "title": "Create view for jQuery UI", |
29575 | - "displayReadonly": false | |
29575 | + "displayReadonly": true | |
29576 | 29576 | }); |
29577 | 29577 | |
29578 | 29578 | Alpaca.registerView({ | ... | ... |
var/httpd/htdocs/skins/Agent/default/css/jquery.jsonview.css
0 → 100755
... | ... | @@ -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 */ | ... | ... |