-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathREADME.html
1310 lines (1110 loc) · 52.6 KB
/
README.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="generator" content="HTML Tidy for Linux/x86 (vers 25 March 2009), see www.w3.org" />
<meta http-equiv="content-Type" content="text/html; charset=us-ascii" />
<title>README</title>
<style type="text/css">
/*<![CDATA[*/
body {
margin: 0px 8% 4em 8%;
padding-top: 18pt;
background-color:white;
color:black;
text-align:justify;
}
.menu li {
list-style:none;
}
.menu, h1,h2 {
color:#990000;
}
h1 a, h2 a, h3, h3 a {
color:#000;
}
.menu a {
color:#000;
text-decoration:none;
border-bottom:1px dotted black;
}
li {
line-height:2em;
}
.envadrouille {
font-style:italic;
}
.title {
font-family:Georgia, "Times New Roman", Times, serif;
line-height:1.2;
font-size:4.4em;
text-align:center;
}
.language {
}
/* CSS Tree menu styles */
ol.tree
{
padding: 0 0 0 30px;
}
ol.tree li
{
list-style: none;
}
li.file
{
margin-left: -1px !important;
background: url(css/document.png) 0 7px no-repeat;
color: #000;
padding-left: 21px;
display: block;
position:relative;
}
li.file a
{
text-decoration: none;
}
ol.tree li label
{
background: url(css/folder-horizontal.png) 0px 7px no-repeat;
cursor: pointer;
display: block;
padding-left: 27px;
position:relative;
}
ol.tree .descr {
position:absolute;
left:180px;
color:#444;
font-style:italic;
font-size:12px;
}
.toolbar {
display:none!important;
}
.hidden {
display:none;
}
.visible {
display:block;
}
.visible-menu {
font-weight:bold;
}
/*]]>*/
</style>
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript">
//<![CDATA[
function hide(div) {
var d = document.getElementById(div);
d.style.display = 'none';
return false;
}
function showHide(div) {
var d = document.getElementById(div);
if(d.style.display == 'none')
d.style.display = 'block';
else
d.style.display = 'none';
return false;
}
//]]>
</script>
<script type="text/javascript">
//<![CDATA[
$(document).ready(function() {
var uid = 0;
function buildMenu(parent, div, rec, hid) {
if(rec > 2)
return;
var elts;
if(parent)
elts = $(parent).parent().find('h'+rec);
else
elts = $(document).find('h'+rec);
elts.each(function(id, v) {
uid++;
var text = $(v).text();
var num = ((hid)?(hid+'.'):'')+(id+1);
var link = text.toLowerCase().replace(/\s|, /g, '-');
$(v).html(num + ' <a name="no'+link+'">'+text+'<\/a>');
$(v).attr('id', "v"+link);
div.append('<li id="li_'+link+'">'+num+' <a href="#'+link+'">'+text+'<\/a><\/li><ul id="h'+rec+'_'+uid+'"><\/ul>');
$('#li_'+link+' a').click(function() { showElt(link); });
buildMenu(v, $('#h'+rec+'_'+uid), rec+1, num);
});
}
buildMenu(null, $('#mainmenu'), 1, null);
function showElt(id) {
$('.visible').removeClass('visible');
$('.visible-menu').removeClass('visible-menu');
$('#v'+id).parents().filter('.hidden').addClass('visible');
$('#v'+id).parent().find('.hidden').addClass('visible');
$('#li_'+id).addClass('visible-menu');
}
showElt(window.location.hash?(window.location.hash.replace('#', '')):'');
});
//]]>
</script>
<script type="text/javascript" src="js/shCore.js"></script>
<script type="text/javascript" src="js/shBrushJScript.js"></script>
<script type="text/javascript" src="js/shBrushCss.js"></script>
<script type="text/javascript" src="js/shBrushPhp.js"></script>
<script type="text/javascript" src="js/shBrushXml.js"></script>
<link href="css/shCore.css" rel="stylesheet" type="text/css" />
<link href="css/shThemeDefault.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div class="title">
EnVadrouille - Developers
</div>
<div id="en" class="language">
<ul id="mainmenu" class="menu"></ul>
<div class="hidden">
<h1>General information about EnVadrouille</h1>Here are some general information about EnVadrouille that might be useful to create themes and plugins.
<div class="hidden">
<h2>Available scripts</h2>In the gallery, you may safely assume that the following API will be automatically loaded:
<ul>
<li>jQuery v1.7</li>
<li>jQuery template plugin, see <a href="https://github.com/jquery/jquery-tmpl">https://github.com/jquery/jquery-tmpl</a></li>
<li>jQuery color animation plugin (you can animate background-color, using jQuery animate)</li>
<li>jQuery doTimeout plugin, see <a href="http://benalman.com/projects/jquery-dotimeout-plugin/">http://benalman.com/projects/jquery-dotimeout-plugin/</a></li>
<li>A custom script loader named $script, see below.</li>
</ul><br />
To know when an API has been loaded, use the $script API as follows:
<pre class="brush: js;">
$script("http://domain/foo.js", "foo", function() {
// code that will be executed once foo.js has been loaded
// this function is optional, you can call $script with only 2 arguments
});
$script.loaded(['foo', 'jquery'], function() {
// code that will get executed once foo and jquery have been loaded
});
</pre>
</div><br />
<div class="hidden">
<h2>Paths, thumbnails, jsons</h2>
<table>
<tr>
<td style="vertical-align:top;width:1000px;padding-right:20px;text-align:justify">
<ol class="tree">
<li>
<label>admin</label>
<ol>
<li><label>common <span class="descr">common php and js classes</span></label> <label>pages <span class="descr">plugins</span></label></li>
</ol><label>cache</label>
<ol>
<li>
<label>json</label>
<ol>
<li class="file">cache.json <span class="descr"> json containing the metadata of the index, <a href="#" onclick="return showHide('json-div');">click here</a> to see an example (content will appear bellow the list of files)</span></li>
<li><label>directoryX</label></li>
<li>
<ol>
<li class="file">cache.json <span class="descr">json containing the metadata of directoryX, <a href="#" onclick="return showHide('json-div');">click here</a> to see an example (content will appear bellow the list of files)</span></li>
</ol>
</li>
</ol><label>thumbs</label>
<ol>
<li>
<label>directoryX</label>
<ol>
<li class="file">picX_r.jpg <span class="descr">main thumbnail for picX; size configured in the admin</span></li>
<li class="file">picX_b.jpg <span class="descr">big thumbnail, width=350px, height depends on the original height</span></li>
<li class="file">picX_c.jpg <span class="descr">crop thumbnail, 200px*150px</span></li>
<li class="file">picX_m.jpg <span class="descr">small thumbnail, width=150px, height depends on the original height</span></li>
</ol>
</li>
</ol>
</li>
</ol><label>pics</label>
<ol>
<li>
<label>directoryX</label>
<ol>
<li class="file">mygpx.gpx</li>
<li class="file">picX.jpg</li>
<li class="file">vid.ogv</li>
<li class="file">vid.mp4 <span class="descr">vid.ogv and vid.mp4 are the same video with different codecs</span></li>
<li class="file">vid2.ogv</li>
</ol>
</li>
</ol><label>themes</label>
<ol>
<li><label>themeX</label></li>
</ol><label>scripts</label>
</li>
</ol>
</td>
<td></td>
</tr>
</table><br />
<div id="json-div" style="display:none;">
<pre class="brush: js;">
// See bellow for the description of the fields
// /cache/json/cache.json, the cache.json of the index of the gallery:
{
"dirs":[{"ID":0, "url":"directoryX", "thumbs":['picX_m.jpg'], "descr":"dir descr", starred:false}],
}
// /cache/json/directoryX/cache.json, the cache.json of directoryX:
{
"dirs":[],
"pics":[{"url":"picX.jpg", "original":true}],
"vids":[{"url":["vid.mp4", "vid.ogv"]}, {"url":["vid2.ogv"]}],
"gpx":["pics/directoryX/mygpx.gpx"],
"gpxtype":"terrain",
"descr":"dir descr",
}
// Format description
// All variables named foo* may be undefined
{
dirs*:[ // list of subdirectories
{
ID:<display order>, // e.g., 0
url:<name of the directory>, // e.g., 'subdirdirX'
thumbs:[<name of thumbs>], // e.g., ['index_m.jpg', '0_m.jpg']
// You can replace _m with _c or _b in your code
// to access thumbnails of different size
descr:<description>, // e.g., 'foobar'
starred:<true if the directory should be highlighted>,
}
],
pics*:[ // list of pictures
{
url:<name of the picture>, // e.g., foo.jpg
fullpath*:<path of the picture (if undefined, path=path of the gallery)>
original:true if the original picture is bigger than the _r thumbnail
}
],
vids*:[ // list of videos
{
url:[<nameS of the video>] // e.g., [foo.mp4, foo.ogv]
} // /!\ videos with same basename but different
// extensions are regrouped!
],
gpx*:[<PATH of the gpx files of the gallery>] or [],
gpxtype*:<map type, e.g., "terrain", "satellite" or "roadmap">
descr*:<description of the gallery>
}
</pre>
</div>
</div><br />
<br />
<br />
<br />
</div>
<div class="hidden">
<h1>Create a theme</h1>
<div style="display:inline-block;text-align:justify;">
If you start from an existing theme, creating your own theme might take you less than 5 minutes!<br />
<ul>
<li>Create a folder in the <i>/themes</i> directory of your EnVadrouille gallery with two files: <i>main.js</i> and <i>main.css</i>.</li>
<li>Once you have created these files with their minimal content (see bellow), update the administration options to add your theme to the gallery.</li>
<li>Go in the gallery and enjoy. If you want to update your theme, simply edit the .css and .js files (no need to go in the administration).</li>
</ul>Click on the files bellow to show the <b>minimal content</b> of the css and js files.<br />
</div>
<ol class="tree">
<li>
<label>themes</label>
<ol>
<li>
<label>mytheme</label>
<ol>
<li class="file"><a href="#" onclick="hide('theme-js'); return showHide('theme-css');">main.css</a> [click or download <a href="code/mytheme/main.css">full file</a>]</li>
<li class="file"><a href="#" onclick="hide('theme-css'); return showHide('theme-js');">main.js</a> [click or download <a href="code/mytheme/main.js">full file</a>]</li>
</ol>
</li>
</ol>
</li>
</ol>
<div id="theme-css" style="display:none;">
There are only two special requirement for the css file. Your css file MUST contain a rule <b>body</b> with a <i>background-color</i> and a <i>color</i> property.
<pre class="brush: css;">
body { /* mandatory */
background-color:#151515; /* mandatory */
color:#FFF; /* mandatory */
}
</pre>This rules are used by the administration to determine the background and foreground colors of your theme. No other rule is enforced. To know which css rules to create, you can either start from an existing theme or look inside the main EnVadrouille /index.html file to find the templates used by the gallery.<br />
<br />
The gallery will work with this single rule (but won't look nice...). The only feature that won't show up are maps because the map container has a default height of 0px. To show the maps, without any decoration, add these rules:
<pre class="brush: css;">
.gps {
position:relative;
}
.gpscanvas {
height:320px;
}
.gpscanvasbig {
height:800px;
}
.gpschart {
display:none; /* chart is hidden by default */
height:200px;
width:100%;
}
.gpsmapwrapper {
position:relative;
}
.gpsadvanced {
display:none; /* button to show charts will be
displayed automatically when
the gpx has been loaded */
position:absolute;
bottom:0px;
left:50%;
margin-left:-60px;
cursor:pointer;
display:none;
}
.gpsadvanced:before {
content:"STATS";
}
.gpsbigger {
display:none;
position:absolute;
bottom:0px;
left:50%;
cursor:pointer;
}
.gpsbigger:before {
content:"BIGGERMAP";
}
</pre>
</div>
<div id="theme-js" style="display:none;">
A theme must implement 8 JavaScript function. Most of these functions are called with a json argument described in section "1.2 Paths, thumbnails, jsons" (click on the link next to the 'cache.json' files). You should not alter this json because it might be used internally or by other themes.<br />
The simplest way to create this JavaScript file is to start from an existing theme.<br />
<pre class="brush: js;">
var myTheme = {
/*
* Boolean to tell whether you want the gallery to perform smooth
* transition between pages (fadeIn/fadeOut)
*/
animateContent : false,
/*
* Called on all pages, with or without an argument. May be used to display a breadcrumb or anything you want.
* @json: /!\ the json being displayed or *undefined* when performing a search
*/
showHeader:function(json) {
// Simplest code: do nothing.
},
/*
* Called multiple times on most pages to display content.
* @content the content to display (e.g., 'dirs', 'pics', 'vids', 'gpx', ...)
* @json the json being displayed
*/
showContent:function(content, json) {
switch(content) {
case 'dirs': return myTheme.showDirs(json);
case 'pics': return myTheme.showPics(json);
case 'vids': return myTheme.showVids(json);
default: return jGallery.defaultContent(content, json);
}
},
/*
* Called to display a search result
* @dataFull: the galleries that match all searched keywords
* @dataPartial: the galleries that some of the searched keywords
* @keywords: the searched keywords
*/
showSearch:function(dataFull, dataPartial, keywords) {
if(dataFull.length) {
myTheme.showSearchResults(dataFull, keywords);
}
if(dataPartial.length) {
myTheme.showSearchResults(dataPartial, keywords);
}
},
showSearchResults:function(data, keywords) {
if(!data)
return;
for (var i in data) {
var res = {};
res.ID = data[i].ID;
res.url = data[i].url;
res.descr = data[i].descr;
res.starred = data[i].starred;
res.completeurl = data[i].url;
res.title = jGallery.highlightText(data[i].url, keywords);
res.thumb = data[i].url+'/'+data[i].thumbs[0];
$("#dirTpl").tmpl(res).appendTo('#search_results');
$('#dir'+res.ID).click({url:res.url}, function(ev) {
ev.preventDefault();
jGallery.switchPage(ev.data.url);
});
}
},
/*
* Called to display an error.
* @data: use data.Error to get the error message
*/
showError:function(data) {
$("#errorTpl").tmpl(data).appendTo('#content');
},
/*
* Called before displaying the first page and when the user
* changes the gallery language.
* All text in <... class="translate"></...> markups will
* be automatically translated for you.
* @lang: 'en', 'fr', ...
*/
changeThemeLang:function(lang) {
if(lang == 'fr') {
config.tr['Hello'] = 'Salut';
// <span class="translate">Hello</span> will be shown as "Salut" in French
}
},
init:function() {
// Called once, when the theme is loaded
},
clean:function() {
// Called on every page change
},
};
// your theme must be in /theme/mytheme
config.loadedThemes['mytheme'] = myTheme;
</pre>You are free to handle (or not to handle) any of the content that is passed as an argument to showContent. A default function is provided for 'gpx' but you should handle the 'dirs', 'pics' and 'vids' contents. Here is an example of functions that you may use to show galleries, pictures and videos:<br />
<pre class="brush: js;">
var myTheme = {
// ... functions declared before
/*
* Called to display galleries.
* @json: the json being displayed; galleries are in the json.dirs field.
*/
showDirs:function(json) {
if(!json.dirs)
return;
var dirs = [];
var dirUrl = jGalleryModel.pageToUrl(json.realurl);
for (var i in json.dirs) {
dirs[i] = {
ID:i,
completeurl:json.dirs[i].completeurl || (dirUrl+json.dirs[i].url),
thumb:json.dirs[i].thumb || (dirUrl+json.dirs[i].url+'/'+json.dirs[i].thumbs[0]),
title:json.dirs[i].title || json.dirs[i].url,
descr:json.dirs[i].descr,
};
/* you may also want to set .day , .month, .year and .starred */
/* you can also specify a .separator (html string) that will show before the directory */
/* see the dirTpl template in /index.html to get the list of variables used by the template */
$("#dirTpl").tmpl(dirs[i]).appendTo('#content');
$('#dir'+dirs[i].ID).css('opacity', 1);
$('#dir'+dirs[i].ID+' img').css('opacity', 1);
$('#dir'+dirs[i].ID).click({url:json.dirs[i].url}, function(ev) {
ev.preventDefault();
jGallery.switchPage(dirUrl+ev.data.url);
});
}
},
/*
* Called to display pictures
* @json: the json being displayed; pictures are in the json.pics field.
*/
showPics:function(json) {
if(!json.pics)
return;
var pics = [];
var dirUrl = jGalleryModel.pageToUrl(json.realurl);
for (var i in json.pics) {
pics[i] = {
ID:i,
url:(json.pics[i].fullpath?json.pics[i].fullpath:dirUrl),
big:json.pics[i].url,
thumb:json.pics[i].url.replace(/\.([^\.]+)$/, "_c.$1"), //pic.jpg -> pic_c.jpg
original:json.pics[i].original
};
$("#picTpl").tmpl(pics[i]).appendTo('#content');
$('#pic'+i+' img').css('opacity', 1);
}
},
/*
* Called to display videos
* @json: the json being displayed; videos are in the json.vids field.
*/
showVids:function(json) {
if(!json.vids)
return;
var dirUrl = jGalleryModel.pageToUrl(json.realurl);
var vids = [];
for (var i in json.vids) {
vids[i] = {
ID:i,
vid:json.vids[i].url,
path:dirUrl,
h:360,
w:640
};
$("#vidTpl").tmpl(vids[i]).appendTo('#content');
}
},
};
</pre>
</div><br />
<br />
<br />
<br />
</div>
<div class="hidden">
<h1>Create a plugin</h1>
<div class="hidden">
<h2>Denomination</h2>The admininistration is composed of a set of plugins. Each view of the administration (index, option, face recognition, etc.) is a plugin. Some views in the gallery (e.g., face search) are also plugins. Some types of files that are handled by the gallery (e.g., gpx files) are also handled by plugins. We call plugins that display a new view <b>"view plugins"</b> and plugins that handle new type of files <b>"content plugins"</b>. Both type of plugins can export data/functions to the main gallery.<br />
Note: a plugin can be both a view and a content plugin at the same time, if you want to do real complex things.<br />
<br />
</div>
<div class="hidden">
<h2>Content Plugins</h2>
<h3>Philosophy</h3>Content plugins are used to handle content that the gallery does not know how to handle by itself, e.g., new type of files. A content plugin can add information in the main administration page (e.g., the gpx chooser is part of a content plugin) and in the jsons generated by the gallery. It can also add javascript in the main gallery to display the new content to the user (e.g., show a map).<br />
The gallery works as follow: when displaying a gallery, for each registered content plugin, it checks if the theme can show the content and then, if the theme does not know how to show the content, it calls the plugin's default function.<br />
<b>A content plugin should only be used to handle new contents that are displayed in the galleries. To create new views (e.g., face search), you should use a view plugin.</b>
<h3>Handling .hello files</h3>Creating a plugin to enhance the gallery is very simple. It only requires the creation of 1 php file. For a more complete example, see the gpx plugin that is shipped with the gallery.
<ul>
<li>Create the index file with the content described bellow.</li>
<li>Activate myplugin in the administration options (you need to do that only once)</li>
<li>Create a gallery with a .hello file in it and update the gallery in the main page of the administration.</li>
<li>Go in the gallery. It should show a popup saying the gallery contains a .hello file</li>
</ul>
<ol class="tree">
<li>
<label>pages</label>
<ol>
<li>
<label>myplugin</label>
<ol>
<li class="file"><a href="#" onclick="return showHide('content-index');">index.php</a> [click or download <a href="./code/myplugin1/index.sample">the file</a>]</li>
</ol>
</li>
</ol>
</li>
</ol>
<div id="content-index" style="display:none">
The index.php file mainly does 2 things: it exports a function to the gallery that will alert the user that a gallery contains a .hello file and it writes a field in .json files used by the gallery.
<pre class="brush: php;">
/*
* Do not forget to activate the plugin in the administration before testing!
* Then update a directory that contains a .hello file and go into the gallery. It will show an alert box.
* WARNING: the name of the class is important! Make sure that if your plugin is in pages/myplugin/, then the class is named Pages_Myplugin_Index!
*/
class Pages_Myplugin_Index {
public static $description = "Plugin";
public static $isOptional = true;
public static $showOnMenu = false;
public static $userContentName = "hello"; // The name of what I will show
// Will call showContent('hello', json) in the gallery
public static $userContentDefaultPosition = 1; // the gallery shows elements in this order by default:
// galeries, pictures, videos. Insert at position 1 to show
// galeries, hello, pictures and videos.
/* Export one function to the gallery.
* Note that we could have put the code in a file and used the getUserScript function
* to make the gallery load the file (recommended if you have a lot of code to load),
* see 2nd example
*/
static public function getUserFunctions() {
return array(
'config.contentPlugins["hello"] = function(json) {
if(json.hashello) // written by the writeJSON function
alert("There is an hello file in this gallery!");
}'
);
}
/* Called when the gallery writes a JSON. Add our field. */
public static function writeJSON($args) {
$json = &$args['json'];
$old_json = $args['old_json'];
$files = $old_json->masterDirectory->getFiles();
foreach($files as $f) {
if($f->extension == 'hello') {
$json['hashello'] = true;
}
}
}
};
</pre>
</div>
<h3>A more complex example</h3>In this example, we show how to show new content in the main administration page (e.g., a textbox that will appear in each directory "update box"). Showing content in the main administration page requires a template and a javascript file to fill the template. We start from the .hello plugin described bellow. We also add js files that will contain the translations of various elements of the plugin.
<ol class="tree">
<li>
<label>pages</label>
<ol>
<li>
<label>myplugin</label>
<ol>
<li class="file"><a href="#" onclick="hide('content2-jso'); hide('content2-js'); hide('content2-tpl');hide('content2-jsl');return showHide('content2-index');">index.php</a> [click or download <a href="./code/myplugin2/index.sample">the file</a>]</li>
<li>
<label>scripts</label>
<ol>
<li class="file"><a href="#" onclick="hide('content2-jso'); hide('content2-index');hide('content2-tpl'); hide('content2-jsl');return showHide('content2-js');">index.myplugin.js</a> [click or download <a href="./code/myplugin2/scripts/index.myplugin.js">the file</a>]</li>
<li>
<label>lang</label>
<ol>
<li class="file"><a href="#" onclick="hide('content2-jso'); hide('content2-js');hide('content2-index');hide('content2-tpl'); return showHide('content2-jsl');">index_en.js</a> [click or download <a href="./code/myplugin2/scripts/lang/index_en.js">the file</a>]</li>
<li class="file"><a href="#" onclick="hide('content2-jsl'); hide('content2-js');hide('content2-index');hide('content2-tpl'); return showHide('content2-jso');">option_en.js</a> [click or download <a href="./code/myplugin2/scripts/lang/option_en.js">the file</a>]</li>
</ol>
</li>
</ol>
</li>
<li>
<label>tpl</label>
<ol>
<li class="file"><a href="#" onclick="hide('content2-jso'); hide('content2-index');hide('content2-js');hide('content2-jsl'); return showHide('content2-tpl');">index.tpl</a> [click or download <a href="./code/myplugin2/tpl/index.tpl">the file</a>]</li>
</ol>
</li>
</ol>
</li>
</ol>
</li>
</ol>
<div id="content2-index" style="display:none">
Compared to the previous example, the index also exports a template to the main administration page.
<pre class="brush: php;">
/*
* Do not forget to activate the plugin in the administration before testing!
* WARNING: the name of the class is important! Make sure that if your plugin is in pages/myplugin/, then the class is named Pages_Myplugin_Index!
*/
class Pages_Myplugin_Index {
public static $description = "Plugin";
public static $isOptional = true;
public static $showOnMenu = false;
public static $userContentName = "hello";
public static $userContentDefaultPosition = 1;
/*
* We export a tpl file in the main administration page.
* The tpl will be filled by the index.myplugin.js file.
*/
static public function getTpl() {
$template = new liteTemplate();
$template->file('pages/myplugin/tpl/index.tpl');
return $template->returnTpl();
}
// this will be exported in the gallery.
static public function getUserFunctions() {
return array(
'config.contentPlugins["hello"] = function(json) {
if(json.hashello) // written by the writeJSON function
alert("You wrote "+json.hashello+" in the administration");
}'
);
}
public static function writeJSON($args) {
$json = &$args['json'];
$old_json = $args['old_json'];
$old_content = $old_json->get();
// only write something in the json for the directory that is being updated
if($old_json->masterDirectory->isUpdated) {
if(isset($old_content['hashello'])
$json['hashello'] = $old_content['hashello'];
return;
}
// here we set the json.hashello field if something has been written in the text input of our plugin of the directory that is being updated
// see main.js file to see where myplugin_post_var is set.
if(Controller::getParameter('myplugin_post_var', null))
$json['hashello'] = Controller::getParameter('myplugin_post_var', null);
}
};
</pre>
</div>
<div id="content2-tpl" style="display:none">
The template must be enclosed in tr markups.
<pre class="brush: php;">
<script id="myplugTpl" type="text/x-jquery-tmpl">
<tr style="height:40px">
<td class="translate">myplu</td>
<td width="100%">
<input type="text" id='plug_${id}' type="input" value="${hello}" />
</td>
</tr>
</script>
</pre>
</div>
<div id="content2-js" style="display:none">
A content plugin that wants to interact with the administration index must implement multiple functions. These functions are used to modify the parameters that are sent to PHP when writing json files, to add DOM elements inside the directories' boxes, etc.
<pre class="brush: js;">
var MyPlugin = {
//called before writing the json of directory 'dir'
//id is the unique id that is passed to your plugin template file;
//it can be used to retrieve values of inputs (or other DOM elements) of the template. See next function.
//cb is a callback that MUST be called once we are done.
preWriteJson:function(id, dir, cb) {
cb(); // we do nothing here
},
// called when writing the json. Put any parameter that you want to be sent to PHP.
getJsonParams:function(id, dir) {
return { myplugin_post_var:$('#plug_'+id).val() }; // add the value of our input field
},
// the json has been written. Nothing else remains to be done
postWriteJson:function(id, dir, cb) {
cb();
},
// the template has been added. Now you can configure what happens when
// the administrator interacts with your buttons/inputs
addButtonActions:function(id, dir, data) {
//nothing
},
// the gallery provides an utility function that watches changes of content
// on inputs and checkboxes. When the content changes, the directory theme changes
// (a warning sign that informs the administrator that she must validate her changes
// is added for example). In this function you can specify the DOM elements that
// should be watched.
getHooks:function(dir, id) {
return [$('#plug_'+id)];
},
// return what you want to show in the box of a directory that has not been added
// to the gallery
getUnparsedDirTpl:function(dir, div, id) {
var tpl = $("#myplugTpl").tmpl({id:id});
return tpl.html();
},
// return what you want to show in the box of a directory that has been added
// to the gallery
getParsedDirTpl:function(dir, id, json) {
// we reuse the json.hashello field that has been set by PHP when the
// directory was first added
return $("#myplugTpl").tmpl({id:id,hello:json.hashello}).html();
},
};
plugins.push(MyPlugin);
</pre>
</div>
<div id="content2-jsl" style="display:none">
The scripts/lang/index_{language}.js files will be exported automatically to the main administration page. They must contain translations for translatable elements of your template file.
<pre class="brush: js;">
known_sentences.concat({
'myplu' : 'My Plugin:',
});
</pre>
</div>
<div id="content2-jso" style="display:none">
The scripts/lang/option_{language}.js files will be exported automatically to the administration option page. We translate the "activate" checkbox for the plugin. Note that this file should also contains translation for possible options of your plugin.
<pre class="brush: js;">
known_sentences.concat({
'myplugin_activated' : 'Activate my Plugin:',
});
</pre>
</div><br />
<br />
</div>
<div class="hidden">
<h2>View Plugins</h2>
<h3>Philosophy</h3>A view plugin is used to
<ul>
<li>Display a new page in the administration (e.g., options).</li>
<li>Display a new page in the gallery (e.g., face search).</li>
</ul>
<h3>Views in the administration - Hello world</h3>A view plugin is composed of multiple "actions" (functions): the <b>mainAction</b> that displays the template and multiple other <b>fooAction</b> that are called asynchronously (via AJAX calls). See bellow for a simple Hello World plugin to understand how to perform AJAX calls. The gallery provides convenient functions to perform AJAX calls. <b>DO NOT TRY TO PERFORM AJAX CALLS BY HAND!</b> Indeed, the gallery needs security variables in each AJAX calls that are used internally to prevent XSS attacks. If you perform an AJAX call without these variables, your call will be rejected by the gallery. So, stick with the galleries AJAX functions or make sure to add the security variables to your calls!
<ol class="tree">
<li>
<label>pages</label>
<ol>
<li>
<label>myplugin</label>
<ol>
<li class="file"><a href="#" onclick="hide('hello-js'); hide('hello-tpl'); return showHide('hello-index');">index.php</a> [click or download <a href="./code/myplugin3/index.sample">the file</a>]</li>
<li>
<label>scripts</label>
<ol>
<li class="file"><a href="#" onclick="hide('hello-tpl'); hide('hello-index'); return showHide('hello-js');">main.js</a> [click or download <a href="./code/myplugin3/scripts/main.js">the file</a>]</li>
</ol>
</li>
<li>
<label>tpl</label>
<ol>
<li class="file"><a href="#" onclick="hide('hello-js'); hide('hello-index'); return showHide('hello-tpl');">index.tpl</a> [click or download <a href="./code/myplugin3/tpl/index.tpl">the file</a>]</li>
</ol>
</li>
</ol>
</li>
</ol>
</li>
</ol>
<div id="hello-js" style="display:none">
Here is a simple JS file that adds an action to the "Click me" text of the template.
<pre class="brush: js;">
$(document).ready(function() {
var nclicks = 0;
$('#hello').click(function() {
var batch = new Batch(ParallelBatch, function(data) {
// All actions in the batch have completed
// In this example we only launch one action (foo_bar) but you may want to launch multiple actions
// and get notified when they have all complete.
// Notice the 'ParallelBatch' that will launch multiple actions in parallel (4 by default). Use
// SequentialBatch for actions that must be executed sequentially (e.g., multiple actions touching the same file)
// Note: Sequential and Parallel Batchs operate on a global level, i.e.,
// var batch1 = new Batch(SequentialBatch);
// var batch2 = new Batch(SequentialBatch);
// ...
// batch1.launch();
// batch2.launch(); // will only execute once batch1 has completed its action(s).
}, null);
batch.get({action:'myplugin.foo_bar', clicks:++nclicks}, function(data) {
// will call /pages/myplugin/index.php?action=foo_bar&clicks=nclicks&custom_security_variables
// that will automatically execute the fooBarAction() function of the index.php file
$('#res').append(data.foo);
});
batch.launch(); // Always call that after adding an action to a batch
});
});
</pre>
</div>
<div id="hello-tpl" style="display:none">
The administration uses the liteTemplate class to display templates from PHP. Alternatively you can also use the jQuery template plugin if you feel more comfortable displaying templates in JavaScript. Note that variables in liteTemplate are of the form {$VAR} whereas jQuery template plugin used ${var} (notice the emplacement of the $).
<pre class="brush: php;">
<div id="hello">{$CLICK}</div>
<div id="res"></div>
</pre>