# HG changeset patch # User Yves-Marie Haussonne <1218002+ymph@users.noreply.github.com> # Date 1451391914 -3600 # Node ID 10974bff4daeb35935f23c31a6dfeb130b18c72e # Parent 20e00017dd60e89b04010ee2e89315fd6ff64162 upgrade metadataplayer + publish enmi 14and 15 diff -r 20e00017dd60 -r 10974bff4dae web/common.php --- a/web/common.php Fri Dec 11 18:11:13 2015 +0100 +++ b/web/common.php Tue Dec 29 13:25:14 2015 +0100 @@ -57,7 +57,7 @@ 'fens2014-design-metadata','fens2014-museo','fens2014-transmediamix','fens2014-edito','fens2014-attention', 'pour-la-transition-une-conomie-du-partage-de-la-connaissance-et-des-biens-communs','spel-01-gout-archivage', 'edito-1415-01-hybridation-pratiques-recherche', 'museo-1415-01-inaugurale', 'museo-1415-02-controverses', 'attention-1415-01-attention-automatisee', - 'museo-1415-03-pedagogies', 'museo-1415-04-reseaux-sociaux-hermeneutiques','edito-1415-02-ressources-documentation-recherche', + 'museo-1415-03-pedagogies', 'museo-1415-04-reseaux-sociaux-hermeneutiques','edito-1415-02-ressources-documentation-recherche', 'enmi14', 'attention-1415-02-recherche-algo-attention-hermeneutique', 'edito-1415-04-elargissement-communautes-scientifiques', /*'museo-1415-05-interfaces-design',*/ 'museo-1415-06-multilinguisme', 'museo-1415-07-traduction', 'attention-1415-05-reseaux-sociaux-valorisation', 'attention-1415-06-game-design', 'edito-1415-05-faire-oeuvre-epoque-numerique', 'museo-1415-08-histoire-critique', diff -r 20e00017dd60 -r 10974bff4dae web/enmi14/config.php --- a/web/enmi14/config.php Fri Dec 11 18:11:13 2015 +0100 +++ b/web/enmi14/config.php Tue Dec 29 13:25:14 2015 +0100 @@ -4,14 +4,15 @@ 'enmi14/session-1', 'enmi14/session-2', 'enmi14/session-3', - 'enmi14/session-4', + 'enmi14/session-4-1', + 'enmi14/session-4-2', ), 'hashtag' => '#enmi14', - + 'title' => "Entretiens du Nouveau Monde Industriel 2014", - + 'abstract' => "LA “VÉRITÉ” DU NUMÉRIQUE
Recherche et enseignement supérieur à l’époque des technologies numériques
les 5 et 6 décembre 2014
Centre Pompidou, Grande Salle
", - + 'description'=> "

LA “VÉRITÉ” DU NUMÉRIQUE

Recherche et enseignement supérieur à l’époque des technologies numériques

Paris. Centre Pompidou. Grande Salle.
@@ -148,24 +149,24 @@

Conclusions

", - + 'link' => 'http://enmi-conf.org/wp/enmi14/', - + 'islive' => true, - + 'keywords' => 'iri, nouveau monde industriel, automatisation, algorithmes', - + 'rep' => basename(__DIR__), - + 'partenaires'=> "IRI | Cap Digital", 'client_visual' => 'images/client_visual.jpg',// 480 × 320 pixels - + 'head_logo' => 'images/logo-enmi.png', // 171 × 63 pixels - + 'slide_background' => 'images/slide_background.jpg', // 606 × 282 pixels - + 'archive_img' => 'images/archive_img.jpg', // 270 × 150 pixels 'archive_title' => "Entretiens du Nouveau Monde Industriel 2013", diff -r 20e00017dd60 -r 10974bff4dae web/enmi14/session-1/config.php --- a/web/enmi14/session-1/config.php Fri Dec 11 18:11:13 2015 +0100 +++ b/web/enmi14/session-1/config.php Tue Dec 29 13:25:14 2015 +0100 @@ -1,11 +1,11 @@ '#enmi14', - + 'title' => "Entretiens du Nouveau Monde Industriel 2014, Session 1", - + 'abstract' => "", - + 'description'=> "

L’ère numérique des savoirs et des non-savoirs

Vendredi 5 Décembre

", - + 'link' => 'http://enmi-conf.org/wp/enmi14/session-1/', - + 'islive' => true, - + 'keywords' => 'iri, nouveau monde industriel, savoir, numérique', - + 'rep' => basename(__DIR__), - + 'partenaires'=> "IRI | Cap Digital", 'client_visual' => 'images/client_visual.jpg',// 480 × 320 pixels - + 'head_logo' => 'images/logo-enmi.png', // 171 × 63 pixels - + 'slide_background' => 'images/slide_background.jpg', // 606 × 282 pixels - + 'archive_img' => 'images/archive_img.jpg', // 270 × 150 pixels 'archive_title' => "Session 1 : L'automatisation contre l'autonomisation ?", 'archive_description' => 'Bernard Stiegler (IRI, UTC, Conseil National du Numérique), David Bates (Université de Californie, Berkeley), Jean Lassègue (EHESS), Guiseppe Longo (ENS Ulm)', // After the event - 'metadata' => "" -); \ No newline at end of file + 'metadata' => "1fd77ed0-86bb-11e4-9c37-00145ea4a2be" +); diff -r 20e00017dd60 -r 10974bff4dae web/enmi14/session-2/config.php --- a/web/enmi14/session-2/config.php Fri Dec 11 18:11:13 2015 +0100 +++ b/web/enmi14/session-2/config.php Tue Dec 29 13:25:14 2015 +0100 @@ -1,11 +1,11 @@ '#enmi14', - + 'title' => "Entretiens du Nouveau Monde Industriel 2014, Session 2", - + 'abstract' => "", - + 'description'=> "

Phénoménotechniques des sciences de la nature et de l’esprit

Vendredi 5 Décembre

", - + 'link' => 'http://enmi-conf.org/wp/enmi14/session-2/', - + 'islive' => true, - + 'keywords' => 'iri, nouveau monde industriel, savoir, numérique', - + 'rep' => basename(__DIR__), - + 'partenaires'=> "IRI | Cap Digital", 'client_visual' => 'images/client_visual.jpg',// 480 × 320 pixels - + 'head_logo' => 'images/logo-enmi.png', // 171 × 63 pixels - + 'slide_background' => 'images/slide_background.jpg', // 606 × 282 pixels - + 'archive_img' => 'images/archive_img.jpg', // 270 × 150 pixels 'archive_title' => "Session 2 : Phénoménotechniques des sciences de la nature et de l’esprit", 'archive_description' => 'Antoinette Rouvroy (FNRS Namur), Dominique Cardon (Orange, Université de Marne la Vallée), Vincent Minier (CEA) et Vincent Bontems (CEA), Cédric Matthews (CNRS)', - // After the event - 'metadata' => "" -); \ No newline at end of file + 'metadata' => "7e64624a-889d-11e4-9c37-00145ea4a2be" +); diff -r 20e00017dd60 -r 10974bff4dae web/enmi14/session-3/config.php --- a/web/enmi14/session-3/config.php Fri Dec 11 18:11:13 2015 +0100 +++ b/web/enmi14/session-3/config.php Tue Dec 29 13:25:14 2015 +0100 @@ -1,11 +1,11 @@ '#enmi14', - + 'title' => "Entretiens du Nouveau Monde Industriel 2014, Session 3", - + 'abstract' => "", - + 'description'=> "

Conceptions instrumentales transdisciplinaires

Samedi 6 Décembre

", - + 'link' => 'http://enmi-conf.org/wp/enmi14/session-4/', - + 'islive' => true, - + 'keywords' => 'iri, nouveau monde industriel, savoir, numérique', - + 'rep' => basename(__DIR__), - + 'partenaires'=> "IRI | Cap Digital", 'client_visual' => 'images/client_visual.jpg',// 480 × 320 pixels - + 'head_logo' => 'images/logo-enmi.png', // 171 × 63 pixels - + 'slide_background' => 'images/slide_background.jpg', // 606 × 282 pixels - + 'archive_img' => 'images/archive_img.jpg', // 270 × 150 pixels 'archive_title' => "Session 3 : Conceptions instrumentales transdisciplinaires", @@ -41,4 +41,4 @@ // After the event 'metadata' => "b9efb8b8-7d5e-11e4-b72c-00145ea4a2be" -); \ No newline at end of file +); diff -r 20e00017dd60 -r 10974bff4dae web/enmi14/session-4-1/config.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/enmi14/session-4-1/config.php Tue Dec 29 13:25:14 2015 +0100 @@ -0,0 +1,43 @@ + '#enmi14', + + 'title' => "Entretiens du Nouveau Monde Industriel 2014, Session 4 1ere partie", + + 'abstract' => "", + + 'description'=> "

Chercher, enseigner, éduquer dans l’anthropocène digitalisé

+

Samedi 6 Décembre

+ + ", + + 'link' => 'http://enmi-conf.org/wp/enmi14/session-4/', + + 'islive' => true, + + 'keywords' => 'iri, nouveau monde industriel, savoir, numérique', + + 'rep' => basename(__DIR__), + + 'partenaires'=> "IRI + | Cap Digital", + + 'client_visual' => 'images/client_visual.jpg',// 480 × 320 pixels + + 'head_logo' => 'images/logo-enmi.png', // 171 × 63 pixels + + 'slide_background' => 'images/slide_background.jpg', // 606 × 282 pixels + + 'archive_img' => 'images/archive_img.jpg', // 270 × 150 pixels + + 'archive_title' => "Session 4-1 : Chercher, enseigner, éduquer dans l’anthropocène digitalisé", + 'archive_description' => 'Warren Sacks (Université de Californie, Santa Cruz), Hélène Mialet (Université de Californie, Berkeley), Francis Jutand (Institut Mines Télécom), Claude Kirchner (INRIA), Valérie Peugeot (Conseil National du Numérique, Orange), Daniel Kaplan (Conseil National du Numérique, FING), Bernard Stiegler (IRI, UTC, Conseil National du Numérique)', + + // After the event + 'metadata' => "157518d4-7d98-11e4-b72c-00145ea4a2be" +); diff -r 20e00017dd60 -r 10974bff4dae web/enmi14/session-4-1/images/archive_img.jpg Binary file web/enmi14/session-4-1/images/archive_img.jpg has changed diff -r 20e00017dd60 -r 10974bff4dae web/enmi14/session-4-1/images/logo-enmi.png Binary file web/enmi14/session-4-1/images/logo-enmi.png has changed diff -r 20e00017dd60 -r 10974bff4dae web/enmi14/session-4-1/index.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/enmi14/session-4-1/index.php Tue Dec 29 13:25:14 2015 +0100 @@ -0,0 +1,6 @@ + \ No newline at end of file diff -r 20e00017dd60 -r 10974bff4dae web/enmi14/session-4-2/config.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/enmi14/session-4-2/config.php Tue Dec 29 13:25:14 2015 +0100 @@ -0,0 +1,43 @@ + '#enmi14', + + 'title' => "Entretiens du Nouveau Monde Industriel 2014, Session 4 2ème partie", + + 'abstract' => "", + + 'description'=> "

Chercher, enseigner, éduquer dans l’anthropocène digitalisé

+

Samedi 6 Décembre

+ + ", + + 'link' => 'http://enmi-conf.org/wp/enmi14/session-4/', + + 'islive' => true, + + 'keywords' => 'iri, nouveau monde industriel, savoir, numérique', + + 'rep' => basename(__DIR__), + + 'partenaires'=> "IRI + | Cap Digital", + + 'client_visual' => 'images/client_visual.jpg',// 480 × 320 pixels + + 'head_logo' => 'images/logo-enmi.png', // 171 × 63 pixels + + 'slide_background' => 'images/slide_background.jpg', // 606 × 282 pixels + + 'archive_img' => 'images/archive_img.jpg', // 270 × 150 pixels + + 'archive_title' => "Session 4-2 : Chercher, enseigner, éduquer dans l’anthropocène digitalisé", + 'archive_description' => 'Warren Sacks (Université de Californie, Santa Cruz), Hélène Mialet (Université de Californie, Berkeley), Francis Jutand (Institut Mines Télécom), Claude Kirchner (INRIA), Valérie Peugeot (Conseil National du Numérique, Orange), Daniel Kaplan (Conseil National du Numérique, FING), Bernard Stiegler (IRI, UTC, Conseil National du Numérique)', + + // After the event + 'metadata' => "750827bc-7d9a-11e4-b72c-00145ea4a2be" +); diff -r 20e00017dd60 -r 10974bff4dae web/enmi14/session-4-2/images/archive_img.jpg Binary file web/enmi14/session-4-2/images/archive_img.jpg has changed diff -r 20e00017dd60 -r 10974bff4dae web/enmi14/session-4-2/images/logo-enmi.png Binary file web/enmi14/session-4-2/images/logo-enmi.png has changed diff -r 20e00017dd60 -r 10974bff4dae web/enmi14/session-4-2/index.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/enmi14/session-4-2/index.php Tue Dec 29 13:25:14 2015 +0100 @@ -0,0 +1,6 @@ + \ No newline at end of file diff -r 20e00017dd60 -r 10974bff4dae web/enmi14/session-4/config.php --- a/web/enmi14/session-4/config.php Fri Dec 11 18:11:13 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ - '#enmi14', - - 'title' => "Entretiens du Nouveau Monde Industriel 2014, Session 4", - - 'abstract' => "", - - 'description'=> "

Chercher, enseigner, éduquer dans l’anthropocène digitalisé

-

Samedi 6 Décembre

- - ", - - 'link' => 'http://enmi-conf.org/wp/enmi14/session-4/', - - 'islive' => true, - - 'keywords' => 'iri, nouveau monde industriel, savoir, numérique', - - 'rep' => basename(__DIR__), - - 'partenaires'=> "IRI - | Cap Digital", - - 'client_visual' => 'images/client_visual.jpg',// 480 × 320 pixels - - 'head_logo' => 'images/logo-enmi.png', // 171 × 63 pixels - - 'slide_background' => 'images/slide_background.jpg', // 606 × 282 pixels - - 'archive_img' => 'images/archive_img.jpg', // 270 × 150 pixels - - 'archive_title' => "Session 4 : Chercher, enseigner, éduquer dans l’anthropocène digitalisé", - 'archive_description' => 'Warren Sacks (Université de Californie, Santa Cruz), Hélène Mialet (Université de Californie, Berkeley), Francis Jutand (Institut Mines Télécom), Claude Kirchner (INRIA), Valérie Peugeot (Conseil National du Numérique, Orange), Daniel Kaplan (Conseil National du Numérique, FING), Bernard Stiegler (IRI, UTC, Conseil National du Numérique)', - - // After the event - 'metadata' => "" -); \ No newline at end of file diff -r 20e00017dd60 -r 10974bff4dae web/enmi14/session-4/images/archive_img.jpg Binary file web/enmi14/session-4/images/archive_img.jpg has changed diff -r 20e00017dd60 -r 10974bff4dae web/enmi14/session-4/images/logo-enmi.png Binary file web/enmi14/session-4/images/logo-enmi.png has changed diff -r 20e00017dd60 -r 10974bff4dae web/enmi14/session-4/index.php --- a/web/enmi14/session-4/index.php Fri Dec 11 18:11:13 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ - \ No newline at end of file diff -r 20e00017dd60 -r 10974bff4dae web/enmi15/config.php --- a/web/enmi15/config.php Fri Dec 11 18:11:13 2015 +0100 +++ b/web/enmi15/config.php Tue Dec 29 13:25:14 2015 +0100 @@ -1,5 +1,11 @@ array( + 'enmi15/session-1', + 'enmi15/session-2', + 'enmi15/session-3', + 'enmi15/session-4', + ), 'hashtag' => '#enmi15', 'title' => 'Entretiens du Nouveau Monde Industriel 2015', @@ -65,15 +71,12 @@
De nos jours, des architectures nouvelles émergent, telle la blockchain à la base du bitcoin, dans un contexte où se développent l’open access scientifique, les plateformes d’annotation contributive, qui relancent des questions posées dès les années 1960 par Ted Nelson et Douglas Engelbart, tandis que les modèles de territoires augmentés et d’industrie 4.0 conduisent vers de nouveaux scénarios de valorisation des traces qui bouleversent les fondements des sociétés industrielles configurées au XXè siècle.


diff -r 20e00017dd60 -r 10974bff4dae web/enmi15/index.php --- a/web/enmi15/index.php Fri Dec 11 18:11:13 2015 +0100 +++ b/web/enmi15/index.php Tue Dec 29 13:25:14 2015 +0100 @@ -1,6 +1,6 @@ diff -r 20e00017dd60 -r 10974bff4dae web/enmi15/session-1/config.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/enmi15/session-1/config.php Tue Dec 29 13:25:14 2015 +0100 @@ -0,0 +1,52 @@ + '#enmi15', + 'annotation_protocol_version' => '2', + + 'title' => "Entretiens du Nouveau Monde Industriel 2015, Session 1", + + 'abstract' => "LA TOILE QUE NOUS VOULONS
Du web sémantique au web herméneutique
+

Paris. Centre Pompidou. Grande Salle.
+ 14 et 15 décembre 2015
+ http://enmi-conf.org +

", + + 'description'=> "

Session 1 : Ouverture et Anthropocène et entropie du web

+

Lundi 14 Décembre 2015

+ + ", + + 'link' => 'http://enmi-conf.org/wp/enmi15/session-1/', + + 'islive' => true, + + 'keywords' => 'iri, nouveau monde industriel, savoir, numérique', + + 'rep' => basename(__DIR__), + + 'partenaires'=> "Organisateurs: IRI + | Cap Digital + - Partenaires Scientifiques: Institut Mines-Télécom + | France Télévisions + | Strate", + + 'client_visual' => 'images/client_visual.jpg',// 480 × 320 pixels + + 'head_logo' => 'images/logo-enmi.png', // 171 × 63 pixels + + 'slide_background' => 'images/slide_background.jpg', // 606 × 282 pixels + + 'archive_img' => 'images/archive_img.jpg', // 270 × 150 pixels + + 'archive_title' => "ENMI 2015 - Session 1 : Ouverture et Anthropocène et entropie du web ?", + 'archive_description' => 'Serge Lasvignes (Président du Centre Georges Pompidou), Axelle Lemaire (Secrétaire d’Etat chargée du numérique), Dominique Cardon (Orange Labs, université de Marne la Vallée), Evgeny Morozov (journaliste, écrivain), Guiseppe Longo (ENS), Bernard Stiegler (IRI)', + + // After the event + 'metadata' => "fab30f52-a284-11e5-8011-00145ea4a2be" +); diff -r 20e00017dd60 -r 10974bff4dae web/enmi15/session-1/images/archive_img.jpg Binary file web/enmi15/session-1/images/archive_img.jpg has changed diff -r 20e00017dd60 -r 10974bff4dae web/enmi15/session-1/images/logo-enmi.png Binary file web/enmi15/session-1/images/logo-enmi.png has changed diff -r 20e00017dd60 -r 10974bff4dae web/enmi15/session-1/index.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/enmi15/session-1/index.php Tue Dec 29 13:25:14 2015 +0100 @@ -0,0 +1,6 @@ + \ No newline at end of file diff -r 20e00017dd60 -r 10974bff4dae web/enmi15/session-2/config.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/enmi15/session-2/config.php Tue Dec 29 13:25:14 2015 +0100 @@ -0,0 +1,52 @@ + '#enmi15', + 'annotation_protocol_version' => '2', + + 'title' => "Entretiens du Nouveau Monde Industriel 2015, Session 2", + + 'abstract' => "LA TOILE QUE NOUS VOULONS
Du web sémantique au web herméneutique
+

Paris. Centre Pompidou. Grande Salle.
+ 14 et 15 décembre 2015
+ http://enmi-conf.org +

", + + 'description'=> "

Architecture, traces et modèles de valeur

+

Lundi 14 Décembre 2015

+ + ", + + 'link' => 'http://enmi-conf.org/wp/enmi15/session-2/', + + 'islive' => true, + + 'keywords' => 'iri, nouveau monde industriel, savoir, numérique', + + 'rep' => basename(__DIR__), + + 'partenaires'=> "Organisateurs: IRI + | Cap Digital + - Partenaires Scientifiques: Institut Mines-Télécom + | France Télévisions + | Strate", + + 'client_visual' => 'images/client_visual.jpg',// 480 × 320 pixels + + 'head_logo' => 'images/logo-enmi.png', // 171 × 63 pixels + + 'slide_background' => 'images/slide_background.jpg', // 606 × 282 pixels + + 'archive_img' => 'images/archive_img.jpg', // 270 × 150 pixels + + 'archive_title' => "ENMI 2015 - Session 2 : Architecture, traces et modèles de valeur", + 'archive_description' => 'Julian Assange (Wikileaks - par conférence vidéo), Christian Fauré (Octo technologies - Ars Industrialis), Pierre Guehenneux (Vinci construction), Yuk Hui (Leuphana Un), Harry Halpin (Inria, projet NextLeap)', + + // After the event + 'metadata' => "330760fc-a31f-11e5-8011-00145ea4a2be" +); diff -r 20e00017dd60 -r 10974bff4dae web/enmi15/session-2/images/archive_img.jpg Binary file web/enmi15/session-2/images/archive_img.jpg has changed diff -r 20e00017dd60 -r 10974bff4dae web/enmi15/session-2/images/logo-enmi.png Binary file web/enmi15/session-2/images/logo-enmi.png has changed diff -r 20e00017dd60 -r 10974bff4dae web/enmi15/session-2/index.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/enmi15/session-2/index.php Tue Dec 29 13:25:14 2015 +0100 @@ -0,0 +1,6 @@ + \ No newline at end of file diff -r 20e00017dd60 -r 10974bff4dae web/enmi15/session-3/config.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/enmi15/session-3/config.php Tue Dec 29 13:25:14 2015 +0100 @@ -0,0 +1,52 @@ + '#enmi15', + 'annotation_protocol_version' => '2', + + 'title' => "Entretiens du Nouveau Monde Industriel 2015, Session 3", + + 'abstract' => "LA TOILE QUE NOUS VOULONS
Du web sémantique au web herméneutique
+

Paris. Centre Pompidou. Grande Salle.
+ 14 et 15 décembre 2015
+ http://enmi-conf.org +

", + + 'description'=> "

Espace public, études digitales et éditorialisation

+

Mardi 15 Décembre 2015

+ + ", + + 'link' => 'http://enmi-conf.org/wp/enmi15/session-3/', + + 'islive' => true, + + 'keywords' => 'iri, nouveau monde industriel, savoir, numérique', + + 'rep' => basename(__DIR__), + + 'partenaires'=> "Organisateurs: IRI + | Cap Digital + - Partenaires Scientifiques: Institut Mines-Télécom + | France Télévisions + | Strate", + + 'client_visual' => 'images/client_visual.jpg',// 480 × 320 pixels + + 'head_logo' => 'images/logo-enmi.png', // 171 × 63 pixels + + 'slide_background' => 'images/slide_background.jpg', // 606 × 282 pixels + + 'archive_img' => 'images/archive_img.jpg', // 270 × 150 pixels + + 'archive_title' => "ENMI 2015 - Session 3 : Espace public, études digitales et éditorialisation", + 'archive_description' => 'Olivier Grise (Inria), David Berry (Université de Sussex), Thomas Berns (Université libre de Bruxelles), Paul Jorion (Anthropologue)', + + // After the event + 'metadata' => "093c26a0-a346-11e5-8011-00145ea4a2be" +); diff -r 20e00017dd60 -r 10974bff4dae web/enmi15/session-3/images/archive_img.jpg Binary file web/enmi15/session-3/images/archive_img.jpg has changed diff -r 20e00017dd60 -r 10974bff4dae web/enmi15/session-3/images/logo-enmi.png Binary file web/enmi15/session-3/images/logo-enmi.png has changed diff -r 20e00017dd60 -r 10974bff4dae web/enmi15/session-3/index.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/enmi15/session-3/index.php Tue Dec 29 13:25:14 2015 +0100 @@ -0,0 +1,6 @@ + \ No newline at end of file diff -r 20e00017dd60 -r 10974bff4dae web/enmi15/session-4/config.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/enmi15/session-4/config.php Tue Dec 29 13:25:14 2015 +0100 @@ -0,0 +1,51 @@ + '#enmi15', + 'annotation_protocol_version' => '2', + + 'title' => "Entretiens du Nouveau Monde Industriel 2015, Session 4", + + 'abstract' => "LA TOILE QUE NOUS VOULONS
Du web sémantique au web herméneutique
+

Paris. Centre Pompidou. Grande Salle.
+ 14 et 15 décembre 2015
+ http://enmi-conf.org +

", + + 'description'=> "

Chercher, enseigner, éduquer dans l’anthropocène digitalisé

+

Mardi 15 Décembre 2015

+ + ", + + 'link' => 'http://enmi-conf.org/wp/enmi15/session-4/', + + 'islive' => true, + + 'keywords' => 'iri, nouveau monde industriel, savoir, numérique', + + 'rep' => basename(__DIR__), + + 'partenaires'=> "Organisateurs: IRI + | Cap Digital + - Partenaires Scientifiques: Institut Mines-Télécom + | France Télévisions + | Strate", + + 'client_visual' => 'images/client_visual.jpg',// 480 × 320 pixels + + 'head_logo' => 'images/logo-enmi.png', // 171 × 63 pixels + + 'slide_background' => 'images/slide_background.jpg', // 606 × 282 pixels + + 'archive_img' => 'images/archive_img.jpg', // 270 × 150 pixels + + 'archive_title' => "ENMI 2015 - Session 4 : Chercher, enseigner, éduquer dans l’anthropocène digitalisé", + 'archive_description' => 'Ariel Kyrou et Bruno Teboul (Keyrus, Université Paris Dauphine), Boris Razon (France Télévisions), Xavier de La Porte (Rue89), François Bon (Ecrivain), Patrick Braouezec (Président de Plaine Commune), Catherine Beaugrand (Artiste), Bernard Stiegler (Ars Industrialis)', + + // After the event + 'metadata' => "e8b49d26-a404-11e5-8011-00145ea4a2be" +); diff -r 20e00017dd60 -r 10974bff4dae web/enmi15/session-4/images/archive_img.jpg Binary file web/enmi15/session-4/images/archive_img.jpg has changed diff -r 20e00017dd60 -r 10974bff4dae web/enmi15/session-4/images/logo-enmi.png Binary file web/enmi15/session-4/images/logo-enmi.png has changed diff -r 20e00017dd60 -r 10974bff4dae web/enmi15/session-4/index.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/enmi15/session-4/index.php Tue Dec 29 13:25:14 2015 +0100 @@ -0,0 +1,6 @@ + \ No newline at end of file diff -r 20e00017dd60 -r 10974bff4dae web/polemicaltimeline.php --- a/web/polemicaltimeline.php Fri Dec 11 18:11:13 2015 +0100 +++ b/web/polemicaltimeline.php Tue Dec 29 13:25:14 2015 +0100 @@ -51,6 +51,7 @@ array_push($_SESSION['answered_events'], $rep); } +//$annotation_protocol_version = isset($config['annotation_protocol_version'])?$config['annotation_protocol_version']:"1"; $annotations = get_default_annotations_config($config, $translate); ?> diff -r 20e00017dd60 -r 10974bff4dae web/res/js/ZeroClipboard.js --- a/web/res/js/ZeroClipboard.js Fri Dec 11 18:11:13 2015 +0100 +++ b/web/res/js/ZeroClipboard.js Tue Dec 29 13:25:14 2015 +0100 @@ -1,311 +1,2581 @@ -// Simple Set Clipboard System -// Author: Joseph Huckaby +/*! + * ZeroClipboard + * The ZeroClipboard library provides an easy way to copy text to the clipboard using an invisible Adobe Flash movie and a JavaScript interface. + * Copyright (c) 2009-2014 Jon Rohan, James M. Greene + * Licensed MIT + * http://zeroclipboard.org/ + * v2.2.0 + */ +(function(window, undefined) { + "use strict"; + /** + * Store references to critically important global functions that may be + * overridden on certain web pages. + */ + var _window = window, _document = _window.document, _navigator = _window.navigator, _setTimeout = _window.setTimeout, _clearTimeout = _window.clearTimeout, _setInterval = _window.setInterval, _clearInterval = _window.clearInterval, _getComputedStyle = _window.getComputedStyle, _encodeURIComponent = _window.encodeURIComponent, _ActiveXObject = _window.ActiveXObject, _Error = _window.Error, _parseInt = _window.Number.parseInt || _window.parseInt, _parseFloat = _window.Number.parseFloat || _window.parseFloat, _isNaN = _window.Number.isNaN || _window.isNaN, _now = _window.Date.now, _keys = _window.Object.keys, _defineProperty = _window.Object.defineProperty, _hasOwn = _window.Object.prototype.hasOwnProperty, _slice = _window.Array.prototype.slice, _unwrap = function() { + var unwrapper = function(el) { + return el; + }; + if (typeof _window.wrap === "function" && typeof _window.unwrap === "function") { + try { + var div = _document.createElement("div"); + var unwrappedDiv = _window.unwrap(div); + if (div.nodeType === 1 && unwrappedDiv && unwrappedDiv.nodeType === 1) { + unwrapper = _window.unwrap; + } + } catch (e) {} + } + return unwrapper; + }(); + /** + * Convert an `arguments` object into an Array. + * + * @returns The arguments as an Array + * @private + */ + var _args = function(argumentsObj) { + return _slice.call(argumentsObj, 0); + }; + /** + * Shallow-copy the owned, enumerable properties of one object over to another, similar to jQuery's `$.extend`. + * + * @returns The target object, augmented + * @private + */ + var _extend = function() { + var i, len, arg, prop, src, copy, args = _args(arguments), target = args[0] || {}; + for (i = 1, len = args.length; i < len; i++) { + if ((arg = args[i]) != null) { + for (prop in arg) { + if (_hasOwn.call(arg, prop)) { + src = target[prop]; + copy = arg[prop]; + if (target !== copy && copy !== undefined) { + target[prop] = copy; + } + } + } + } + } + return target; + }; + /** + * Return a deep copy of the source object or array. + * + * @returns Object or Array + * @private + */ + var _deepCopy = function(source) { + var copy, i, len, prop; + if (typeof source !== "object" || source == null || typeof source.nodeType === "number") { + copy = source; + } else if (typeof source.length === "number") { + copy = []; + for (i = 0, len = source.length; i < len; i++) { + if (_hasOwn.call(source, i)) { + copy[i] = _deepCopy(source[i]); + } + } + } else { + copy = {}; + for (prop in source) { + if (_hasOwn.call(source, prop)) { + copy[prop] = _deepCopy(source[prop]); + } + } + } + return copy; + }; + /** + * Makes a shallow copy of `obj` (like `_extend`) but filters its properties based on a list of `keys` to keep. + * The inverse of `_omit`, mostly. The big difference is that these properties do NOT need to be enumerable to + * be kept. + * + * @returns A new filtered object. + * @private + */ + var _pick = function(obj, keys) { + var newObj = {}; + for (var i = 0, len = keys.length; i < len; i++) { + if (keys[i] in obj) { + newObj[keys[i]] = obj[keys[i]]; + } + } + return newObj; + }; + /** + * Makes a shallow copy of `obj` (like `_extend`) but filters its properties based on a list of `keys` to omit. + * The inverse of `_pick`. + * + * @returns A new filtered object. + * @private + */ + var _omit = function(obj, keys) { + var newObj = {}; + for (var prop in obj) { + if (keys.indexOf(prop) === -1) { + newObj[prop] = obj[prop]; + } + } + return newObj; + }; + /** + * Remove all owned, enumerable properties from an object. + * + * @returns The original object without its owned, enumerable properties. + * @private + */ + var _deleteOwnProperties = function(obj) { + if (obj) { + for (var prop in obj) { + if (_hasOwn.call(obj, prop)) { + delete obj[prop]; + } + } + } + return obj; + }; + /** + * Determine if an element is contained within another element. + * + * @returns Boolean + * @private + */ + var _containedBy = function(el, ancestorEl) { + if (el && el.nodeType === 1 && el.ownerDocument && ancestorEl && (ancestorEl.nodeType === 1 && ancestorEl.ownerDocument && ancestorEl.ownerDocument === el.ownerDocument || ancestorEl.nodeType === 9 && !ancestorEl.ownerDocument && ancestorEl === el.ownerDocument)) { + do { + if (el === ancestorEl) { + return true; + } + el = el.parentNode; + } while (el); + } + return false; + }; + /** + * Get the URL path's parent directory. + * + * @returns String or `undefined` + * @private + */ + var _getDirPathOfUrl = function(url) { + var dir; + if (typeof url === "string" && url) { + dir = url.split("#")[0].split("?")[0]; + dir = url.slice(0, url.lastIndexOf("/") + 1); + } + return dir; + }; + /** + * Get the current script's URL by throwing an `Error` and analyzing it. + * + * @returns String or `undefined` + * @private + */ + var _getCurrentScriptUrlFromErrorStack = function(stack) { + var url, matches; + if (typeof stack === "string" && stack) { + matches = stack.match(/^(?:|[^:@]*@|.+\)@(?=http[s]?|file)|.+?\s+(?: at |@)(?:[^:\(]+ )*[\(]?)((?:http[s]?|file):\/\/[\/]?.+?\/[^:\)]*?)(?::\d+)(?::\d+)?/); + if (matches && matches[1]) { + url = matches[1]; + } else { + matches = stack.match(/\)@((?:http[s]?|file):\/\/[\/]?.+?\/[^:\)]*?)(?::\d+)(?::\d+)?/); + if (matches && matches[1]) { + url = matches[1]; + } + } + } + return url; + }; + /** + * Get the current script's URL by throwing an `Error` and analyzing it. + * + * @returns String or `undefined` + * @private + */ + var _getCurrentScriptUrlFromError = function() { + var url, err; + try { + throw new _Error(); + } catch (e) { + err = e; + } + if (err) { + url = err.sourceURL || err.fileName || _getCurrentScriptUrlFromErrorStack(err.stack); + } + return url; + }; + /** + * Get the current script's URL. + * + * @returns String or `undefined` + * @private + */ + var _getCurrentScriptUrl = function() { + var jsPath, scripts, i; + if (_document.currentScript && (jsPath = _document.currentScript.src)) { + return jsPath; + } + scripts = _document.getElementsByTagName("script"); + if (scripts.length === 1) { + return scripts[0].src || undefined; + } + if ("readyState" in scripts[0]) { + for (i = scripts.length; i--; ) { + if (scripts[i].readyState === "interactive" && (jsPath = scripts[i].src)) { + return jsPath; + } + } + } + if (_document.readyState === "loading" && (jsPath = scripts[scripts.length - 1].src)) { + return jsPath; + } + if (jsPath = _getCurrentScriptUrlFromError()) { + return jsPath; + } + return undefined; + }; + /** + * Get the unanimous parent directory of ALL script tags. + * If any script tags are either (a) inline or (b) from differing parent + * directories, this method must return `undefined`. + * + * @returns String or `undefined` + * @private + */ + var _getUnanimousScriptParentDir = function() { + var i, jsDir, jsPath, scripts = _document.getElementsByTagName("script"); + for (i = scripts.length; i--; ) { + if (!(jsPath = scripts[i].src)) { + jsDir = null; + break; + } + jsPath = _getDirPathOfUrl(jsPath); + if (jsDir == null) { + jsDir = jsPath; + } else if (jsDir !== jsPath) { + jsDir = null; + break; + } + } + return jsDir || undefined; + }; + /** + * Get the presumed location of the "ZeroClipboard.swf" file, based on the location + * of the executing JavaScript file (e.g. "ZeroClipboard.js", etc.). + * + * @returns String + * @private + */ + var _getDefaultSwfPath = function() { + var jsDir = _getDirPathOfUrl(_getCurrentScriptUrl()) || _getUnanimousScriptParentDir() || ""; + return jsDir + "ZeroClipboard.swf"; + }; + /** + * Keep track of if the page is framed (in an `iframe`). This can never change. + * @private + */ + var _pageIsFramed = function() { + return window.opener == null && (!!window.top && window != window.top || !!window.parent && window != window.parent); + }(); + /** + * Keep track of the state of the Flash object. + * @private + */ + var _flashState = { + bridge: null, + version: "0.0.0", + pluginType: "unknown", + disabled: null, + outdated: null, + sandboxed: null, + unavailable: null, + degraded: null, + deactivated: null, + overdue: null, + ready: null + }; + /** + * The minimum Flash Player version required to use ZeroClipboard completely. + * @readonly + * @private + */ + var _minimumFlashVersion = "11.0.0"; + /** + * The ZeroClipboard library version number, as reported by Flash, at the time the SWF was compiled. + */ + var _zcSwfVersion; + /** + * Keep track of all event listener registrations. + * @private + */ + var _handlers = {}; + /** + * Keep track of the currently activated element. + * @private + */ + var _currentElement; + /** + * Keep track of the element that was activated when a `copy` process started. + * @private + */ + var _copyTarget; + /** + * Keep track of data for the pending clipboard transaction. + * @private + */ + var _clipData = {}; + /** + * Keep track of data formats for the pending clipboard transaction. + * @private + */ + var _clipDataFormatMap = null; + /** + * Keep track of the Flash availability check timeout. + * @private + */ + var _flashCheckTimeout = 0; + /** + * Keep track of SWF network errors interval polling. + * @private + */ + var _swfFallbackCheckInterval = 0; + /** + * The `message` store for events + * @private + */ + var _eventMessages = { + ready: "Flash communication is established", + error: { + "flash-disabled": "Flash is disabled or not installed. May also be attempting to run Flash in a sandboxed iframe, which is impossible.", + "flash-outdated": "Flash is too outdated to support ZeroClipboard", + "flash-sandboxed": "Attempting to run Flash in a sandboxed iframe, which is impossible", + "flash-unavailable": "Flash is unable to communicate bidirectionally with JavaScript", + "flash-degraded": "Flash is unable to preserve data fidelity when communicating with JavaScript", + "flash-deactivated": "Flash is too outdated for your browser and/or is configured as click-to-activate.\nThis may also mean that the ZeroClipboard SWF object could not be loaded, so please check your `swfPath` configuration and/or network connectivity.\nMay also be attempting to run Flash in a sandboxed iframe, which is impossible.", + "flash-overdue": "Flash communication was established but NOT within the acceptable time limit", + "version-mismatch": "ZeroClipboard JS version number does not match ZeroClipboard SWF version number", + "clipboard-error": "At least one error was thrown while ZeroClipboard was attempting to inject your data into the clipboard", + "config-mismatch": "ZeroClipboard configuration does not match Flash's reality", + "swf-not-found": "The ZeroClipboard SWF object could not be loaded, so please check your `swfPath` configuration and/or network connectivity" + } + }; + /** + * The `name`s of `error` events that can only occur is Flash has at least + * been able to load the SWF successfully. + * @private + */ + var _errorsThatOnlyOccurAfterFlashLoads = [ "flash-unavailable", "flash-degraded", "flash-overdue", "version-mismatch", "config-mismatch", "clipboard-error" ]; + /** + * The `name`s of `error` events that should likely result in the `_flashState` + * variable's property values being updated. + * @private + */ + var _flashStateErrorNames = [ "flash-disabled", "flash-outdated", "flash-sandboxed", "flash-unavailable", "flash-degraded", "flash-deactivated", "flash-overdue" ]; + /** + * A RegExp to match the `name` property of `error` events related to Flash. + * @private + */ + var _flashStateErrorNameMatchingRegex = new RegExp("^flash-(" + _flashStateErrorNames.map(function(errorName) { + return errorName.replace(/^flash-/, ""); + }).join("|") + ")$"); + /** + * A RegExp to match the `name` property of `error` events related to Flash, + * which is enabled. + * @private + */ + var _flashStateEnabledErrorNameMatchingRegex = new RegExp("^flash-(" + _flashStateErrorNames.slice(1).map(function(errorName) { + return errorName.replace(/^flash-/, ""); + }).join("|") + ")$"); + /** + * ZeroClipboard configuration defaults for the Core module. + * @private + */ + var _globalConfig = { + swfPath: _getDefaultSwfPath(), + trustedDomains: window.location.host ? [ window.location.host ] : [], + cacheBust: true, + forceEnhancedClipboard: false, + flashLoadTimeout: 3e4, + autoActivate: true, + bubbleEvents: true, + containerId: "global-zeroclipboard-html-bridge", + containerClass: "global-zeroclipboard-container", + swfObjectId: "global-zeroclipboard-flash-bridge", + hoverClass: "zeroclipboard-is-hover", + activeClass: "zeroclipboard-is-active", + forceHandCursor: false, + title: null, + zIndex: 999999999 + }; + /** + * The underlying implementation of `ZeroClipboard.config`. + * @private + */ + var _config = function(options) { + if (typeof options === "object" && options !== null) { + for (var prop in options) { + if (_hasOwn.call(options, prop)) { + if (/^(?:forceHandCursor|title|zIndex|bubbleEvents)$/.test(prop)) { + _globalConfig[prop] = options[prop]; + } else if (_flashState.bridge == null) { + if (prop === "containerId" || prop === "swfObjectId") { + if (_isValidHtml4Id(options[prop])) { + _globalConfig[prop] = options[prop]; + } else { + throw new Error("The specified `" + prop + "` value is not valid as an HTML4 Element ID"); + } + } else { + _globalConfig[prop] = options[prop]; + } + } + } + } + } + if (typeof options === "string" && options) { + if (_hasOwn.call(_globalConfig, options)) { + return _globalConfig[options]; + } + return; + } + return _deepCopy(_globalConfig); + }; + /** + * The underlying implementation of `ZeroClipboard.state`. + * @private + */ + var _state = function() { + _detectSandbox(); + return { + browser: _pick(_navigator, [ "userAgent", "platform", "appName" ]), + flash: _omit(_flashState, [ "bridge" ]), + zeroclipboard: { + version: ZeroClipboard.version, + config: ZeroClipboard.config() + } + }; + }; + /** + * The underlying implementation of `ZeroClipboard.isFlashUnusable`. + * @private + */ + var _isFlashUnusable = function() { + return !!(_flashState.disabled || _flashState.outdated || _flashState.sandboxed || _flashState.unavailable || _flashState.degraded || _flashState.deactivated); + }; + /** + * The underlying implementation of `ZeroClipboard.on`. + * @private + */ + var _on = function(eventType, listener) { + var i, len, events, added = {}; + if (typeof eventType === "string" && eventType) { + events = eventType.toLowerCase().split(/\s+/); + } else if (typeof eventType === "object" && eventType && typeof listener === "undefined") { + for (i in eventType) { + if (_hasOwn.call(eventType, i) && typeof i === "string" && i && typeof eventType[i] === "function") { + ZeroClipboard.on(i, eventType[i]); + } + } + } + if (events && events.length) { + for (i = 0, len = events.length; i < len; i++) { + eventType = events[i].replace(/^on/, ""); + added[eventType] = true; + if (!_handlers[eventType]) { + _handlers[eventType] = []; + } + _handlers[eventType].push(listener); + } + if (added.ready && _flashState.ready) { + ZeroClipboard.emit({ + type: "ready" + }); + } + if (added.error) { + for (i = 0, len = _flashStateErrorNames.length; i < len; i++) { + if (_flashState[_flashStateErrorNames[i].replace(/^flash-/, "")] === true) { + ZeroClipboard.emit({ + type: "error", + name: _flashStateErrorNames[i] + }); + break; + } + } + if (_zcSwfVersion !== undefined && ZeroClipboard.version !== _zcSwfVersion) { + ZeroClipboard.emit({ + type: "error", + name: "version-mismatch", + jsVersion: ZeroClipboard.version, + swfVersion: _zcSwfVersion + }); + } + } + } + return ZeroClipboard; + }; + /** + * The underlying implementation of `ZeroClipboard.off`. + * @private + */ + var _off = function(eventType, listener) { + var i, len, foundIndex, events, perEventHandlers; + if (arguments.length === 0) { + events = _keys(_handlers); + } else if (typeof eventType === "string" && eventType) { + events = eventType.split(/\s+/); + } else if (typeof eventType === "object" && eventType && typeof listener === "undefined") { + for (i in eventType) { + if (_hasOwn.call(eventType, i) && typeof i === "string" && i && typeof eventType[i] === "function") { + ZeroClipboard.off(i, eventType[i]); + } + } + } + if (events && events.length) { + for (i = 0, len = events.length; i < len; i++) { + eventType = events[i].toLowerCase().replace(/^on/, ""); + perEventHandlers = _handlers[eventType]; + if (perEventHandlers && perEventHandlers.length) { + if (listener) { + foundIndex = perEventHandlers.indexOf(listener); + while (foundIndex !== -1) { + perEventHandlers.splice(foundIndex, 1); + foundIndex = perEventHandlers.indexOf(listener, foundIndex); + } + } else { + perEventHandlers.length = 0; + } + } + } + } + return ZeroClipboard; + }; + /** + * The underlying implementation of `ZeroClipboard.handlers`. + * @private + */ + var _listeners = function(eventType) { + var copy; + if (typeof eventType === "string" && eventType) { + copy = _deepCopy(_handlers[eventType]) || null; + } else { + copy = _deepCopy(_handlers); + } + return copy; + }; + /** + * The underlying implementation of `ZeroClipboard.emit`. + * @private + */ + var _emit = function(event) { + var eventCopy, returnVal, tmp; + event = _createEvent(event); + if (!event) { + return; + } + if (_preprocessEvent(event)) { + return; + } + if (event.type === "ready" && _flashState.overdue === true) { + return ZeroClipboard.emit({ + type: "error", + name: "flash-overdue" + }); + } + eventCopy = _extend({}, event); + _dispatchCallbacks.call(this, eventCopy); + if (event.type === "copy") { + tmp = _mapClipDataToFlash(_clipData); + returnVal = tmp.data; + _clipDataFormatMap = tmp.formatMap; + } + return returnVal; + }; + /** + * The underlying implementation of `ZeroClipboard.create`. + * @private + */ + var _create = function() { + var previousState = _flashState.sandboxed; + _detectSandbox(); + if (typeof _flashState.ready !== "boolean") { + _flashState.ready = false; + } + if (_flashState.sandboxed !== previousState && _flashState.sandboxed === true) { + _flashState.ready = false; + ZeroClipboard.emit({ + type: "error", + name: "flash-sandboxed" + }); + } else if (!ZeroClipboard.isFlashUnusable() && _flashState.bridge === null) { + var maxWait = _globalConfig.flashLoadTimeout; + if (typeof maxWait === "number" && maxWait >= 0) { + _flashCheckTimeout = _setTimeout(function() { + if (typeof _flashState.deactivated !== "boolean") { + _flashState.deactivated = true; + } + if (_flashState.deactivated === true) { + ZeroClipboard.emit({ + type: "error", + name: "flash-deactivated" + }); + } + }, maxWait); + } + _flashState.overdue = false; + _embedSwf(); + } + }; + /** + * The underlying implementation of `ZeroClipboard.destroy`. + * @private + */ + var _destroy = function() { + ZeroClipboard.clearData(); + ZeroClipboard.blur(); + ZeroClipboard.emit("destroy"); + _unembedSwf(); + ZeroClipboard.off(); + }; + /** + * The underlying implementation of `ZeroClipboard.setData`. + * @private + */ + var _setData = function(format, data) { + var dataObj; + if (typeof format === "object" && format && typeof data === "undefined") { + dataObj = format; + ZeroClipboard.clearData(); + } else if (typeof format === "string" && format) { + dataObj = {}; + dataObj[format] = data; + } else { + return; + } + for (var dataFormat in dataObj) { + if (typeof dataFormat === "string" && dataFormat && _hasOwn.call(dataObj, dataFormat) && typeof dataObj[dataFormat] === "string" && dataObj[dataFormat]) { + _clipData[dataFormat] = dataObj[dataFormat]; + } + } + }; + /** + * The underlying implementation of `ZeroClipboard.clearData`. + * @private + */ + var _clearData = function(format) { + if (typeof format === "undefined") { + _deleteOwnProperties(_clipData); + _clipDataFormatMap = null; + } else if (typeof format === "string" && _hasOwn.call(_clipData, format)) { + delete _clipData[format]; + } + }; + /** + * The underlying implementation of `ZeroClipboard.getData`. + * @private + */ + var _getData = function(format) { + if (typeof format === "undefined") { + return _deepCopy(_clipData); + } else if (typeof format === "string" && _hasOwn.call(_clipData, format)) { + return _clipData[format]; + } + }; + /** + * The underlying implementation of `ZeroClipboard.focus`/`ZeroClipboard.activate`. + * @private + */ + var _focus = function(element) { + if (!(element && element.nodeType === 1)) { + return; + } + if (_currentElement) { + _removeClass(_currentElement, _globalConfig.activeClass); + if (_currentElement !== element) { + _removeClass(_currentElement, _globalConfig.hoverClass); + } + } + _currentElement = element; + _addClass(element, _globalConfig.hoverClass); + var newTitle = element.getAttribute("title") || _globalConfig.title; + if (typeof newTitle === "string" && newTitle) { + var htmlBridge = _getHtmlBridge(_flashState.bridge); + if (htmlBridge) { + htmlBridge.setAttribute("title", newTitle); + } + } + var useHandCursor = _globalConfig.forceHandCursor === true || _getStyle(element, "cursor") === "pointer"; + _setHandCursor(useHandCursor); + _reposition(); + }; + /** + * The underlying implementation of `ZeroClipboard.blur`/`ZeroClipboard.deactivate`. + * @private + */ + var _blur = function() { + var htmlBridge = _getHtmlBridge(_flashState.bridge); + if (htmlBridge) { + htmlBridge.removeAttribute("title"); + htmlBridge.style.left = "0px"; + htmlBridge.style.top = "-9999px"; + htmlBridge.style.width = "1px"; + htmlBridge.style.height = "1px"; + } + if (_currentElement) { + _removeClass(_currentElement, _globalConfig.hoverClass); + _removeClass(_currentElement, _globalConfig.activeClass); + _currentElement = null; + } + }; + /** + * The underlying implementation of `ZeroClipboard.activeElement`. + * @private + */ + var _activeElement = function() { + return _currentElement || null; + }; + /** + * Check if a value is a valid HTML4 `ID` or `Name` token. + * @private + */ + var _isValidHtml4Id = function(id) { + return typeof id === "string" && id && /^[A-Za-z][A-Za-z0-9_:\-\.]*$/.test(id); + }; + /** + * Create or update an `event` object, based on the `eventType`. + * @private + */ + var _createEvent = function(event) { + var eventType; + if (typeof event === "string" && event) { + eventType = event; + event = {}; + } else if (typeof event === "object" && event && typeof event.type === "string" && event.type) { + eventType = event.type; + } + if (!eventType) { + return; + } + eventType = eventType.toLowerCase(); + if (!event.target && (/^(copy|aftercopy|_click)$/.test(eventType) || eventType === "error" && event.name === "clipboard-error")) { + event.target = _copyTarget; + } + _extend(event, { + type: eventType, + target: event.target || _currentElement || null, + relatedTarget: event.relatedTarget || null, + currentTarget: _flashState && _flashState.bridge || null, + timeStamp: event.timeStamp || _now() || null + }); + var msg = _eventMessages[event.type]; + if (event.type === "error" && event.name && msg) { + msg = msg[event.name]; + } + if (msg) { + event.message = msg; + } + if (event.type === "ready") { + _extend(event, { + target: null, + version: _flashState.version + }); + } + if (event.type === "error") { + if (_flashStateErrorNameMatchingRegex.test(event.name)) { + _extend(event, { + target: null, + minimumVersion: _minimumFlashVersion + }); + } + if (_flashStateEnabledErrorNameMatchingRegex.test(event.name)) { + _extend(event, { + version: _flashState.version + }); + } + } + if (event.type === "copy") { + event.clipboardData = { + setData: ZeroClipboard.setData, + clearData: ZeroClipboard.clearData + }; + } + if (event.type === "aftercopy") { + event = _mapClipResultsFromFlash(event, _clipDataFormatMap); + } + if (event.target && !event.relatedTarget) { + event.relatedTarget = _getRelatedTarget(event.target); + } + return _addMouseData(event); + }; + /** + * Get a relatedTarget from the target's `data-clipboard-target` attribute + * @private + */ + var _getRelatedTarget = function(targetEl) { + var relatedTargetId = targetEl && targetEl.getAttribute && targetEl.getAttribute("data-clipboard-target"); + return relatedTargetId ? _document.getElementById(relatedTargetId) : null; + }; + /** + * Add element and position data to `MouseEvent` instances + * @private + */ + var _addMouseData = function(event) { + if (event && /^_(?:click|mouse(?:over|out|down|up|move))$/.test(event.type)) { + var srcElement = event.target; + var fromElement = event.type === "_mouseover" && event.relatedTarget ? event.relatedTarget : undefined; + var toElement = event.type === "_mouseout" && event.relatedTarget ? event.relatedTarget : undefined; + var pos = _getElementPosition(srcElement); + var screenLeft = _window.screenLeft || _window.screenX || 0; + var screenTop = _window.screenTop || _window.screenY || 0; + var scrollLeft = _document.body.scrollLeft + _document.documentElement.scrollLeft; + var scrollTop = _document.body.scrollTop + _document.documentElement.scrollTop; + var pageX = pos.left + (typeof event._stageX === "number" ? event._stageX : 0); + var pageY = pos.top + (typeof event._stageY === "number" ? event._stageY : 0); + var clientX = pageX - scrollLeft; + var clientY = pageY - scrollTop; + var screenX = screenLeft + clientX; + var screenY = screenTop + clientY; + var moveX = typeof event.movementX === "number" ? event.movementX : 0; + var moveY = typeof event.movementY === "number" ? event.movementY : 0; + delete event._stageX; + delete event._stageY; + _extend(event, { + srcElement: srcElement, + fromElement: fromElement, + toElement: toElement, + screenX: screenX, + screenY: screenY, + pageX: pageX, + pageY: pageY, + clientX: clientX, + clientY: clientY, + x: clientX, + y: clientY, + movementX: moveX, + movementY: moveY, + offsetX: 0, + offsetY: 0, + layerX: 0, + layerY: 0 + }); + } + return event; + }; + /** + * Determine if an event's registered handlers should be execute synchronously or asynchronously. + * + * @returns {boolean} + * @private + */ + var _shouldPerformAsync = function(event) { + var eventType = event && typeof event.type === "string" && event.type || ""; + return !/^(?:(?:before)?copy|destroy)$/.test(eventType); + }; + /** + * Control if a callback should be executed asynchronously or not. + * + * @returns `undefined` + * @private + */ + var _dispatchCallback = function(func, context, args, async) { + if (async) { + _setTimeout(function() { + func.apply(context, args); + }, 0); + } else { + func.apply(context, args); + } + }; + /** + * Handle the actual dispatching of events to client instances. + * + * @returns `undefined` + * @private + */ + var _dispatchCallbacks = function(event) { + if (!(typeof event === "object" && event && event.type)) { + return; + } + var async = _shouldPerformAsync(event); + var wildcardTypeHandlers = _handlers["*"] || []; + var specificTypeHandlers = _handlers[event.type] || []; + var handlers = wildcardTypeHandlers.concat(specificTypeHandlers); + if (handlers && handlers.length) { + var i, len, func, context, eventCopy, originalContext = this; + for (i = 0, len = handlers.length; i < len; i++) { + func = handlers[i]; + context = originalContext; + if (typeof func === "string" && typeof _window[func] === "function") { + func = _window[func]; + } + if (typeof func === "object" && func && typeof func.handleEvent === "function") { + context = func; + func = func.handleEvent; + } + if (typeof func === "function") { + eventCopy = _extend({}, event); + _dispatchCallback(func, context, [ eventCopy ], async); + } + } + } + return this; + }; + /** + * Check an `error` event's `name` property to see if Flash has + * already loaded, which rules out possible `iframe` sandboxing. + * @private + */ + var _getSandboxStatusFromErrorEvent = function(event) { + var isSandboxed = null; + if (_pageIsFramed === false || event && event.type === "error" && event.name && _errorsThatOnlyOccurAfterFlashLoads.indexOf(event.name) !== -1) { + isSandboxed = false; + } + return isSandboxed; + }; + /** + * Preprocess any special behaviors, reactions, or state changes after receiving this event. + * Executes only once per event emitted, NOT once per client. + * @private + */ + var _preprocessEvent = function(event) { + var element = event.target || _currentElement || null; + var sourceIsSwf = event._source === "swf"; + delete event._source; + switch (event.type) { + case "error": + var isSandboxed = event.name === "flash-sandboxed" || _getSandboxStatusFromErrorEvent(event); + if (typeof isSandboxed === "boolean") { + _flashState.sandboxed = isSandboxed; + } + if (_flashStateErrorNames.indexOf(event.name) !== -1) { + _extend(_flashState, { + disabled: event.name === "flash-disabled", + outdated: event.name === "flash-outdated", + unavailable: event.name === "flash-unavailable", + degraded: event.name === "flash-degraded", + deactivated: event.name === "flash-deactivated", + overdue: event.name === "flash-overdue", + ready: false + }); + } else if (event.name === "version-mismatch") { + _zcSwfVersion = event.swfVersion; + _extend(_flashState, { + disabled: false, + outdated: false, + unavailable: false, + degraded: false, + deactivated: false, + overdue: false, + ready: false + }); + } + _clearTimeoutsAndPolling(); + break; -var ZeroClipboard = { - - version: "1.0.7", - clients: {}, // registered upload clients on page, indexed by id - moviePath: 'ZeroClipboard.swf', // URL to movie - nextId: 1, // ID of next movie - - $: function(thingy) { - // simple DOM lookup utility function - if (typeof(thingy) == 'string') thingy = document.getElementById(thingy); - if (!thingy.addClass) { - // extend element with a few useful methods - thingy.hide = function() { this.style.display = 'none'; }; - thingy.show = function() { this.style.display = ''; }; - thingy.addClass = function(name) { this.removeClass(name); this.className += ' ' + name; }; - thingy.removeClass = function(name) { - var classes = this.className.split(/\s+/); - var idx = -1; - for (var k = 0; k < classes.length; k++) { - if (classes[k] == name) { idx = k; k = classes.length; } - } - if (idx > -1) { - classes.splice( idx, 1 ); - this.className = classes.join(' '); - } - return this; - }; - thingy.hasClass = function(name) { - return !!this.className.match( new RegExp("\\s*" + name + "\\s*") ); - }; - } - return thingy; - }, - - setMoviePath: function(path) { - // set path to ZeroClipboard.swf - this.moviePath = path; - }, - - dispatch: function(id, eventName, args) { - // receive event from flash movie, send to client - var client = this.clients[id]; - if (client) { - client.receiveEvent(eventName, args); - } - }, - - register: function(id, client) { - // register new client to receive events - this.clients[id] = client; - }, - - getDOMObjectPosition: function(obj, stopObj) { - // get absolute coordinates for dom element - var info = { - left: 0, - top: 0, - width: obj.width ? obj.width : obj.offsetWidth, - height: obj.height ? obj.height : obj.offsetHeight - }; + case "ready": + _zcSwfVersion = event.swfVersion; + var wasDeactivated = _flashState.deactivated === true; + _extend(_flashState, { + disabled: false, + outdated: false, + sandboxed: false, + unavailable: false, + degraded: false, + deactivated: false, + overdue: wasDeactivated, + ready: !wasDeactivated + }); + _clearTimeoutsAndPolling(); + break; + + case "beforecopy": + _copyTarget = element; + break; + + case "copy": + var textContent, htmlContent, targetEl = event.relatedTarget; + if (!(_clipData["text/html"] || _clipData["text/plain"]) && targetEl && (htmlContent = targetEl.value || targetEl.outerHTML || targetEl.innerHTML) && (textContent = targetEl.value || targetEl.textContent || targetEl.innerText)) { + event.clipboardData.clearData(); + event.clipboardData.setData("text/plain", textContent); + if (htmlContent !== textContent) { + event.clipboardData.setData("text/html", htmlContent); + } + } else if (!_clipData["text/plain"] && event.target && (textContent = event.target.getAttribute("data-clipboard-text"))) { + event.clipboardData.clearData(); + event.clipboardData.setData("text/plain", textContent); + } + break; + + case "aftercopy": + _queueEmitClipboardErrors(event); + ZeroClipboard.clearData(); + if (element && element !== _safeActiveElement() && element.focus) { + element.focus(); + } + break; - while (obj && (obj != stopObj)) { - info.left += obj.offsetLeft; - info.top += obj.offsetTop; - obj = obj.offsetParent; - } + case "_mouseover": + ZeroClipboard.focus(element); + if (_globalConfig.bubbleEvents === true && sourceIsSwf) { + if (element && element !== event.relatedTarget && !_containedBy(event.relatedTarget, element)) { + _fireMouseEvent(_extend({}, event, { + type: "mouseenter", + bubbles: false, + cancelable: false + })); + } + _fireMouseEvent(_extend({}, event, { + type: "mouseover" + })); + } + break; - return info; - }, - - Client: function(elem) { - // constructor for new simple upload client - this.handlers = {}; - - // unique ID - this.id = ZeroClipboard.nextId++; - this.movieId = 'ZeroClipboardMovie_' + this.id; - - // register client with singleton to receive flash events - ZeroClipboard.register(this.id, this); - - // create movie - if (elem) this.glue(elem); - } -}; + case "_mouseout": + ZeroClipboard.blur(); + if (_globalConfig.bubbleEvents === true && sourceIsSwf) { + if (element && element !== event.relatedTarget && !_containedBy(event.relatedTarget, element)) { + _fireMouseEvent(_extend({}, event, { + type: "mouseleave", + bubbles: false, + cancelable: false + })); + } + _fireMouseEvent(_extend({}, event, { + type: "mouseout" + })); + } + break; + + case "_mousedown": + _addClass(element, _globalConfig.activeClass); + if (_globalConfig.bubbleEvents === true && sourceIsSwf) { + _fireMouseEvent(_extend({}, event, { + type: event.type.slice(1) + })); + } + break; + + case "_mouseup": + _removeClass(element, _globalConfig.activeClass); + if (_globalConfig.bubbleEvents === true && sourceIsSwf) { + _fireMouseEvent(_extend({}, event, { + type: event.type.slice(1) + })); + } + break; + + case "_click": + _copyTarget = null; + if (_globalConfig.bubbleEvents === true && sourceIsSwf) { + _fireMouseEvent(_extend({}, event, { + type: event.type.slice(1) + })); + } + break; -ZeroClipboard.Client.prototype = { - - id: 0, // unique ID for us - ready: false, // whether movie is ready to receive events or not - movie: null, // reference to movie object - clipText: '', // text to copy to clipboard - handCursorEnabled: true, // whether to show hand cursor, or default pointer cursor - cssEffects: true, // enable CSS mouse effects on dom container - handlers: null, // user event handlers - - glue: function(elem, appendElem, stylesToAdd) { - // glue to DOM element - // elem can be ID or actual DOM element object - this.domElement = ZeroClipboard.$(elem); - - // float just above object, or zIndex 99 if dom element isn't set - var zIndex = 99; - if (this.domElement.style.zIndex) { - zIndex = parseInt(this.domElement.style.zIndex, 10) + 1; - } - - if (typeof(appendElem) == 'string') { - appendElem = ZeroClipboard.$(appendElem); - } - else if (typeof(appendElem) == 'undefined') { - appendElem = document.getElementsByTagName('body')[0]; - } - - // find X/Y position of domElement - var box = ZeroClipboard.getDOMObjectPosition(this.domElement, appendElem); - - // create floating DIV above element - this.div = document.createElement('div'); - var style = this.div.style; - style.position = 'absolute'; - style.left = '' + box.left + 'px'; - style.top = '' + box.top + 'px'; - style.width = '' + box.width + 'px'; - style.height = '' + box.height + 'px'; - style.zIndex = zIndex; - - if (typeof(stylesToAdd) == 'object') { - for (addedStyle in stylesToAdd) { - style[addedStyle] = stylesToAdd[addedStyle]; - } - } - - // style.backgroundColor = '#f00'; // debug - - appendElem.appendChild(this.div); - - this.div.innerHTML = this.getHTML( box.width, box.height ); - }, - - getHTML: function(width, height) { - // return HTML for movie - var html = ''; - var flashvars = 'id=' + this.id + - '&width=' + width + - '&height=' + height; - - if (navigator.userAgent.match(/MSIE/)) { - // IE gets an OBJECT tag - var protocol = location.href.match(/^https/i) ? 'https://' : 'http://'; - html += ''; - } - else { - // all other browsers get an EMBED tag - html += ''; - } - return html; - }, - - hide: function() { - // temporarily hide floater offscreen - if (this.div) { - this.div.style.left = '-2000px'; - } - }, - - show: function() { - // show ourselves after a call to hide() - this.reposition(); - }, - - destroy: function() { - // destroy control and floater - if (this.domElement && this.div) { - this.hide(); - this.div.innerHTML = ''; - - var body = document.getElementsByTagName('body')[0]; - try { body.removeChild( this.div ); } catch(e) {;} - - this.domElement = null; - this.div = null; - } - }, - - reposition: function(elem) { - // reposition our floating div, optionally to new container - // warning: container CANNOT change size, only position - if (elem) { - this.domElement = ZeroClipboard.$(elem); - if (!this.domElement) this.hide(); - } - - if (this.domElement && this.div) { - var box = ZeroClipboard.getDOMObjectPosition(this.domElement); - var style = this.div.style; - style.left = '' + box.left + 'px'; - style.top = '' + box.top + 'px'; - } - }, - - setText: function(newText) { - // set text to be copied to clipboard - this.clipText = newText; - if (this.ready) this.movie.setText(newText); - }, - - addEventListener: function(eventName, func) { - // add user event listener for event - // event types: load, queueStart, fileStart, fileComplete, queueComplete, progress, error, cancel - eventName = eventName.toString().toLowerCase().replace(/^on/, ''); - if (!this.handlers[eventName]) this.handlers[eventName] = []; - this.handlers[eventName].push(func); - }, - - setHandCursor: function(enabled) { - // enable hand cursor (true), or default arrow cursor (false) - this.handCursorEnabled = enabled; - if (this.ready) this.movie.setHandCursor(enabled); - }, - - setCSSEffects: function(enabled) { - // enable or disable CSS effects on DOM container - this.cssEffects = !!enabled; - }, - - receiveEvent: function(eventName, args) { - // receive event from flash - eventName = eventName.toString().toLowerCase().replace(/^on/, ''); - - // special behavior for certain events - switch (eventName) { - case 'load': - // movie claims it is ready, but in IE this isn't always the case... - // bug fix: Cannot extend EMBED DOM elements in Firefox, must use traditional function - this.movie = document.getElementById(this.movieId); - if (!this.movie) { - var self = this; - setTimeout( function() { self.receiveEvent('load', null); }, 1 ); - return; - } - - // firefox on pc needs a "kick" in order to set these in certain cases - if (!this.ready && navigator.userAgent.match(/Firefox/) && navigator.userAgent.match(/Windows/)) { - var self = this; - setTimeout( function() { self.receiveEvent('load', null); }, 100 ); - this.ready = true; - return; - } - - this.ready = true; - this.movie.setText( this.clipText ); - this.movie.setHandCursor( this.handCursorEnabled ); - break; - - case 'mouseover': - if (this.domElement && this.cssEffects) { - this.domElement.addClass('hover'); - if (this.recoverActive) this.domElement.addClass('active'); - } - break; - - case 'mouseout': - if (this.domElement && this.cssEffects) { - this.recoverActive = false; - if (this.domElement.hasClass('active')) { - this.domElement.removeClass('active'); - this.recoverActive = true; - } - this.domElement.removeClass('hover'); - } - break; - - case 'mousedown': - if (this.domElement && this.cssEffects) { - this.domElement.addClass('active'); - } - break; - - case 'mouseup': - if (this.domElement && this.cssEffects) { - this.domElement.removeClass('active'); - this.recoverActive = false; - } - break; - } // switch eventName - - if (this.handlers[eventName]) { - for (var idx = 0, len = this.handlers[eventName].length; idx < len; idx++) { - var func = this.handlers[eventName][idx]; - - if (typeof(func) == 'function') { - // actual function reference - func(this, args); - } - else if ((typeof(func) == 'object') && (func.length == 2)) { - // PHP style object + method, i.e. [myObject, 'myMethod'] - func[0][ func[1] ](this, args); - } - else if (typeof(func) == 'string') { - // name of function - window[func](this, args); - } - } // foreach event handler defined - } // user defined handler for event - } - -}; + case "_mousemove": + if (_globalConfig.bubbleEvents === true && sourceIsSwf) { + _fireMouseEvent(_extend({}, event, { + type: event.type.slice(1) + })); + } + break; + } + if (/^_(?:click|mouse(?:over|out|down|up|move))$/.test(event.type)) { + return true; + } + }; + /** + * Check an "aftercopy" event for clipboard errors and emit a corresponding "error" event. + * @private + */ + var _queueEmitClipboardErrors = function(aftercopyEvent) { + if (aftercopyEvent.errors && aftercopyEvent.errors.length > 0) { + var errorEvent = _deepCopy(aftercopyEvent); + _extend(errorEvent, { + type: "error", + name: "clipboard-error" + }); + delete errorEvent.success; + _setTimeout(function() { + ZeroClipboard.emit(errorEvent); + }, 0); + } + }; + /** + * Dispatch a synthetic MouseEvent. + * + * @returns `undefined` + * @private + */ + var _fireMouseEvent = function(event) { + if (!(event && typeof event.type === "string" && event)) { + return; + } + var e, target = event.target || null, doc = target && target.ownerDocument || _document, defaults = { + view: doc.defaultView || _window, + canBubble: true, + cancelable: true, + detail: event.type === "click" ? 1 : 0, + button: typeof event.which === "number" ? event.which - 1 : typeof event.button === "number" ? event.button : doc.createEvent ? 0 : 1 + }, args = _extend(defaults, event); + if (!target) { + return; + } + if (doc.createEvent && target.dispatchEvent) { + args = [ args.type, args.canBubble, args.cancelable, args.view, args.detail, args.screenX, args.screenY, args.clientX, args.clientY, args.ctrlKey, args.altKey, args.shiftKey, args.metaKey, args.button, args.relatedTarget ]; + e = doc.createEvent("MouseEvents"); + if (e.initMouseEvent) { + e.initMouseEvent.apply(e, args); + e._source = "js"; + target.dispatchEvent(e); + } + } + }; + /** + * Continuously poll the DOM until either: + * (a) the fallback content becomes visible, or + * (b) we receive an event from SWF (handled elsewhere) + * + * IMPORTANT: + * This is NOT a necessary check but it can result in significantly faster + * detection of bad `swfPath` configuration and/or network/server issues [in + * supported browsers] than waiting for the entire `flashLoadTimeout` duration + * to elapse before detecting that the SWF cannot be loaded. The detection + * duration can be anywhere from 10-30 times faster [in supported browsers] by + * using this approach. + * + * @returns `undefined` + * @private + */ + var _watchForSwfFallbackContent = function() { + var maxWait = _globalConfig.flashLoadTimeout; + if (typeof maxWait === "number" && maxWait >= 0) { + var pollWait = Math.min(1e3, maxWait / 10); + var fallbackContentId = _globalConfig.swfObjectId + "_fallbackContent"; + _swfFallbackCheckInterval = _setInterval(function() { + var el = _document.getElementById(fallbackContentId); + if (_isElementVisible(el)) { + _clearTimeoutsAndPolling(); + _flashState.deactivated = null; + ZeroClipboard.emit({ + type: "error", + name: "swf-not-found" + }); + } + }, pollWait); + } + }; + /** + * Create the HTML bridge element to embed the Flash object into. + * @private + */ + var _createHtmlBridge = function() { + var container = _document.createElement("div"); + container.id = _globalConfig.containerId; + container.className = _globalConfig.containerClass; + container.style.position = "absolute"; + container.style.left = "0px"; + container.style.top = "-9999px"; + container.style.width = "1px"; + container.style.height = "1px"; + container.style.zIndex = "" + _getSafeZIndex(_globalConfig.zIndex); + return container; + }; + /** + * Get the HTML element container that wraps the Flash bridge object/element. + * @private + */ + var _getHtmlBridge = function(flashBridge) { + var htmlBridge = flashBridge && flashBridge.parentNode; + while (htmlBridge && htmlBridge.nodeName === "OBJECT" && htmlBridge.parentNode) { + htmlBridge = htmlBridge.parentNode; + } + return htmlBridge || null; + }; + /** + * Create the SWF object. + * + * @returns The SWF object reference. + * @private + */ + var _embedSwf = function() { + var len, flashBridge = _flashState.bridge, container = _getHtmlBridge(flashBridge); + if (!flashBridge) { + var allowScriptAccess = _determineScriptAccess(_window.location.host, _globalConfig); + var allowNetworking = allowScriptAccess === "never" ? "none" : "all"; + var flashvars = _vars(_extend({ + jsVersion: ZeroClipboard.version + }, _globalConfig)); + var swfUrl = _globalConfig.swfPath + _cacheBust(_globalConfig.swfPath, _globalConfig); + container = _createHtmlBridge(); + var divToBeReplaced = _document.createElement("div"); + container.appendChild(divToBeReplaced); + _document.body.appendChild(container); + var tmpDiv = _document.createElement("div"); + var usingActiveX = _flashState.pluginType === "activex"; + tmpDiv.innerHTML = '" + (usingActiveX ? '' : "") + '' + '' + '' + '' + '' + '
 
' + "
"; + flashBridge = tmpDiv.firstChild; + tmpDiv = null; + _unwrap(flashBridge).ZeroClipboard = ZeroClipboard; + container.replaceChild(flashBridge, divToBeReplaced); + _watchForSwfFallbackContent(); + } + if (!flashBridge) { + flashBridge = _document[_globalConfig.swfObjectId]; + if (flashBridge && (len = flashBridge.length)) { + flashBridge = flashBridge[len - 1]; + } + if (!flashBridge && container) { + flashBridge = container.firstChild; + } + } + _flashState.bridge = flashBridge || null; + return flashBridge; + }; + /** + * Destroy the SWF object. + * @private + */ + var _unembedSwf = function() { + var flashBridge = _flashState.bridge; + if (flashBridge) { + var htmlBridge = _getHtmlBridge(flashBridge); + if (htmlBridge) { + if (_flashState.pluginType === "activex" && "readyState" in flashBridge) { + flashBridge.style.display = "none"; + (function removeSwfFromIE() { + if (flashBridge.readyState === 4) { + for (var prop in flashBridge) { + if (typeof flashBridge[prop] === "function") { + flashBridge[prop] = null; + } + } + if (flashBridge.parentNode) { + flashBridge.parentNode.removeChild(flashBridge); + } + if (htmlBridge.parentNode) { + htmlBridge.parentNode.removeChild(htmlBridge); + } + } else { + _setTimeout(removeSwfFromIE, 10); + } + })(); + } else { + if (flashBridge.parentNode) { + flashBridge.parentNode.removeChild(flashBridge); + } + if (htmlBridge.parentNode) { + htmlBridge.parentNode.removeChild(htmlBridge); + } + } + } + _clearTimeoutsAndPolling(); + _flashState.ready = null; + _flashState.bridge = null; + _flashState.deactivated = null; + _zcSwfVersion = undefined; + } + }; + /** + * Map the data format names of the "clipData" to Flash-friendly names. + * + * @returns A new transformed object. + * @private + */ + var _mapClipDataToFlash = function(clipData) { + var newClipData = {}, formatMap = {}; + if (!(typeof clipData === "object" && clipData)) { + return; + } + for (var dataFormat in clipData) { + if (dataFormat && _hasOwn.call(clipData, dataFormat) && typeof clipData[dataFormat] === "string" && clipData[dataFormat]) { + switch (dataFormat.toLowerCase()) { + case "text/plain": + case "text": + case "air:text": + case "flash:text": + newClipData.text = clipData[dataFormat]; + formatMap.text = dataFormat; + break; + + case "text/html": + case "html": + case "air:html": + case "flash:html": + newClipData.html = clipData[dataFormat]; + formatMap.html = dataFormat; + break; + + case "application/rtf": + case "text/rtf": + case "rtf": + case "richtext": + case "air:rtf": + case "flash:rtf": + newClipData.rtf = clipData[dataFormat]; + formatMap.rtf = dataFormat; + break; + + default: + break; + } + } + } + return { + data: newClipData, + formatMap: formatMap + }; + }; + /** + * Map the data format names from Flash-friendly names back to their original "clipData" names (via a format mapping). + * + * @returns A new transformed object. + * @private + */ + var _mapClipResultsFromFlash = function(clipResults, formatMap) { + if (!(typeof clipResults === "object" && clipResults && typeof formatMap === "object" && formatMap)) { + return clipResults; + } + var newResults = {}; + for (var prop in clipResults) { + if (_hasOwn.call(clipResults, prop)) { + if (prop === "errors") { + newResults[prop] = clipResults[prop] ? clipResults[prop].slice() : []; + for (var i = 0, len = newResults[prop].length; i < len; i++) { + newResults[prop][i].format = formatMap[newResults[prop][i].format]; + } + } else if (prop !== "success" && prop !== "data") { + newResults[prop] = clipResults[prop]; + } else { + newResults[prop] = {}; + var tmpHash = clipResults[prop]; + for (var dataFormat in tmpHash) { + if (dataFormat && _hasOwn.call(tmpHash, dataFormat) && _hasOwn.call(formatMap, dataFormat)) { + newResults[prop][formatMap[dataFormat]] = tmpHash[dataFormat]; + } + } + } + } + } + return newResults; + }; + /** + * Will look at a path, and will create a "?noCache={time}" or "&noCache={time}" + * query param string to return. Does NOT append that string to the original path. + * This is useful because ExternalInterface often breaks when a Flash SWF is cached. + * + * @returns The `noCache` query param with necessary "?"/"&" prefix. + * @private + */ + var _cacheBust = function(path, options) { + var cacheBust = options == null || options && options.cacheBust === true; + if (cacheBust) { + return (path.indexOf("?") === -1 ? "?" : "&") + "noCache=" + _now(); + } else { + return ""; + } + }; + /** + * Creates a query string for the FlashVars param. + * Does NOT include the cache-busting query param. + * + * @returns FlashVars query string + * @private + */ + var _vars = function(options) { + var i, len, domain, domains, str = "", trustedOriginsExpanded = []; + if (options.trustedDomains) { + if (typeof options.trustedDomains === "string") { + domains = [ options.trustedDomains ]; + } else if (typeof options.trustedDomains === "object" && "length" in options.trustedDomains) { + domains = options.trustedDomains; + } + } + if (domains && domains.length) { + for (i = 0, len = domains.length; i < len; i++) { + if (_hasOwn.call(domains, i) && domains[i] && typeof domains[i] === "string") { + domain = _extractDomain(domains[i]); + if (!domain) { + continue; + } + if (domain === "*") { + trustedOriginsExpanded.length = 0; + trustedOriginsExpanded.push(domain); + break; + } + trustedOriginsExpanded.push.apply(trustedOriginsExpanded, [ domain, "//" + domain, _window.location.protocol + "//" + domain ]); + } + } + } + if (trustedOriginsExpanded.length) { + str += "trustedOrigins=" + _encodeURIComponent(trustedOriginsExpanded.join(",")); + } + if (options.forceEnhancedClipboard === true) { + str += (str ? "&" : "") + "forceEnhancedClipboard=true"; + } + if (typeof options.swfObjectId === "string" && options.swfObjectId) { + str += (str ? "&" : "") + "swfObjectId=" + _encodeURIComponent(options.swfObjectId); + } + if (typeof options.jsVersion === "string" && options.jsVersion) { + str += (str ? "&" : "") + "jsVersion=" + _encodeURIComponent(options.jsVersion); + } + return str; + }; + /** + * Extract the domain (e.g. "github.com") from an origin (e.g. "https://github.com") or + * URL (e.g. "https://github.com/zeroclipboard/zeroclipboard/"). + * + * @returns the domain + * @private + */ + var _extractDomain = function(originOrUrl) { + if (originOrUrl == null || originOrUrl === "") { + return null; + } + originOrUrl = originOrUrl.replace(/^\s+|\s+$/g, ""); + if (originOrUrl === "") { + return null; + } + var protocolIndex = originOrUrl.indexOf("//"); + originOrUrl = protocolIndex === -1 ? originOrUrl : originOrUrl.slice(protocolIndex + 2); + var pathIndex = originOrUrl.indexOf("/"); + originOrUrl = pathIndex === -1 ? originOrUrl : protocolIndex === -1 || pathIndex === 0 ? null : originOrUrl.slice(0, pathIndex); + if (originOrUrl && originOrUrl.slice(-4).toLowerCase() === ".swf") { + return null; + } + return originOrUrl || null; + }; + /** + * Set `allowScriptAccess` based on `trustedDomains` and `window.location.host` vs. `swfPath`. + * + * @returns The appropriate script access level. + * @private + */ + var _determineScriptAccess = function() { + var _extractAllDomains = function(origins) { + var i, len, tmp, resultsArray = []; + if (typeof origins === "string") { + origins = [ origins ]; + } + if (!(typeof origins === "object" && origins && typeof origins.length === "number")) { + return resultsArray; + } + for (i = 0, len = origins.length; i < len; i++) { + if (_hasOwn.call(origins, i) && (tmp = _extractDomain(origins[i]))) { + if (tmp === "*") { + resultsArray.length = 0; + resultsArray.push("*"); + break; + } + if (resultsArray.indexOf(tmp) === -1) { + resultsArray.push(tmp); + } + } + } + return resultsArray; + }; + return function(currentDomain, configOptions) { + var swfDomain = _extractDomain(configOptions.swfPath); + if (swfDomain === null) { + swfDomain = currentDomain; + } + var trustedDomains = _extractAllDomains(configOptions.trustedDomains); + var len = trustedDomains.length; + if (len > 0) { + if (len === 1 && trustedDomains[0] === "*") { + return "always"; + } + if (trustedDomains.indexOf(currentDomain) !== -1) { + if (len === 1 && currentDomain === swfDomain) { + return "sameDomain"; + } + return "always"; + } + } + return "never"; + }; + }(); + /** + * Get the currently active/focused DOM element. + * + * @returns the currently active/focused element, or `null` + * @private + */ + var _safeActiveElement = function() { + try { + return _document.activeElement; + } catch (err) { + return null; + } + }; + /** + * Add a class to an element, if it doesn't already have it. + * + * @returns The element, with its new class added. + * @private + */ + var _addClass = function(element, value) { + var c, cl, className, classNames = []; + if (typeof value === "string" && value) { + classNames = value.split(/\s+/); + } + if (element && element.nodeType === 1 && classNames.length > 0) { + if (element.classList) { + for (c = 0, cl = classNames.length; c < cl; c++) { + element.classList.add(classNames[c]); + } + } else if (element.hasOwnProperty("className")) { + className = " " + element.className + " "; + for (c = 0, cl = classNames.length; c < cl; c++) { + if (className.indexOf(" " + classNames[c] + " ") === -1) { + className += classNames[c] + " "; + } + } + element.className = className.replace(/^\s+|\s+$/g, ""); + } + } + return element; + }; + /** + * Remove a class from an element, if it has it. + * + * @returns The element, with its class removed. + * @private + */ + var _removeClass = function(element, value) { + var c, cl, className, classNames = []; + if (typeof value === "string" && value) { + classNames = value.split(/\s+/); + } + if (element && element.nodeType === 1 && classNames.length > 0) { + if (element.classList && element.classList.length > 0) { + for (c = 0, cl = classNames.length; c < cl; c++) { + element.classList.remove(classNames[c]); + } + } else if (element.className) { + className = (" " + element.className + " ").replace(/[\r\n\t]/g, " "); + for (c = 0, cl = classNames.length; c < cl; c++) { + className = className.replace(" " + classNames[c] + " ", " "); + } + element.className = className.replace(/^\s+|\s+$/g, ""); + } + } + return element; + }; + /** + * Attempt to interpret the element's CSS styling. If `prop` is `"cursor"`, + * then we assume that it should be a hand ("pointer") cursor if the element + * is an anchor element ("a" tag). + * + * @returns The computed style property. + * @private + */ + var _getStyle = function(el, prop) { + var value = _getComputedStyle(el, null).getPropertyValue(prop); + if (prop === "cursor") { + if (!value || value === "auto") { + if (el.nodeName === "A") { + return "pointer"; + } + } + } + return value; + }; + /** + * Get the absolutely positioned coordinates of a DOM element. + * + * @returns Object containing the element's position, width, and height. + * @private + */ + var _getElementPosition = function(el) { + var pos = { + left: 0, + top: 0, + width: 0, + height: 0 + }; + if (el.getBoundingClientRect) { + var elRect = el.getBoundingClientRect(); + var pageXOffset = _window.pageXOffset; + var pageYOffset = _window.pageYOffset; + var leftBorderWidth = _document.documentElement.clientLeft || 0; + var topBorderWidth = _document.documentElement.clientTop || 0; + var leftBodyOffset = 0; + var topBodyOffset = 0; + if (_getStyle(_document.body, "position") === "relative") { + var bodyRect = _document.body.getBoundingClientRect(); + var htmlRect = _document.documentElement.getBoundingClientRect(); + leftBodyOffset = bodyRect.left - htmlRect.left || 0; + topBodyOffset = bodyRect.top - htmlRect.top || 0; + } + pos.left = elRect.left + pageXOffset - leftBorderWidth - leftBodyOffset; + pos.top = elRect.top + pageYOffset - topBorderWidth - topBodyOffset; + pos.width = "width" in elRect ? elRect.width : elRect.right - elRect.left; + pos.height = "height" in elRect ? elRect.height : elRect.bottom - elRect.top; + } + return pos; + }; + /** + * Determine is an element is visible somewhere within the document (page). + * + * @returns Boolean + * @private + */ + var _isElementVisible = function(el) { + if (!el) { + return false; + } + var styles = _getComputedStyle(el, null); + var hasCssHeight = _parseFloat(styles.height) > 0; + var hasCssWidth = _parseFloat(styles.width) > 0; + var hasCssTop = _parseFloat(styles.top) >= 0; + var hasCssLeft = _parseFloat(styles.left) >= 0; + var cssKnows = hasCssHeight && hasCssWidth && hasCssTop && hasCssLeft; + var rect = cssKnows ? null : _getElementPosition(el); + var isVisible = styles.display !== "none" && styles.visibility !== "collapse" && (cssKnows || !!rect && (hasCssHeight || rect.height > 0) && (hasCssWidth || rect.width > 0) && (hasCssTop || rect.top >= 0) && (hasCssLeft || rect.left >= 0)); + return isVisible; + }; + /** + * Clear all existing timeouts and interval polling delegates. + * + * @returns `undefined` + * @private + */ + var _clearTimeoutsAndPolling = function() { + _clearTimeout(_flashCheckTimeout); + _flashCheckTimeout = 0; + _clearInterval(_swfFallbackCheckInterval); + _swfFallbackCheckInterval = 0; + }; + /** + * Reposition the Flash object to cover the currently activated element. + * + * @returns `undefined` + * @private + */ + var _reposition = function() { + var htmlBridge; + if (_currentElement && (htmlBridge = _getHtmlBridge(_flashState.bridge))) { + var pos = _getElementPosition(_currentElement); + _extend(htmlBridge.style, { + width: pos.width + "px", + height: pos.height + "px", + top: pos.top + "px", + left: pos.left + "px", + zIndex: "" + _getSafeZIndex(_globalConfig.zIndex) + }); + } + }; + /** + * Sends a signal to the Flash object to display the hand cursor if `true`. + * + * @returns `undefined` + * @private + */ + var _setHandCursor = function(enabled) { + if (_flashState.ready === true) { + if (_flashState.bridge && typeof _flashState.bridge.setHandCursor === "function") { + _flashState.bridge.setHandCursor(enabled); + } else { + _flashState.ready = false; + } + } + }; + /** + * Get a safe value for `zIndex` + * + * @returns an integer, or "auto" + * @private + */ + var _getSafeZIndex = function(val) { + if (/^(?:auto|inherit)$/.test(val)) { + return val; + } + var zIndex; + if (typeof val === "number" && !_isNaN(val)) { + zIndex = val; + } else if (typeof val === "string") { + zIndex = _getSafeZIndex(_parseInt(val, 10)); + } + return typeof zIndex === "number" ? zIndex : "auto"; + }; + /** + * Attempt to detect if ZeroClipboard is executing inside of a sandboxed iframe. + * If it is, Flash Player cannot be used, so ZeroClipboard is dead in the water. + * + * @see {@link http://lists.w3.org/Archives/Public/public-whatwg-archive/2014Dec/0002.html} + * @see {@link https://github.com/zeroclipboard/zeroclipboard/issues/511} + * @see {@link http://zeroclipboard.org/test-iframes.html} + * + * @returns `true` (is sandboxed), `false` (is not sandboxed), or `null` (uncertain) + * @private + */ + var _detectSandbox = function(doNotReassessFlashSupport) { + var effectiveScriptOrigin, frame, frameError, previousState = _flashState.sandboxed, isSandboxed = null; + doNotReassessFlashSupport = doNotReassessFlashSupport === true; + if (_pageIsFramed === false) { + isSandboxed = false; + } else { + try { + frame = window.frameElement || null; + } catch (e) { + frameError = { + name: e.name, + message: e.message + }; + } + if (frame && frame.nodeType === 1 && frame.nodeName === "IFRAME") { + try { + isSandboxed = frame.hasAttribute("sandbox"); + } catch (e) { + isSandboxed = null; + } + } else { + try { + effectiveScriptOrigin = document.domain || null; + } catch (e) { + effectiveScriptOrigin = null; + } + if (effectiveScriptOrigin === null || frameError && frameError.name === "SecurityError" && /(^|[\s\(\[@])sandbox(es|ed|ing|[\s\.,!\)\]@]|$)/.test(frameError.message.toLowerCase())) { + isSandboxed = true; + } + } + } + _flashState.sandboxed = isSandboxed; + if (previousState !== isSandboxed && !doNotReassessFlashSupport) { + _detectFlashSupport(_ActiveXObject); + } + return isSandboxed; + }; + /** + * Detect the Flash Player status, version, and plugin type. + * + * @see {@link https://code.google.com/p/doctype-mirror/wiki/ArticleDetectFlash#The_code} + * @see {@link http://stackoverflow.com/questions/12866060/detecting-pepper-ppapi-flash-with-javascript} + * + * @returns `undefined` + * @private + */ + var _detectFlashSupport = function(ActiveXObject) { + var plugin, ax, mimeType, hasFlash = false, isActiveX = false, isPPAPI = false, flashVersion = ""; + /** + * Derived from Apple's suggested sniffer. + * @param {String} desc e.g. "Shockwave Flash 7.0 r61" + * @returns {String} "7.0.61" + * @private + */ + function parseFlashVersion(desc) { + var matches = desc.match(/[\d]+/g); + matches.length = 3; + return matches.join("."); + } + function isPepperFlash(flashPlayerFileName) { + return !!flashPlayerFileName && (flashPlayerFileName = flashPlayerFileName.toLowerCase()) && (/^(pepflashplayer\.dll|libpepflashplayer\.so|pepperflashplayer\.plugin)$/.test(flashPlayerFileName) || flashPlayerFileName.slice(-13) === "chrome.plugin"); + } + function inspectPlugin(plugin) { + if (plugin) { + hasFlash = true; + if (plugin.version) { + flashVersion = parseFlashVersion(plugin.version); + } + if (!flashVersion && plugin.description) { + flashVersion = parseFlashVersion(plugin.description); + } + if (plugin.filename) { + isPPAPI = isPepperFlash(plugin.filename); + } + } + } + if (_navigator.plugins && _navigator.plugins.length) { + plugin = _navigator.plugins["Shockwave Flash"]; + inspectPlugin(plugin); + if (_navigator.plugins["Shockwave Flash 2.0"]) { + hasFlash = true; + flashVersion = "2.0.0.11"; + } + } else if (_navigator.mimeTypes && _navigator.mimeTypes.length) { + mimeType = _navigator.mimeTypes["application/x-shockwave-flash"]; + plugin = mimeType && mimeType.enabledPlugin; + inspectPlugin(plugin); + } else if (typeof ActiveXObject !== "undefined") { + isActiveX = true; + try { + ax = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7"); + hasFlash = true; + flashVersion = parseFlashVersion(ax.GetVariable("$version")); + } catch (e1) { + try { + ax = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"); + hasFlash = true; + flashVersion = "6.0.21"; + } catch (e2) { + try { + ax = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"); + hasFlash = true; + flashVersion = parseFlashVersion(ax.GetVariable("$version")); + } catch (e3) { + isActiveX = false; + } + } + } + } + _flashState.disabled = hasFlash !== true; + _flashState.outdated = flashVersion && _parseFloat(flashVersion) < _parseFloat(_minimumFlashVersion); + _flashState.version = flashVersion || "0.0.0"; + _flashState.pluginType = isPPAPI ? "pepper" : isActiveX ? "activex" : hasFlash ? "netscape" : "unknown"; + }; + /** + * Invoke the Flash detection algorithms immediately upon inclusion so we're not waiting later. + */ + _detectFlashSupport(_ActiveXObject); + /** + * Always assess the `sandboxed` state of the page at important Flash-related moments. + */ + _detectSandbox(true); + /** + * A shell constructor for `ZeroClipboard` client instances. + * + * @constructor + */ + var ZeroClipboard = function() { + if (!(this instanceof ZeroClipboard)) { + return new ZeroClipboard(); + } + if (typeof ZeroClipboard._createClient === "function") { + ZeroClipboard._createClient.apply(this, _args(arguments)); + } + }; + /** + * The ZeroClipboard library's version number. + * + * @static + * @readonly + * @property {string} + */ + _defineProperty(ZeroClipboard, "version", { + value: "2.2.0", + writable: false, + configurable: true, + enumerable: true + }); + /** + * Update or get a copy of the ZeroClipboard global configuration. + * Returns a copy of the current/updated configuration. + * + * @returns Object + * @static + */ + ZeroClipboard.config = function() { + return _config.apply(this, _args(arguments)); + }; + /** + * Diagnostic method that describes the state of the browser, Flash Player, and ZeroClipboard. + * + * @returns Object + * @static + */ + ZeroClipboard.state = function() { + return _state.apply(this, _args(arguments)); + }; + /** + * Check if Flash is unusable for any reason: disabled, outdated, deactivated, etc. + * + * @returns Boolean + * @static + */ + ZeroClipboard.isFlashUnusable = function() { + return _isFlashUnusable.apply(this, _args(arguments)); + }; + /** + * Register an event listener. + * + * @returns `ZeroClipboard` + * @static + */ + ZeroClipboard.on = function() { + return _on.apply(this, _args(arguments)); + }; + /** + * Unregister an event listener. + * If no `listener` function/object is provided, it will unregister all listeners for the provided `eventType`. + * If no `eventType` is provided, it will unregister all listeners for every event type. + * + * @returns `ZeroClipboard` + * @static + */ + ZeroClipboard.off = function() { + return _off.apply(this, _args(arguments)); + }; + /** + * Retrieve event listeners for an `eventType`. + * If no `eventType` is provided, it will retrieve all listeners for every event type. + * + * @returns array of listeners for the `eventType`; if no `eventType`, then a map/hash object of listeners for all event types; or `null` + */ + ZeroClipboard.handlers = function() { + return _listeners.apply(this, _args(arguments)); + }; + /** + * Event emission receiver from the Flash object, forwarding to any registered JavaScript event listeners. + * + * @returns For the "copy" event, returns the Flash-friendly "clipData" object; otherwise `undefined`. + * @static + */ + ZeroClipboard.emit = function() { + return _emit.apply(this, _args(arguments)); + }; + /** + * Create and embed the Flash object. + * + * @returns The Flash object + * @static + */ + ZeroClipboard.create = function() { + return _create.apply(this, _args(arguments)); + }; + /** + * Self-destruct and clean up everything, including the embedded Flash object. + * + * @returns `undefined` + * @static + */ + ZeroClipboard.destroy = function() { + return _destroy.apply(this, _args(arguments)); + }; + /** + * Set the pending data for clipboard injection. + * + * @returns `undefined` + * @static + */ + ZeroClipboard.setData = function() { + return _setData.apply(this, _args(arguments)); + }; + /** + * Clear the pending data for clipboard injection. + * If no `format` is provided, all pending data formats will be cleared. + * + * @returns `undefined` + * @static + */ + ZeroClipboard.clearData = function() { + return _clearData.apply(this, _args(arguments)); + }; + /** + * Get a copy of the pending data for clipboard injection. + * If no `format` is provided, a copy of ALL pending data formats will be returned. + * + * @returns `String` or `Object` + * @static + */ + ZeroClipboard.getData = function() { + return _getData.apply(this, _args(arguments)); + }; + /** + * Sets the current HTML object that the Flash object should overlay. This will put the global + * Flash object on top of the current element; depending on the setup, this may also set the + * pending clipboard text data as well as the Flash object's wrapping element's title attribute + * based on the underlying HTML element and ZeroClipboard configuration. + * + * @returns `undefined` + * @static + */ + ZeroClipboard.focus = ZeroClipboard.activate = function() { + return _focus.apply(this, _args(arguments)); + }; + /** + * Un-overlays the Flash object. This will put the global Flash object off-screen; depending on + * the setup, this may also unset the Flash object's wrapping element's title attribute based on + * the underlying HTML element and ZeroClipboard configuration. + * + * @returns `undefined` + * @static + */ + ZeroClipboard.blur = ZeroClipboard.deactivate = function() { + return _blur.apply(this, _args(arguments)); + }; + /** + * Returns the currently focused/"activated" HTML element that the Flash object is wrapping. + * + * @returns `HTMLElement` or `null` + * @static + */ + ZeroClipboard.activeElement = function() { + return _activeElement.apply(this, _args(arguments)); + }; + /** + * Keep track of the ZeroClipboard client instance counter. + */ + var _clientIdCounter = 0; + /** + * Keep track of the state of the client instances. + * + * Entry structure: + * _clientMeta[client.id] = { + * instance: client, + * elements: [], + * handlers: {} + * }; + */ + var _clientMeta = {}; + /** + * Keep track of the ZeroClipboard clipped elements counter. + */ + var _elementIdCounter = 0; + /** + * Keep track of the state of the clipped element relationships to clients. + * + * Entry structure: + * _elementMeta[element.zcClippingId] = [client1.id, client2.id]; + */ + var _elementMeta = {}; + /** + * Keep track of the state of the mouse event handlers for clipped elements. + * + * Entry structure: + * _mouseHandlers[element.zcClippingId] = { + * mouseover: function(event) {}, + * mouseout: function(event) {}, + * mouseenter: function(event) {}, + * mouseleave: function(event) {}, + * mousemove: function(event) {} + * }; + */ + var _mouseHandlers = {}; + /** + * Extending the ZeroClipboard configuration defaults for the Client module. + */ + _extend(_globalConfig, { + autoActivate: true + }); + /** + * The real constructor for `ZeroClipboard` client instances. + * @private + */ + var _clientConstructor = function(elements) { + var client = this; + client.id = "" + _clientIdCounter++; + _clientMeta[client.id] = { + instance: client, + elements: [], + handlers: {} + }; + if (elements) { + client.clip(elements); + } + ZeroClipboard.on("*", function(event) { + return client.emit(event); + }); + ZeroClipboard.on("destroy", function() { + client.destroy(); + }); + ZeroClipboard.create(); + }; + /** + * The underlying implementation of `ZeroClipboard.Client.prototype.on`. + * @private + */ + var _clientOn = function(eventType, listener) { + var i, len, events, added = {}, meta = _clientMeta[this.id], handlers = meta && meta.handlers; + if (!meta) { + throw new Error("Attempted to add new listener(s) to a destroyed ZeroClipboard client instance"); + } + if (typeof eventType === "string" && eventType) { + events = eventType.toLowerCase().split(/\s+/); + } else if (typeof eventType === "object" && eventType && typeof listener === "undefined") { + for (i in eventType) { + if (_hasOwn.call(eventType, i) && typeof i === "string" && i && typeof eventType[i] === "function") { + this.on(i, eventType[i]); + } + } + } + if (events && events.length) { + for (i = 0, len = events.length; i < len; i++) { + eventType = events[i].replace(/^on/, ""); + added[eventType] = true; + if (!handlers[eventType]) { + handlers[eventType] = []; + } + handlers[eventType].push(listener); + } + if (added.ready && _flashState.ready) { + this.emit({ + type: "ready", + client: this + }); + } + if (added.error) { + for (i = 0, len = _flashStateErrorNames.length; i < len; i++) { + if (_flashState[_flashStateErrorNames[i].replace(/^flash-/, "")]) { + this.emit({ + type: "error", + name: _flashStateErrorNames[i], + client: this + }); + break; + } + } + if (_zcSwfVersion !== undefined && ZeroClipboard.version !== _zcSwfVersion) { + this.emit({ + type: "error", + name: "version-mismatch", + jsVersion: ZeroClipboard.version, + swfVersion: _zcSwfVersion + }); + } + } + } + return this; + }; + /** + * The underlying implementation of `ZeroClipboard.Client.prototype.off`. + * @private + */ + var _clientOff = function(eventType, listener) { + var i, len, foundIndex, events, perEventHandlers, meta = _clientMeta[this.id], handlers = meta && meta.handlers; + if (!handlers) { + return this; + } + if (arguments.length === 0) { + events = _keys(handlers); + } else if (typeof eventType === "string" && eventType) { + events = eventType.split(/\s+/); + } else if (typeof eventType === "object" && eventType && typeof listener === "undefined") { + for (i in eventType) { + if (_hasOwn.call(eventType, i) && typeof i === "string" && i && typeof eventType[i] === "function") { + this.off(i, eventType[i]); + } + } + } + if (events && events.length) { + for (i = 0, len = events.length; i < len; i++) { + eventType = events[i].toLowerCase().replace(/^on/, ""); + perEventHandlers = handlers[eventType]; + if (perEventHandlers && perEventHandlers.length) { + if (listener) { + foundIndex = perEventHandlers.indexOf(listener); + while (foundIndex !== -1) { + perEventHandlers.splice(foundIndex, 1); + foundIndex = perEventHandlers.indexOf(listener, foundIndex); + } + } else { + perEventHandlers.length = 0; + } + } + } + } + return this; + }; + /** + * The underlying implementation of `ZeroClipboard.Client.prototype.handlers`. + * @private + */ + var _clientListeners = function(eventType) { + var copy = null, handlers = _clientMeta[this.id] && _clientMeta[this.id].handlers; + if (handlers) { + if (typeof eventType === "string" && eventType) { + copy = handlers[eventType] ? handlers[eventType].slice(0) : []; + } else { + copy = _deepCopy(handlers); + } + } + return copy; + }; + /** + * The underlying implementation of `ZeroClipboard.Client.prototype.emit`. + * @private + */ + var _clientEmit = function(event) { + if (_clientShouldEmit.call(this, event)) { + if (typeof event === "object" && event && typeof event.type === "string" && event.type) { + event = _extend({}, event); + } + var eventCopy = _extend({}, _createEvent(event), { + client: this + }); + _clientDispatchCallbacks.call(this, eventCopy); + } + return this; + }; + /** + * The underlying implementation of `ZeroClipboard.Client.prototype.clip`. + * @private + */ + var _clientClip = function(elements) { + if (!_clientMeta[this.id]) { + throw new Error("Attempted to clip element(s) to a destroyed ZeroClipboard client instance"); + } + elements = _prepClip(elements); + for (var i = 0; i < elements.length; i++) { + if (_hasOwn.call(elements, i) && elements[i] && elements[i].nodeType === 1) { + if (!elements[i].zcClippingId) { + elements[i].zcClippingId = "zcClippingId_" + _elementIdCounter++; + _elementMeta[elements[i].zcClippingId] = [ this.id ]; + if (_globalConfig.autoActivate === true) { + _addMouseHandlers(elements[i]); + } + } else if (_elementMeta[elements[i].zcClippingId].indexOf(this.id) === -1) { + _elementMeta[elements[i].zcClippingId].push(this.id); + } + var clippedElements = _clientMeta[this.id] && _clientMeta[this.id].elements; + if (clippedElements.indexOf(elements[i]) === -1) { + clippedElements.push(elements[i]); + } + } + } + return this; + }; + /** + * The underlying implementation of `ZeroClipboard.Client.prototype.unclip`. + * @private + */ + var _clientUnclip = function(elements) { + var meta = _clientMeta[this.id]; + if (!meta) { + return this; + } + var clippedElements = meta.elements; + var arrayIndex; + if (typeof elements === "undefined") { + elements = clippedElements.slice(0); + } else { + elements = _prepClip(elements); + } + for (var i = elements.length; i--; ) { + if (_hasOwn.call(elements, i) && elements[i] && elements[i].nodeType === 1) { + arrayIndex = 0; + while ((arrayIndex = clippedElements.indexOf(elements[i], arrayIndex)) !== -1) { + clippedElements.splice(arrayIndex, 1); + } + var clientIds = _elementMeta[elements[i].zcClippingId]; + if (clientIds) { + arrayIndex = 0; + while ((arrayIndex = clientIds.indexOf(this.id, arrayIndex)) !== -1) { + clientIds.splice(arrayIndex, 1); + } + if (clientIds.length === 0) { + if (_globalConfig.autoActivate === true) { + _removeMouseHandlers(elements[i]); + } + delete elements[i].zcClippingId; + } + } + } + } + return this; + }; + /** + * The underlying implementation of `ZeroClipboard.Client.prototype.elements`. + * @private + */ + var _clientElements = function() { + var meta = _clientMeta[this.id]; + return meta && meta.elements ? meta.elements.slice(0) : []; + }; + /** + * The underlying implementation of `ZeroClipboard.Client.prototype.destroy`. + * @private + */ + var _clientDestroy = function() { + if (!_clientMeta[this.id]) { + return; + } + this.unclip(); + this.off(); + delete _clientMeta[this.id]; + }; + /** + * Inspect an Event to see if the Client (`this`) should honor it for emission. + * @private + */ + var _clientShouldEmit = function(event) { + if (!(event && event.type)) { + return false; + } + if (event.client && event.client !== this) { + return false; + } + var meta = _clientMeta[this.id]; + var clippedEls = meta && meta.elements; + var hasClippedEls = !!clippedEls && clippedEls.length > 0; + var goodTarget = !event.target || hasClippedEls && clippedEls.indexOf(event.target) !== -1; + var goodRelTarget = event.relatedTarget && hasClippedEls && clippedEls.indexOf(event.relatedTarget) !== -1; + var goodClient = event.client && event.client === this; + if (!meta || !(goodTarget || goodRelTarget || goodClient)) { + return false; + } + return true; + }; + /** + * Handle the actual dispatching of events to a client instance. + * + * @returns `undefined` + * @private + */ + var _clientDispatchCallbacks = function(event) { + var meta = _clientMeta[this.id]; + if (!(typeof event === "object" && event && event.type && meta)) { + return; + } + var async = _shouldPerformAsync(event); + var wildcardTypeHandlers = meta && meta.handlers["*"] || []; + var specificTypeHandlers = meta && meta.handlers[event.type] || []; + var handlers = wildcardTypeHandlers.concat(specificTypeHandlers); + if (handlers && handlers.length) { + var i, len, func, context, eventCopy, originalContext = this; + for (i = 0, len = handlers.length; i < len; i++) { + func = handlers[i]; + context = originalContext; + if (typeof func === "string" && typeof _window[func] === "function") { + func = _window[func]; + } + if (typeof func === "object" && func && typeof func.handleEvent === "function") { + context = func; + func = func.handleEvent; + } + if (typeof func === "function") { + eventCopy = _extend({}, event); + _dispatchCallback(func, context, [ eventCopy ], async); + } + } + } + }; + /** + * Prepares the elements for clipping/unclipping. + * + * @returns An Array of elements. + * @private + */ + var _prepClip = function(elements) { + if (typeof elements === "string") { + elements = []; + } + return typeof elements.length !== "number" ? [ elements ] : elements; + }; + /** + * Add a `mouseover` handler function for a clipped element. + * + * @returns `undefined` + * @private + */ + var _addMouseHandlers = function(element) { + if (!(element && element.nodeType === 1)) { + return; + } + var _suppressMouseEvents = function(event) { + if (!(event || (event = _window.event))) { + return; + } + if (event._source !== "js") { + event.stopImmediatePropagation(); + event.preventDefault(); + } + delete event._source; + }; + var _elementMouseOver = function(event) { + if (!(event || (event = _window.event))) { + return; + } + _suppressMouseEvents(event); + ZeroClipboard.focus(element); + }; + element.addEventListener("mouseover", _elementMouseOver, false); + element.addEventListener("mouseout", _suppressMouseEvents, false); + element.addEventListener("mouseenter", _suppressMouseEvents, false); + element.addEventListener("mouseleave", _suppressMouseEvents, false); + element.addEventListener("mousemove", _suppressMouseEvents, false); + _mouseHandlers[element.zcClippingId] = { + mouseover: _elementMouseOver, + mouseout: _suppressMouseEvents, + mouseenter: _suppressMouseEvents, + mouseleave: _suppressMouseEvents, + mousemove: _suppressMouseEvents + }; + }; + /** + * Remove a `mouseover` handler function for a clipped element. + * + * @returns `undefined` + * @private + */ + var _removeMouseHandlers = function(element) { + if (!(element && element.nodeType === 1)) { + return; + } + var mouseHandlers = _mouseHandlers[element.zcClippingId]; + if (!(typeof mouseHandlers === "object" && mouseHandlers)) { + return; + } + var key, val, mouseEvents = [ "move", "leave", "enter", "out", "over" ]; + for (var i = 0, len = mouseEvents.length; i < len; i++) { + key = "mouse" + mouseEvents[i]; + val = mouseHandlers[key]; + if (typeof val === "function") { + element.removeEventListener(key, val, false); + } + } + delete _mouseHandlers[element.zcClippingId]; + }; + /** + * Creates a new ZeroClipboard client instance. + * Optionally, auto-`clip` an element or collection of elements. + * + * @constructor + */ + ZeroClipboard._createClient = function() { + _clientConstructor.apply(this, _args(arguments)); + }; + /** + * Register an event listener to the client. + * + * @returns `this` + */ + ZeroClipboard.prototype.on = function() { + return _clientOn.apply(this, _args(arguments)); + }; + /** + * Unregister an event handler from the client. + * If no `listener` function/object is provided, it will unregister all handlers for the provided `eventType`. + * If no `eventType` is provided, it will unregister all handlers for every event type. + * + * @returns `this` + */ + ZeroClipboard.prototype.off = function() { + return _clientOff.apply(this, _args(arguments)); + }; + /** + * Retrieve event listeners for an `eventType` from the client. + * If no `eventType` is provided, it will retrieve all listeners for every event type. + * + * @returns array of listeners for the `eventType`; if no `eventType`, then a map/hash object of listeners for all event types; or `null` + */ + ZeroClipboard.prototype.handlers = function() { + return _clientListeners.apply(this, _args(arguments)); + }; + /** + * Event emission receiver from the Flash object for this client's registered JavaScript event listeners. + * + * @returns For the "copy" event, returns the Flash-friendly "clipData" object; otherwise `undefined`. + */ + ZeroClipboard.prototype.emit = function() { + return _clientEmit.apply(this, _args(arguments)); + }; + /** + * Register clipboard actions for new element(s) to the client. + * + * @returns `this` + */ + ZeroClipboard.prototype.clip = function() { + return _clientClip.apply(this, _args(arguments)); + }; + /** + * Unregister the clipboard actions of previously registered element(s) on the page. + * If no elements are provided, ALL registered elements will be unregistered. + * + * @returns `this` + */ + ZeroClipboard.prototype.unclip = function() { + return _clientUnclip.apply(this, _args(arguments)); + }; + /** + * Get all of the elements to which this client is clipped. + * + * @returns array of clipped elements + */ + ZeroClipboard.prototype.elements = function() { + return _clientElements.apply(this, _args(arguments)); + }; + /** + * Self-destruct and clean up everything for a single client. + * This will NOT destroy the embedded Flash object. + * + * @returns `undefined` + */ + ZeroClipboard.prototype.destroy = function() { + return _clientDestroy.apply(this, _args(arguments)); + }; + /** + * Stores the pending plain text to inject into the clipboard. + * + * @returns `this` + */ + ZeroClipboard.prototype.setText = function(text) { + if (!_clientMeta[this.id]) { + throw new Error("Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance"); + } + ZeroClipboard.setData("text/plain", text); + return this; + }; + /** + * Stores the pending HTML text to inject into the clipboard. + * + * @returns `this` + */ + ZeroClipboard.prototype.setHtml = function(html) { + if (!_clientMeta[this.id]) { + throw new Error("Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance"); + } + ZeroClipboard.setData("text/html", html); + return this; + }; + /** + * Stores the pending rich text (RTF) to inject into the clipboard. + * + * @returns `this` + */ + ZeroClipboard.prototype.setRichText = function(richText) { + if (!_clientMeta[this.id]) { + throw new Error("Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance"); + } + ZeroClipboard.setData("application/rtf", richText); + return this; + }; + /** + * Stores the pending data to inject into the clipboard. + * + * @returns `this` + */ + ZeroClipboard.prototype.setData = function() { + if (!_clientMeta[this.id]) { + throw new Error("Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance"); + } + ZeroClipboard.setData.apply(this, _args(arguments)); + return this; + }; + /** + * Clears the pending data to inject into the clipboard. + * If no `format` is provided, all pending data formats will be cleared. + * + * @returns `this` + */ + ZeroClipboard.prototype.clearData = function() { + if (!_clientMeta[this.id]) { + throw new Error("Attempted to clear pending clipboard data from a destroyed ZeroClipboard client instance"); + } + ZeroClipboard.clearData.apply(this, _args(arguments)); + return this; + }; + /** + * Gets a copy of the pending data to inject into the clipboard. + * If no `format` is provided, a copy of ALL pending data formats will be returned. + * + * @returns `String` or `Object` + */ + ZeroClipboard.prototype.getData = function() { + if (!_clientMeta[this.id]) { + throw new Error("Attempted to get pending clipboard data from a destroyed ZeroClipboard client instance"); + } + return ZeroClipboard.getData.apply(this, _args(arguments)); + }; + if (typeof define === "function" && define.amd) { + define(function() { + return ZeroClipboard; + }); + } else if (typeof module === "object" && module && typeof module.exports === "object" && module.exports) { + module.exports = ZeroClipboard; + } else { + window.ZeroClipboard = ZeroClipboard; + } +})(function() { + return this || window; +}()); \ No newline at end of file diff -r 20e00017dd60 -r 10974bff4dae web/res/js/ZeroClipboard.swf Binary file web/res/js/ZeroClipboard.swf has changed diff -r 20e00017dd60 -r 10974bff4dae web/res/js/backbone-min.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/res/js/backbone-min.js Tue Dec 29 13:25:14 2015 +0100 @@ -0,0 +1,2 @@ +(function(t){var e=typeof self=="object"&&self.self==self&&self||typeof global=="object"&&global.global==global&&global;if(typeof define==="function"&&define.amd){define(["underscore","jquery","exports"],function(i,r,n){e.Backbone=t(e,n,i,r)})}else if(typeof exports!=="undefined"){var i=require("underscore"),r;try{r=require("jquery")}catch(n){}t(e,exports,i,r)}else{e.Backbone=t(e,{},e._,e.jQuery||e.Zepto||e.ender||e.$)}})(function(t,e,i,r){var n=t.Backbone;var s=Array.prototype.slice;e.VERSION="1.2.3";e.$=r;e.noConflict=function(){t.Backbone=n;return this};e.emulateHTTP=false;e.emulateJSON=false;var a=function(t,e,r){switch(t){case 1:return function(){return i[e](this[r])};case 2:return function(t){return i[e](this[r],t)};case 3:return function(t,n){return i[e](this[r],h(t,this),n)};case 4:return function(t,n,s){return i[e](this[r],h(t,this),n,s)};default:return function(){var t=s.call(arguments);t.unshift(this[r]);return i[e].apply(i,t)}}};var o=function(t,e,r){i.each(e,function(e,n){if(i[n])t.prototype[n]=a(e,n,r)})};var h=function(t,e){if(i.isFunction(t))return t;if(i.isObject(t)&&!e._isModel(t))return u(t);if(i.isString(t))return function(e){return e.get(t)};return t};var u=function(t){var e=i.matches(t);return function(t){return e(t.attributes)}};var l=e.Events={};var c=/\s+/;var f=function(t,e,r,n,s){var a=0,o;if(r&&typeof r==="object"){if(n!==void 0&&"context"in s&&s.context===void 0)s.context=n;for(o=i.keys(r);a7);this._useHashChange=this._wantsHashChange&&this._hasHashChange;this._wantsPushState=!!this.options.pushState;this._hasPushState=!!(this.history&&this.history.pushState);this._usePushState=this._wantsPushState&&this._hasPushState;this.fragment=this.getFragment();this.root=("/"+this.root+"/").replace(O,"/");if(this._wantsHashChange&&this._wantsPushState){if(!this._hasPushState&&!this.atRoot()){var e=this.root.slice(0,-1)||"/";this.location.replace(e+"#"+this.getPath());return true}else if(this._hasPushState&&this.atRoot()){this.navigate(this.getHash(),{replace:true})}}if(!this._hasHashChange&&this._wantsHashChange&&!this._usePushState){this.iframe=document.createElement("iframe");this.iframe.src="javascript:0";this.iframe.style.display="none";this.iframe.tabIndex=-1;var r=document.body;var n=r.insertBefore(this.iframe,r.firstChild).contentWindow;n.document.open();n.document.close();n.location.hash="#"+this.fragment}var s=window.addEventListener||function(t,e){return attachEvent("on"+t,e)};if(this._usePushState){s("popstate",this.checkUrl,false)}else if(this._useHashChange&&!this.iframe){s("hashchange",this.checkUrl,false)}else if(this._wantsHashChange){this._checkUrlInterval=setInterval(this.checkUrl,this.interval)}if(!this.options.silent)return this.loadUrl()},stop:function(){var t=window.removeEventListener||function(t,e){return detachEvent("on"+t,e)};if(this._usePushState){t("popstate",this.checkUrl,false)}else if(this._useHashChange&&!this.iframe){t("hashchange",this.checkUrl,false)}if(this.iframe){document.body.removeChild(this.iframe);this.iframe=null}if(this._checkUrlInterval)clearInterval(this._checkUrlInterval);M.started=false},route:function(t,e){this.handlers.unshift({route:t,callback:e})},checkUrl:function(t){var e=this.getFragment();if(e===this.fragment&&this.iframe){e=this.getHash(this.iframe.contentWindow)}if(e===this.fragment)return false;if(this.iframe)this.navigate(e);this.loadUrl()},loadUrl:function(t){if(!this.matchRoot())return false;t=this.fragment=this.getFragment(t);return i.some(this.handlers,function(e){if(e.route.test(t)){e.callback(t);return true}})},navigate:function(t,e){if(!M.started)return false;if(!e||e===true)e={trigger:!!e};t=this.getFragment(t||"");var i=this.root;if(t===""||t.charAt(0)==="?"){i=i.slice(0,-1)||"/"}var r=i+t;t=this.decodeFragment(t.replace(U,""));if(this.fragment===t)return;this.fragment=t;if(this._usePushState){this.history[e.replace?"replaceState":"pushState"]({},document.title,r)}else if(this._wantsHashChange){this._updateHash(this.location,t,e.replace);if(this.iframe&&t!==this.getHash(this.iframe.contentWindow)){var n=this.iframe.contentWindow;if(!e.replace){n.document.open();n.document.close()}this._updateHash(n.location,t,e.replace)}}else{return this.location.assign(r)}if(e.trigger)return this.loadUrl(t)},_updateHash:function(t,e,i){if(i){var r=t.href.replace(/(javascript:|#).*$/,"");t.replace(r+"#"+e)}else{t.hash="#"+e}}});e.history=new M;var q=function(t,e){var r=this;var n;if(t&&i.has(t,"constructor")){n=t.constructor}else{n=function(){return r.apply(this,arguments)}}i.extend(n,r,e);var s=function(){this.constructor=n};s.prototype=r.prototype;n.prototype=new s;if(t)i.extend(n.prototype,t);n.__super__=r.prototype;return n};y.extend=x.extend=$.extend=I.extend=M.extend=q;var F=function(){throw new Error('A "url" property or function must be specified')};var z=function(t,e){var i=e.error;e.error=function(r){if(i)i.call(e.context,t,r,e);t.trigger("error",t,r,e)}};return e}); +//# sourceMappingURL=backbone-min.map \ No newline at end of file diff -r 20e00017dd60 -r 10974bff4dae web/res/js/backbone-min.map --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/res/js/backbone-min.map Tue Dec 29 13:25:14 2015 +0100 @@ -0,0 +1,1 @@ +{"version":3,"file":"backbone-min.js","sources":["backbone.js"],"names":["factory","root","self","global","define","amd","_","$","exports","Backbone","require","e","jQuery","Zepto","ender","previousBackbone","slice","Array","prototype","VERSION","noConflict","this","emulateHTTP","emulateJSON","addMethod","length","method","attribute","value","iteratee","context","cb","defaultVal","args","call","arguments","unshift","apply","addUnderscoreMethods","Class","methods","each","instance","isFunction","isObject","_isModel","modelMatcher","isString","model","get","attrs","matcher","matches","attributes","Events","eventSplitter","eventsApi","events","name","callback","opts","i","names","keys","test","split","on","internalOn","obj","listening","_events","onApi","ctx","listeners","_listeners","id","listenTo","_listenId","uniqueId","listeningTo","_listeningTo","thisId","objId","count","options","handlers","push","off","offApi","stopListening","ids","isEmpty","remaining","j","handler","_callback","size","once","onceMap","bind","listenToOnce","map","offer","trigger","Math","max","triggerApi","objEvents","allEvents","all","triggerEvents","concat","ev","l","a1","a2","a3","unbind","extend","Model","cid","cidPrefix","collection","parse","defaults","result","set","changed","initialize","validationError","idAttribute","toJSON","clone","sync","attr","escape","has","key","val","_validate","unset","silent","changes","changing","_changing","_previousAttributes","current","prev","isEqual","_pending","clear","hasChanged","changedAttributes","diff","old","previous","previousAttributes","fetch","success","resp","serverAttrs","wrapError","save","validate","wait","isNew","patch","xhr","destroy","defer","url","base","urlError","replace","encodeURIComponent","constructor","isValid","error","modelMethods","values","pairs","invert","pick","omit","chain","Collection","models","comparator","_reset","reset","setOptions","add","remove","merge","addOptions","splice","array","insert","at","min","tail","singular","isArray","removed","_removeModels","toAdd","toRemove","modelMap","sort","sortable","sortAttr","existing","_prepareModel","_addReference","orderChanged","some","index","_removeReference","previousModels","pop","shift","modelId","_byId","where","first","findWhere","Error","sortBy","pluck","invoke","create","callbackOpts","indexOf","_onModelEvent","event","prevId","collectionMethods","forEach","collect","reduce","foldl","inject","reduceRight","foldr","find","detect","filter","select","reject","every","any","include","includes","contains","toArray","head","take","initial","rest","drop","last","without","difference","shuffle","lastIndexOf","sample","partition","groupBy","countBy","indexBy","View","viewOptions","_ensureElement","delegateEventSplitter","tagName","selector","$el","render","_removeElement","setElement","element","undelegateEvents","_setElement","delegateEvents","el","match","delegate","eventName","listener","undelegate","_createElement","document","createElement","className","_setAttributes","type","methodMap","params","dataType","data","contentType","JSON","stringify","_method","beforeSend","setRequestHeader","processData","textStatus","errorThrown","ajax","update","delete","read","Router","routes","_bindRoutes","optionalParam","namedParam","splatParam","escapeRegExp","route","isRegExp","_routeToRegExp","router","history","fragment","_extractParameters","execute","navigate","optional","RegExp","exec","param","decodeURIComponent","History","checkUrl","window","location","routeStripper","rootStripper","pathStripper","started","interval","atRoot","path","pathname","getSearch","matchRoot","decodeFragment","decodeURI","href","getHash","getPath","charAt","getFragment","_usePushState","_wantsHashChange","start","hashChange","_hasHashChange","documentMode","_useHashChange","_wantsPushState","pushState","_hasPushState","iframe","src","style","display","tabIndex","body","iWindow","insertBefore","firstChild","contentWindow","open","close","hash","addEventListener","attachEvent","_checkUrlInterval","setInterval","loadUrl","stop","removeEventListener","detachEvent","removeChild","clearInterval","title","_updateHash","assign","protoProps","staticProps","parent","child","Surrogate","__super__"],"mappings":"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"} \ No newline at end of file diff -r 20e00017dd60 -r 10974bff4dae web/res/js/backbone.js --- a/web/res/js/backbone.js Fri Dec 11 18:11:13 2015 +0100 +++ b/web/res/js/backbone.js Tue Dec 29 13:25:14 2015 +0100 @@ -1,4 +1,1894 @@ -(function(){var t=this;var e=t.Backbone;var i=[];var r=i.push;var s=i.slice;var n=i.splice;var a;if(typeof exports!=="undefined"){a=exports}else{a=t.Backbone={}}a.VERSION="1.0.0";var h=t._;if(!h&&typeof require!=="undefined")h=require("underscore");a.$=t.jQuery||t.Zepto||t.ender||t.$;a.noConflict=function(){t.Backbone=e;return this};a.emulateHTTP=false;a.emulateJSON=false;var o=a.Events={on:function(t,e,i){if(!l(this,"on",t,[e,i])||!e)return this;this._events||(this._events={});var r=this._events[t]||(this._events[t]=[]);r.push({callback:e,context:i,ctx:i||this});return this},once:function(t,e,i){if(!l(this,"once",t,[e,i])||!e)return this;var r=this;var s=h.once(function(){r.off(t,s);e.apply(this,arguments)});s._callback=e;return this.on(t,s,i)},off:function(t,e,i){var r,s,n,a,o,u,c,f;if(!this._events||!l(this,"off",t,[e,i]))return this;if(!t&&!e&&!i){this._events={};return this}a=t?[t]:h.keys(this._events);for(o=0,u=a.length;o").attr(t);this.setElement(e,false)}else{this.setElement(h.result(this,"el"),false)}}});a.sync=function(t,e,i){var r=k[t];h.defaults(i||(i={}),{emulateHTTP:a.emulateHTTP,emulateJSON:a.emulateJSON});var s={type:r,dataType:"json"};if(!i.url){s.url=h.result(e,"url")||U()}if(i.data==null&&e&&(t==="create"||t==="update"||t==="patch")){s.contentType="application/json";s.data=JSON.stringify(i.attrs||e.toJSON(i))}if(i.emulateJSON){s.contentType="application/x-www-form-urlencoded";s.data=s.data?{model:s.data}:{}}if(i.emulateHTTP&&(r==="PUT"||r==="DELETE"||r==="PATCH")){s.type="POST";if(i.emulateJSON)s.data._method=r;var n=i.beforeSend;i.beforeSend=function(t){t.setRequestHeader("X-HTTP-Method-Override",r);if(n)return n.apply(this,arguments)}}if(s.type!=="GET"&&!i.emulateJSON){s.processData=false}if(s.type==="PATCH"&&window.ActiveXObject&&!(window.external&&window.external.msActiveXFilteringEnabled)){s.xhr=function(){return new ActiveXObject("Microsoft.XMLHTTP")}}var o=i.xhr=a.ajax(h.extend(s,i));e.trigger("request",e,o,i);return o};var k={create:"POST",update:"PUT",patch:"PATCH","delete":"DELETE",read:"GET"};a.ajax=function(){return a.$.ajax.apply(a.$,arguments)};var S=a.Router=function(t){t||(t={});if(t.routes)this.routes=t.routes;this._bindRoutes();this.initialize.apply(this,arguments)};var $=/\((.*?)\)/g;var T=/(\(\?)?:\w+/g;var H=/\*\w+/g;var A=/[\-{}\[\]+?.,\\\^$|#\s]/g;h.extend(S.prototype,o,{initialize:function(){},route:function(t,e,i){if(!h.isRegExp(t))t=this._routeToRegExp(t);if(h.isFunction(e)){i=e;e=""}if(!i)i=this[e];var r=this;a.history.route(t,function(s){var n=r._extractParameters(t,s);i&&i.apply(r,n);r.trigger.apply(r,["route:"+e].concat(n));r.trigger("route",e,n);a.history.trigger("route",r,e,n)});return this},navigate:function(t,e){a.history.navigate(t,e);return this},_bindRoutes:function(){if(!this.routes)return;this.routes=h.result(this,"routes");var t,e=h.keys(this.routes);while((t=e.pop())!=null){this.route(t,this.routes[t])}},_routeToRegExp:function(t){t=t.replace(A,"\\$&").replace($,"(?:$1)?").replace(T,function(t,e){return e?t:"([^/]+)"}).replace(H,"(.*?)");return new RegExp("^"+t+"$")},_extractParameters:function(t,e){var i=t.exec(e).slice(1);return h.map(i,function(t){return t?decodeURIComponent(t):null})}});var I=a.History=function(){this.handlers=[];h.bindAll(this,"checkUrl");if(typeof window!=="undefined"){this.location=window.location;this.history=window.history}};var N=/^[#\/]|\s+$/g;var P=/^\/+|\/+$/g;var O=/msie [\w.]+/;var C=/\/$/;I.started=false;h.extend(I.prototype,o,{interval:50,getHash:function(t){var e=(t||this).location.href.match(/#(.*)$/);return e?e[1]:""},getFragment:function(t,e){if(t==null){if(this._hasPushState||!this._wantsHashChange||e){t=this.location.pathname;var i=this.root.replace(C,"");if(!t.indexOf(i))t=t.substr(i.length)}else{t=this.getHash()}}return t.replace(N,"")},start:function(t){if(I.started)throw new Error("Backbone.history has already been started");I.started=true;this.options=h.extend({},{root:"/"},this.options,t);this.root=this.options.root;this._wantsHashChange=this.options.hashChange!==false;this._wantsPushState=!!this.options.pushState;this._hasPushState=!!(this.options.pushState&&this.history&&this.history.pushState);var e=this.getFragment();var i=document.documentMode;var r=O.exec(navigator.userAgent.toLowerCase())&&(!i||i<=7);this.root=("/"+this.root+"/").replace(P,"/");if(r&&this._wantsHashChange){this.iframe=a.$('', { + player_url: player_url, + params: Object.keys(params).reduce(function(a,k){a.push(k+'='+encodeURIComponent(params[k]));return a;},[]).join('&'), + width: this.width, + height: this.height, + id: params.id + })); + + function setup_media_methods () { + var dest = _this.$.find("#" + params.id)[0].contentWindow; + var execute = function(c, v) { + if (v !== undefined) + c = c + "=" + v; + dest.postMessage(c, "*"); + }; + _media.getCurrentTime = function() { - return new IriSP.Model.Time(1000*_player.getCurrentTime()); + return state.time; }; _media.getVolume = function() { - return _player.getVolume() / 100; + return state.volume; }; _media.getPaused = function() { - return _pauseState; + return state.pause; }; _media.getMuted = function() { - return _player.isMuted(); + return state.muted; }; _media.setCurrentTime = function(_milliseconds) { - _seekPause = _pauseState; - return _player.seekTo(_milliseconds / 1000); + execute("seek", _milliseconds / 1000); }; _media.setVolume = function(_vol) { - return _player.setVolume(Math.floor(_vol*100)); + execute("volume", _vol * 100); }; _media.mute = function() { - return _player.mute(); + execute("muted", 1); }; _media.unmute = function() { - return _player.unMute(); + execute("muted", 0); }; _media.play = function() { - return _player.playVideo(); + execute("play"); }; _media.pause = function() { - return _player.pauseVideo(); + execute("pause"); }; - - _player.addEventListener("onStateChange", "onDailymotionStateChange"); - _player.addEventListener("onVideoProgress", "onDailymotionVideoProgress"); - - _player.cueVideoByUrl(_this.video); - - _media.trigger("loadedmetadata"); - }; - - window.onDailymotionStateChange = function(_state) { - switch(_state) { - case 1: - _media.trigger("play"); - _pauseState = false; - break; - - case 2: - _media.trigger("pause"); - _pauseState = true; - break; - - case 3: - _media.trigger("seeked"); - break; - } - }; - - window.onDailymotionVideoProgress = function(_progress) { - _media.trigger("timeupdate", new IriSP.Model.Time(_progress.mediaTime * 1000)); - }; - - var params = { - "allowScriptAccess" : "always", - "wmode": "opaque" - }; - - var atts = { - id : this.container }; - swfobject.embedSWF("http://www.dailymotion.com/swf?chromeless=1&enableApi=1", this.container, this.width, this.height, "8", null, null, params, atts); - -}; \ No newline at end of file + window.addEventListener("message", function (event) { + // Parse event.data (query-string for to object) + + // Duck-checking if event.data is a string + if (event.data.split === undefined) + return; + + var info = event.data.split("&").map( function(s) { return s.split("="); }).reduce( function(o, v) { o[v[0]] = decodeURIComponent(v[1]); return o; }, {}); + + switch (info.event) { + case "apiready": + state.apiready = true; + setup_media_methods(); + break; + //case "canplay": + // break; + case "durationchange": + if (info.duration.slice(-2) == "sc") { + state.duration = 1000 * Number(info.duration.slice(0, -2)); + _media.setDuration(state.duration); + } + break; + case "ended": + state.pause = true; + break; + case "loadedmetadata": + _media.trigger("loadedmetadata"); + break; + case "pause": + state.pause = true; + _media.trigger("pause"); + break; + case "play": + state.pause = false; + _media.trigger("play"); + break; + //case "playing": + // break; + //case "progress": + // Loading progress + // break; + case "seeked": + state.time = new IriSP.Model.Time(1000 * Number(info.time)); + _media.trigger("seeked"); + break; + case "timeupdate": + state.time = new IriSP.Model.Time(1000 * Number(info.time)); + _media.trigger("timeupdate", state.time); + break; + case "volumechange": + state.muted = (info.muted == "true"); + state.volume = Number(info.volume) / 100; + break; + } + }, false); +}; diff -r 20e00017dd60 -r 10974bff4dae web/res/metadataplayer/EnrichedPlan.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/res/metadataplayer/EnrichedPlan.css Tue Dec 29 13:25:14 2015 +0100 @@ -0,0 +1,207 @@ +.Ldt-EnrichedPlan-Slide { + border-bottom: 2px dotted #ccc; + padding-top: 4px; + cursor: pointer; +} + +.Ldt-EnrichedPlan-SlideItem { + max-height: 3000px; + transition: max-height .6s; +} + +.Ldt-EnrichedPlan-SlideItem.filtered_out { + max-height: 0px; + overflow: hidden; +} + +.Ldt-EnrichedPlan-SlideTimecode { + display: inline-block; + width: 24px; + color: #999 !important; + font-size: 9px !important; + width: 24px; + vertical-align: top; +} + +.Ldt-EnrichedPlan-SlideThumbnail { + display: inline-block; + width: 180px; + height: 100px; + padding-left: 10px; + margin: 0; + vertical-align: top; +} + +.Ldt-EnrichedPlan-SlideThumbnail img { + max-width: 180px; + max-height: 100px; + margin: auto; + border: 1px solid #ccc; +} + +.Ldt-EnrichedPlan-SlideContent { + display: inline-block; + width: calc(100% - 220px); + transition: width .4s; +} + +.Ldt-EnrichedPlan-SlideThumbnail.filtered_out + .Ldt-EnrichedPlan-SlideContent { + width: calc(100% - 40px); +} + +.Ldt-EnrichedPlan-SlideTitle { + display: inline-block; + font-size: 14px; + width: 100%; + height: 1em; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.Ldt-EnrichedPlan-SlideTitle1 { + text-transform: uppercase; + font-size: 13px; + font-weight: 600; +} + +.Ldt-EnrichedPlan-Note { + font-weight: normal; + font-size: 14px; + font-family: Roboto-italic; +} +.Ldt-EnrichedPlan-Note:hover { + background-color: #eee; +} + +.Ldt-EnrichedPlan-Note-Teacher { + color: #e5007e; + font-style: italic; +} +.Ldt-EnrichedPlan-Note-Own { + color: #66ccff; +} +.Ldt-EnrichedPlan-Note-Other { + color: #996633; +} + +.Ldt-EnrichedPlan-Note-Text { + line-height: 22px; + word-wrap: break-word; +} + +.Ldt-EnrichedPlan-Note-Author { + text-transform: uppercase; + font-size: 10px; +} + +.Ldt-EnrichedPlan-Content { + margin-top: 37px; +} + +.Ldt-EnrichedPlan-Controls { + height: 36px; + padding: 9px 0px 6px 0px; + border-bottom: 1px solid #000; + overflow-y: hidden; + overflow-x: hidden; + position: absolute; + top: 0px; + left: 0px; + right: 0px; + z-index: 1; + background-color: #fff; +} + +.Ldt-EnrichedPlan-Control-Label { + display: inline-block; + text-transform: uppercase; + line-height: 10px; + font-family: Roboto; + font-size: 10px; + font-weight: 100; + width: 80px; + position: relative; +} +.Ldt-EnrichedPlan-Controls .Ldt-EnrichedPlan-Search-Input { + float: right; + font-family: Roboto; + font-size: 16px; + width: calc(100% - 340px); +} + +.Ldt-EnrichedPlan-Note.non_matching { + display: none; +} + +.Ldt-EnrichedPlan-Control- { + font-style: normal; +} + /**********************************************************/ +/* Base for label styling */ +.Ldt-EnrichedPlan-Control-Checkbox:not(:checked), +.Ldt-EnrichedPlan-Control-Checkbox:checked { + position: absolute; + left: -9999px; +} +.Ldt-EnrichedPlan-Control-Checkbox:not(:checked) + label, +.Ldt-EnrichedPlan-Control-Checkbox:checked + label { + position: relative; + padding-left: 20px; + cursor: pointer; +} + +/* checkbox aspect */ +.Ldt-EnrichedPlan-Control-Checkbox:not(:checked) + label:before, +.Ldt-EnrichedPlan-Control-Checkbox:checked + label:before { + content: ''; + position: absolute; + left:0; top: 2px; + width: 13px; height: 13px; + border: 1px solid #aaa; +} +/* checked mark aspect */ +.Ldt-EnrichedPlan-Control-Checkbox:not(:checked) + label:after, +.Ldt-EnrichedPlan-Control-Checkbox:checked + label:after { + content: '\2a2f'; + font-style: normal; + position: absolute; + top: 3px; left: -1px; + font-size: 20px; + transition: all .2s; +} +/* checked mark aspect changes */ +.Ldt-EnrichedPlan-Control-Checkbox:not(:checked) + label:after { + opacity: 0; +} +.Ldt-EnrichedPlan-Control-Checkbox:checked + label:after { + opacity: 1; +} +/* disabled checkbox */ +.Ldt-EnrichedPlan-Control-Checkbox:disabled:not(:checked) + label:before, +.Ldt-EnrichedPlan-Control-Checkbox:disabled:checked + label:before { + box-shadow: none; + border-color: #bbb; + background-color: #ddd; +} +.Ldt-EnrichedPlan-Control-Checkbox:disabled:checked + label:after { + color: #999; +} +.Ldt-EnrichedPlan-Control-Checkbox:disabled + label { + color: #aaa; +} +/* accessibility */ +.Ldt-EnrichedPlan-Control-Checkbox:checked:focus + label:before, +.Ldt-EnrichedPlan-Control-Checkbox:not(:checked):focus + label:before { + border: 1px dotted blue; +} + +/* hover style just for information */ +label:hover:before { + border: 1px solid #4778d9!important; +} + +/* hover style just for information */ +label:hover:before { + background-color: #ededed; +} diff -r 20e00017dd60 -r 10974bff4dae web/res/metadataplayer/EnrichedPlan.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/res/metadataplayer/EnrichedPlan.js Tue Dec 29 13:25:14 2015 +0100 @@ -0,0 +1,145 @@ +/* TODO +- add callbacks + */ + +IriSP.Widgets.EnrichedPlan = function(player, config) { + IriSP.Widgets.Widget.call(this, player, config); +} + +IriSP.Widgets.EnrichedPlan.prototype = new IriSP.Widgets.Widget(); + +IriSP.Widgets.EnrichedPlan.prototype.defaults = { + // Main type for slide segmentation + annotation_type: "Slides", + // If no annotation type list is specified, use all other types + annotation_types: [], + show_controls: true, + show_slides: true, + show_teacher_notes: true, + show_other_notes: true, + show_own_notes: true +} + +IriSP.Widgets.EnrichedPlan.prototype.template = + '
' + + '{{#show_controls}}
' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '
{{/show_controls}}' + + '
' + + '
'; + +IriSP.Widgets.EnrichedPlan.prototype.slideTemplate = + '
' + + '
{{ begin }}
' + + '
' + + '
' + + '
{{ atitle }}
' + + '
{{{ notes }}}
' + + '
' + + '
'; + +IriSP.Widgets.EnrichedPlan.prototype.annotationTemplate = '
{{{ text }}} {{ author }}
'; + +IriSP.Widgets.EnrichedPlan.prototype.draw = function() { + var _this = this; + // Generate a unique prefix, so that ids of input fields + // (necessary for label association) are unique too. + _this.prefix = "TODO"; + // slides content: title, level (for toc) + var _slides = this.getWidgetAnnotations().sortBy(function(_annotation) { + return _annotation.begin; + }); + // All other annotations + var _annotations = this.media.getAnnotations().filter( function (a) { + return a.getAnnotationType().title != _this.annotation_type; + }).sortBy(function(_annotation) { + return _annotation.begin; + }); + + // Reference annotations in each slide: assume that end time is + // correctly set. + _slides.forEach( function (slide) { + slide.annotations = _annotations.filter( function (a) { + return a.begin >= slide.begin && a.begin <= slide.end; + }); + }); + + _this.renderTemplate(); + var container = _this.$.find('.Ldt-EnrichedPlan-Container'); + var content = _this.$.find('.Ldt-EnrichedPlan-Content'); + + // Returns the note category: Own, Other, Teacher + function note_category(a) { + return a.title.indexOf('Anonyme') < 0 ? "Own" : "Other"; + }; + + _slides.forEach(function(slide) { + var _html = Mustache.to_html(_this.slideTemplate, { + id : slide.id, + atitle : IriSP.textFieldHtml(slide.title), + level: slide.content.level || 1, + begin : slide.begin.toString(), + begintc: slide.begin.milliseconds, + thumbnail: slide.thumbnail, + show_slides: _this.show_slides, + notes: slide.annotations.map( function (a) { + return Mustache.to_html(_this.annotationTemplate, { + id: a.id, + text: IriSP.textFieldHtml(a.description || a.title), + author: a.creator, + begin: a.begin.toString(), + begintc: a.begin.milliseconds, + atitle: a.title.slice(0, 20), + // FIXME: Temporary hack waiting for a proper metadata definition + category: "Ldt-EnrichedPlan-Note-" + note_category(a), + filtered: ( (note_category(a) == 'Own' && ! _this.show_own_notes) + || (note_category(a) == 'Other' && ! _this.show_other_notes) + || (note_category(a) == 'Teacher' && ! _this.show_teacher_notes) ) ? 'filtered_out' : '' + }); + }).join("\n") + }); + var _el = IriSP.jQuery(_html); + content.append(_el); + }); + + container.on("click", "[data-timecode]", function () { + _this.media.setCurrentTime(Number(this.dataset.timecode)); + }); + + container.on("click", ".Ldt-EnrichedPlan-Control-Checkbox", function () { + var classname = _.first(_.filter(this.classList, function (s) { return s != "Ldt-EnrichedPlan-Control-Checkbox"; })); + if (classname !== undefined) { + if ($(this).is(':checked')) { + content.find(".Ldt-EnrichedPlan-Slide ." + classname).removeClass("filtered_out"); + } else { + content.find(".Ldt-EnrichedPlan-Slide ." + classname).addClass("filtered_out"); + } + } + + }); + + container.find(".Ldt-EnrichedPlan-Search-Input").on("search", function () { + var q = $(this).val().toLocaleLowerCase(); + if (q === "") { + // Show all + content.find(".Ldt-EnrichedPlan-Note").removeClass("non_matching"); + } else { + $(".Ldt-EnrichedPlan-Note").each( function () { + var node = $(this); + if (node.text().toLocaleLowerCase().indexOf(q) > -1) { + node.removeClass("non_matching"); + } else { + node.addClass("non_matching"); + } + }); + } + }); +}; diff -r 20e00017dd60 -r 10974bff4dae web/res/metadataplayer/ImageDisplay.css --- a/web/res/metadataplayer/ImageDisplay.css Fri Dec 11 18:11:13 2015 +0100 +++ b/web/res/metadataplayer/ImageDisplay.css Tue Dec 29 13:25:14 2015 +0100 @@ -1,6 +1,10 @@ -/* Nothing */ .Ldt-ImageDisplay-Container { - margin: auto; + width: 100%; + height: 100%; + background-color: white; + background-repeat: no-repeat; + background-position: center; + background-size: contain; } .Ldt-ImageDisplay-Image { @@ -9,7 +13,7 @@ } .Ldt-ImageDisplay-Overlay { - width: 20%; + width: 30%; min-width: 20px; height: 100%; opacity: 0.1; @@ -23,10 +27,10 @@ .Ldt-ImageDisplay-Overlay-Left { left: 0px; - cursor: url(img/hand_left.png), pointer; + cursor: url(img/left_arrow.svg) 20 20, pointer; } .Ldt-ImageDisplay-Overlay-Right { right: 0px; - cursor: url(img/hand_right.png), pointer; + cursor: url(img/right_arrow.svg) 20 20, pointer; } diff -r 20e00017dd60 -r 10974bff4dae web/res/metadataplayer/ImageDisplay.js --- a/web/res/metadataplayer/ImageDisplay.js Fri Dec 11 18:11:13 2015 +0100 +++ b/web/res/metadataplayer/ImageDisplay.js Tue Dec 29 13:25:14 2015 +0100 @@ -7,27 +7,27 @@ IriSP.Widgets.ImageDisplay.prototype = new IriSP.Widgets.Widget(); IriSP.Widgets.ImageDisplay.prototype.defaults = { - annotation_type: "Slides", + annotation_type: "Slides" // container: "imageContainer" } -IriSP.Widgets.ImageDisplay.prototype.template = '
Slide Image
'; +IriSP.Widgets.ImageDisplay.prototype.template = '
'; IriSP.Widgets.ImageDisplay.prototype.annotationTemplate = ''; IriSP.Widgets.ImageDisplay.prototype.update = function(annotation) { // Update the widget with data corresponding to the annotation - this.image.setAttribute("title", IriSP.textFieldHtml(annotation.title) + " - " + annotation.begin.toString()); - this.image.setAttribute("src", annotation.thumbnail); + this.image.css("background-image", "url(" + annotation.thumbnail + ")"); + this.image.attr("title", IriSP.textFieldHtml(annotation.title) + " - " + annotation.begin.toString()); }; -IriSP.Widgets.ImageDisplay.prototype.draw = function() { +IriSP.Widgets.ImageDisplay.prototype.draw = function() { var _annotations = this.getWidgetAnnotations().sortBy(function(_annotation) { return _annotation.begin; }); var _this = this; _this.renderTemplate(); - _this.image = _this.$.find("img")[0]; + _this.image = _this.$.find(".Ldt-ImageDisplay-Container"); _this.$.find(".Ldt-ImageDisplay-Overlay-Left").on("click", function () { _this.navigate(-1); }); _this.$.find(".Ldt-ImageDisplay-Overlay-Right").on("click", function () { _this.navigate(+1); }); diff -r 20e00017dd60 -r 10974bff4dae web/res/metadataplayer/LatestAnnotation.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/res/metadataplayer/LatestAnnotation.css Tue Dec 29 13:25:14 2015 +0100 @@ -0,0 +1,63 @@ +.Ldt-LatestAnnotation{ + background: url(img/pinstripe.png); + width: 535px; + max-height: 180px; + margin: 0px; + margin-top: 4px; + border-style: solid; + border-width: 1px; + border-color: #b7b7b7; +} + +.Ldt-LatestAnnotation-Element{ + margin: 5px; + display: inline-block; + vertical-align: top; +} + +.Ldt-LatestAnnotation-Box{ + background-color: #ffffff; + margin: 3px; +} + +.Ldt-LatestAnnotation-CreationDate{ + color: #f7268e; +} + +.Ldt-LatestAnnotation-Content{ + text-align: justify; +} + +.Ldt-LatestAnnotation-Title{ + color: #0068c4; + font-size: 14px; + font-weight: bold; +} + +.Ldt-LatestAnnotation-NoAnnotation{ + font-size: 14px; + font-weight: bold; +} + +.Ldt-LatestAnnotation-CopyEditButton{ + display: inline-block; + background-color: #d93c71; + color: #ffffff; + float: right; + cursor: pointer; + height: 14px; + width: 100px; + margin: 2px; + padding: 2px; + font-size: 11px; + border: 1px solid; + border-color: #eca3bc #631e34 #36101c #e16e93; + cursor: pointer; + text-align: center; + vertical-align: middle; +} + +.Ldt-LatestAnnotation-CopyEditButton:hover{ + background-color: #e15581; + border-color: #222222 #e87d9f #f0adc3 #68273c; +} \ No newline at end of file diff -r 20e00017dd60 -r 10974bff4dae web/res/metadataplayer/LatestAnnotation.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/res/metadataplayer/LatestAnnotation.js Tue Dec 29 13:25:14 2015 +0100 @@ -0,0 +1,303 @@ +/* Widget that displays the last annotation that was posted, optionally for current segment, optionally for a given username */ + +IriSP.Widgets.LatestAnnotation = function(player, config){ + IriSP.Widgets.Widget.call(this, player, config); +}; + +IriSP.Widgets.LatestAnnotation.prototype = new IriSP.Widgets.Widget(); + +IriSP.Widgets.LatestAnnotation.prototype.defaults = { + pre_draw_callback: function(){ + return this.importUsers(); + }, + from_user: false, + filter_by_segment: false, + segments_annotation_type: "chap", + hide_without_segment: false, + annotation_type: "contribution", + /* + * Set to a username if you only want to display annotations from a given user + */ + show_only_annotation_from_user: false, + /* + * Displays a button that copy currently displayed annotation into CreateAnnotation input field + */ + copy_and_edit_button: false, + hide_annotations_list: false, + /* + * Allows clicks on an annotation from Annotations to display the annotation content into this widget + */ + selectable_annotations: false, + empty_message: false, + starts_hidden: false, + show_header: false, + custom_header: false, + make_name_string_function: function(params){ + return params.username ? params.username : "Anonymous"; + }, +}; + +IriSP.Widgets.LatestAnnotation.prototype.messages = { + fr : { + copy_and_edit: "Copier et Editer", + empty : "Aucune annotation à afficher", + header: "Dernière annotation" + }, + en: { + copy_and_edit: "Copy and Edit", + empty: "No annotation to display", + header: "Last annotation" + } +} + +IriSP.Widgets.LatestAnnotation.prototype.template = + "{{#show_header}}" + + "

" + + "{{#custom_header}}{{custom_header}}{{/custom_header}}" + + "{{^custom_header}}{{l10n.header}}{{/custom_header}}" + + "

" + + "{{/show_header}}" + + "
" + + "
"; + +IriSP.Widgets.LatestAnnotation.prototype.annotationTemplate = + "
" + + "{{#copy_and_edit_button}}
{{button_text}}
{{/copy_and_edit_button}}" + + "
{{{annotation_created}}}
" + + "
{{{annotation_creator}}}{{#annotation_title}}: {{{annotation_title}}}{{/annotation_title}}
" + + "
" + + "{{{annotation_content}}}" + + "
" + + "
" + + +IriSP.Widgets.LatestAnnotation.prototype.importUsers = function(){ + if (!this.source.users_data){ + this.usernames = Array(); + var _this = this, + _list = this.getWidgetAnnotations(), + usernames_list_string = ""; + + _list.forEach(function(_annotation){ + if(_this.usernames.indexOf(_annotation.creator) == -1){ + _this.usernames.push(_annotation.creator); + } + }); + this.usernames.forEach(function(_username){ + usernames_list_string+=_username+"," + }) + usernames_list_string = usernames_list_string.substring(0, usernames_list_string.length - 1); + _url = Mustache.to_html(this.api_users_endpoint, {usernames_list_string: encodeURIComponent(usernames_list_string), usernames_list_length: this.usernames.length}); + return IriSP.jQuery.ajax({ + async: false, + url: _url, + type: "GET", + success: function(_data) { + _this.source.users_data = _data.objects + }, + error: function(_xhr, _error, _thrown) { + console.log(_xhr) + console.log(_error) + console.log(_thrown) + } + }) + } +} + +IriSP.Widgets.LatestAnnotation.prototype.draw = function(){ + var _this = this; + this.renderTemplate(); + + this.annotationContainer_$ = this.$.find('.Ldt-LatestAnnotation'); + + if (this.selectable_annotations){ + this.onMdpEvent("AnnotationsList.refresh", function(){ + _this.getWidgetAnnotations().forEach(function(_annotation){ + _annotation.off("click"); + _annotation.on("click", function(){ + var _user = {}, + _user_display_string = "", + _users = this.source.users_data.filter(function(_user_data){ + return _user_data.username == _annotation.creator + }); + if (_users.length == 0){ + _user.username = _annotation.creator; + } + else { + _user = _users[0]; + } + _user_display_string = _this.make_name_string_function(_user) + _html = Mustache.to_html(_this.annotationTemplate, { + annotation_created: _annotation.created.toLocaleDateString()+", "+_annotation.created.toLocaleTimeString(), + annotation_creator: _user_display_string, + annotation_title: _annotation.title, + annotation_content: _annotation.description, + copy_and_edit_button: _this.copy_and_edit_button, + button_text: _this.l10n.copy_and_edit, + }); + _this.annotationContainer_$.html(_html); + _this.selectedAnnotation = true; + }); + }); + }); + + this.segments = _this.source.getAnnotationsByTypeTitle(this.segments_annotation_type) + this.segments.forEach(function(_segment){ + _segment.on("click", function(){ + _this.selectedAnnotation = false; + }) + }) + this.currentSegment = false; + } + + this.onMediaEvent("timeupdate", function(){ + _this.refresh(); + }); + this.onMediaEvent("settimerange", function(_timeRange){ + _this.refresh(_timeRange); + }) + + if (this.starts_hidden){ + this.visible = true; + this.hide(); + } + else{ + this.visible = false; + this.show(); + } + + this.selectedAnnotation = false; // This flag tells the widget if it must display last annotation (false) or clicked annotation (true) + this.player.trigger("AnnotationsList.refresh"); + this.refresh(); +} + + +IriSP.Widgets.LatestAnnotation.prototype.refresh = function(_timeRange){ + _timeRange = typeof _timeRange !== 'undefined' ? _timeRange : false ; + var _this = this; + if (this.hide_without_segment){ + if (!_timeRange && !this.media.getTimeRange()){ + var _currentTime = this.media.getCurrentTime(); + var _currentSegments = this.segments.filter(function(_segment){ + return (_currentTime >= _segment.begin && _currentTime <= _segment.end) + }); + if (_currentSegments.length == 0){ + this.currentSegment = false; + this.selectedAnnotation = false; + } + else { + this.currentSegment = _currentSegments[0] + } + } + else { + var _segmentBegin = _timeRange? _timeRange[0] : this.media.getTimeRange()[0], + _segmentEnd = _timeRange? _timeRange[1] : this.media.getTimeRange()[1]; + if ((!this.currentSegment)||(this.currentSegment.begin != _segmentBegin || this.currentSegment.end != _segmentEnd)) { + var _currentSegments = this.segments.filter(function(_segment){ + return _segment.begin == _segmentBegin && _segment.end == _segmentEnd + }); + if (_currentSegments.length > 0){ + this.selectedAnnotation = false; + this.currentSegment = _currentSegments[0]; + } + } + } + if (!this.currentSegment){ + if (this.visible){ + this.hide(); + } + } + else { + if (!this.visible){ + this.show(); + } + } + } + + if (this.visible && !this.selectedAnnotation){ + var _list = this.getWidgetAnnotations(); + + if(this.filter_by_segment){ + if (!this.currentSegment) { + _list = _list.filter(function(_annotation){ + return false; + }); + } + else { + _list = _list.filter(function(_annotation){ + _annotationTime = (_annotation.begin+_annotation.end)/2; + return (_this.currentSegment.begin <= _annotationTime && _this.currentSegment.end >= _annotationTime); + }); + } + } + _list = _list.sortBy(function(_annotation){ + return _annotation.created; + }); + + var _latestAnnotation = false, + _html="", + _user_display_string = "", + _user = {}; + if (_list.length != 0){ + _latestAnnotation = _list.pop(); + _users = this.source.users_data.filter(function(_user_data){ + return _user_data.username == _latestAnnotation.creator + }) + if (_users.length == 0){ + _user.username = _latestAnnotation.creator; + } + else { + _user = _users[0]; + } + _user_display_string = this.make_name_string_function(_user) + _html = Mustache.to_html(this.annotationTemplate, { + annotation_created: _latestAnnotation.created.toLocaleDateString()+", "+_latestAnnotation.created.toLocaleTimeString(), + annotation_creator: _user_display_string, + annotation_title: _latestAnnotation.title, + annotation_content: _latestAnnotation.description, + copy_and_edit_button: this.copy_and_edit_button, + button_text: this.l10n.copy_and_edit, + }); + } + else { + var _empty_message = this.l10n.empty + if (this.empty_message) { + _empty_message = this.empty_message + } + _html = "
"+_empty_message+"
"; + } + this.annotationContainer_$.html(_html); + } + + if(this.copy_and_edit_button){ + this.copyAndEditButton_$ = this.$.find('.Ldt-LatestAnnotation-CopyEditButton'); + this.copyAndEditButton_$.click(this.functionWrapper("copy_and_edit")); + } +} + +IriSP.Widgets.LatestAnnotation.prototype.copy_and_edit = function(){ + this.player.trigger("CreateAnnotation.show"); + if (this.hide_annotations_list){ + this.player.trigger("AnnotationsList.hide"); + } + annotationText = $('.Ldt-LatestAnnotation-Content').get(0).innerHTML; + + $('.Ldt-CreateAnnotation-Description').removeClass('empty'); + $('.Ldt-CreateAnnotation-Description').val(annotationText); +} + +IriSP.Widgets.LatestAnnotation.prototype.hide = function() { + if (this.visible){ + this.visible = false; + this.$.find('.Ldt-LatestAnnotation-header').hide(); + this.annotationContainer_$.hide() + } +} + +IriSP.Widgets.LatestAnnotation.prototype.show = function() { + if(!this.visible){ + this.visible = true; + this.$.find('.Ldt-LatestAnnotation-header').show(); + this.annotationContainer_$.show() + } +} diff -r 20e00017dd60 -r 10974bff4dae web/res/metadataplayer/LdtPlayer-core.js --- a/web/res/metadataplayer/LdtPlayer-core.js Fri Dec 11 18:11:13 2015 +0100 +++ b/web/res/metadataplayer/LdtPlayer-core.js Tue Dec 29 13:25:14 2015 +0100 @@ -13,7 +13,7 @@ |_| |___/ * Copyright 2010-2012 Institut de recherche et d'innovation - * contributor(s) : Karim Hamidou, Samuel Huron, Raphael Velt, Thibaut Cavalie + * contributor(s) : Karim Hamidou, Samuel Huron, Raphael Velt, Thibaut Cavalie, Yves-Marie Haussonne, Nicolas Durand, Olivier Aubert * * contact@iri.centrepompidou.fr * http://www.iri.centrepompidou.fr @@ -28,6 +28,7 @@ * The fact that you are presently reading this means that you have had * knowledge of the CeCILL-C license and that you accept its terms. */ +// Metadataplayer - version 0.2 /* Initialization of the namespace */ if (typeof window.IriSP === "undefined") { @@ -82,7 +83,7 @@ var list = [], positions = [], text = _text.replace(/(^\s+|\s+$)/g,''); - + function addToList(_rx, _startHtml, _endHtml) { while(true) { var result = _rx.exec(text); @@ -101,11 +102,11 @@ positions.push(end); } } - + if (_regexp) { addToList(_regexp, '', ''); } - + addToList(/(https?:\/\/)?[\w\d\-]+\.[\w\d\-]+\S+/gm, function(matches) { return ''; }, ''); @@ -114,19 +115,19 @@ }, ''); addToList(/\*[^*]+\*/gm, '', ''); addToList(/[\n\r]+/gm, '', '
'); - + IriSP._(_extend).each(function(x) { addToList.apply(null, x); }); - + positions = IriSP._(positions) .chain() .uniq() .sortBy(function(p) { return parseInt(p); }) .value(); - + var res = "", lastIndex = 0; - + for (var i = 0; i < positions.length; i++) { var pos = positions[i]; res += text.substring(lastIndex, pos); @@ -144,11 +145,11 @@ } lastIndex = pos; } - + res += text.substring(lastIndex); - + return res; - + }; IriSP.log = function() { @@ -161,11 +162,27 @@ jqSel.attr("draggable", "true").on("dragstart", function(_event) { var d = (typeof data === "function" ? data.call(this) : data); try { + if (d.html === undefined && d.uri && d.text) { + d.html = '' + d.text + ''; + } IriSP._(d).each(function(v, k) { - if (v) { + if (v && k != 'text' && k != 'html') { _event.originalEvent.dataTransfer.setData("text/x-iri-" + k, v); } }); + if (d.uri && d.text) { + _event.originalEvent.dataTransfer.setData("text/x-moz-url", d.uri + "\n" + d.text.replace("\n", " ")); + _event.originalEvent.dataTransfer.setData("text/plain", d.text + " " + d.uri); + } + // Define generic text/html and text/plain last (least + // specific types, see + // https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Drag_operations#Drag_Data) + if (d.html !== undefined) { + _event.originalEvent.dataTransfer.setData("text/html", d.html); + } + if (d.text !== undefined && ! d.uri) { + _event.originalEvent.dataTransfer.setData("text/plain", d.text); + } } catch(err) { _event.originalEvent.dataTransfer.setData("Text", JSON.stringify(d)); } @@ -180,6 +197,62 @@ }); }; +IriSP.timestamp2ms = function(t) { + // Convert timestamp to numeric value + // It accepts the following forms: + // [h:mm:ss] [mm:ss] [ss] + var s = t.split(":").reverse(); + while (s.length < 3) { + s.push("0"); + } + return 1000 * (3600 * parseInt(s[2], 10) + 60 * parseInt(s[1], 10) + parseInt(s[0], 10)); +}; + +IriSP.setFullScreen= function(elem, value) { + // Set fullscreen on or off + if (value) { + if (elem.requestFullscreen) { + elem.requestFullscreen(); + } else if (elem.mozRequestFullScreen) { + elem.mozRequestFullScreen(); + } else if (elem.webkitRequestFullscreen) { + elem.webkitRequestFullscreen(); + } else if (elem.msRequestFullscreen) { + elem.msRequestFullscreen(); + } + } else { + if (document.exitFullscreen) { + document.exitFullscreen(); + } else if (document.msExitFullscreen) { + document.msExitFullscreen(); + } else if (document.mozCancelFullScreen) { + document.mozCancelFullScreen(); + } else if (document.webkitExitFullscreen) { + document.webkitExitFullscreen(); + } + } +}; + +IriSP.isFullscreen = function() { + return (document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement); +}; + +IriSP.getFullscreenElement = function () { + return (document.fullscreenElement + || document.webkitFullscreenElement + || document.mozFullScreenElement + || document.msFullscreenElement + || undefined); +}; + +IriSP.getFullscreenEventname = function () { + return ((document.exitFullscreen && "fullscreenchange") + || (document.webkitExitFullscreen && "webkitfullscreenchange") + || (document.mozExitFullScreen && "mozfullscreenchange") + || (document.msExitFullscreen && "msfullscreenchange") + || ""); +}; + /* js is where data is stored in a standard form, whatever the serializer */ //TODO: Separate Project-specific data from Source @@ -757,6 +830,7 @@ this.volume = .5; this.paused = true; this.muted = false; + this.timeRange = false; this.loadedMetadata = false; var _this = this; this.on("play", function() { @@ -781,6 +855,18 @@ _a.trigger("enter"); _this.trigger("enter-annotation",_a); }); + + if (_this.getTimeRange()){ + if (_this.getTimeRange()[0] > _time) { + _this.pause(); + _this.setCurrentTime(_this.getTimeRange()[0]); + } + if (_this.getTimeRange()[1] < _time){ + _this.pause(); + _this.setCurrentTime(_this.getTimeRange()[1]); + } + } + }); this.on("loadedmetadata", function() { _this.loadedMetadata = true; @@ -805,6 +891,10 @@ return this.muted; }; +Playable.prototype.getTimeRange = function() { + return this.timeRange; +} + Playable.prototype.setCurrentTime = function(_time) { this.trigger("setcurrenttime",_time); }; @@ -817,6 +907,16 @@ this.trigger("setmuted",_muted); }; +Playable.prototype.setTimeRange = function(_timeBegin, _timeEnd) { + if ((_timeBegin < _timeEnd)&&(_timeBegin >= 0)&&(_timeEnd>0)){ + return this.trigger("settimerange", [_timeBegin, _timeEnd]); + } +} + +Playable.prototype.resetTimeRange = function() { + return this.trigger("resettimerange"); +} + Playable.prototype.play = function() { this.trigger("setplay"); }; @@ -840,6 +940,17 @@ }; extendPrototype(Media, Playable); +/* */ + +var Media = Model.Media = function(_id, _source) { + Playable.call(this, _id, _source); + this.elementType = 'media'; + this.duration = new Time(); + this.video = ''; + var _this = this; +}; + +extendPrototype(Media, Playable); /* Default functions to be overriden by players */ @@ -905,6 +1016,19 @@ extendPrototype(Annotation, BaseElement); +/* Set begin and end in one go, to avoid undesired side-effects in + * setBegin/setEnd interaction */ +Annotation.prototype.setBeginEnd = function(_beginMs, _endMs) { + _beginMs = Math.max(0,_beginMs); + _endMs = Math.max(0,_endMs); + if (_endMs < _beginMs) + _endMs = _beginMs; + this.begin.setMilliseconds(_beginMs); + this.end.setMilliseconds(_endMs); + this.trigger("change-begin"); + this.trigger("change-end"); +}; + Annotation.prototype.setBegin = function(_beginMs) { this.begin.setMilliseconds(Math.max(0,_beginMs)); this.trigger("change-begin"); @@ -1432,7 +1556,17 @@ videoEl.append(_srcNode); } } - + if (opts.subtitle) { + var _trackNode = IriSP.jQuery(''); + _trackNode.attr({ + label: "Subtitles", + kind: "subtitles", + srclang: "fr", + src: opts.subtitle, + default: "" + }); + videoEl.append(_trackNode); + } jqselector.html(videoEl); var mediaEl = videoEl[0]; @@ -1464,6 +1598,20 @@ } }); + media.on("settimerange", function(_timeRange){ + media.timeRange = _timeRange; + try { + if (media.getCurrentTime() > _timeRange[0] || media.getCurrentTime() < _timeRange){ + mediaEl.currentTime = (_timeRange[0] / 1000); + } + } catch (err) { + } + }) + + media.on("resettimerange", function(){ + media.timeRange = false; + }) + media.on("setplay", function() { try { mediaEl.play(); @@ -1517,7 +1665,13 @@ media.trigger("seeked"); }); - + videoEl.on("click", function() { + if (mediaEl.paused) { + media.play(); + } else { + media.pause(); + }; + }); }; /* START contentapi-serializer.js */ @@ -1694,7 +1848,7 @@ if (typeof _data.content.img !== "undefined" && _data.content.img.src !== "undefined") { _res.thumbnail = _data.content.img.src; } - _res.created = IriSP.Model.isoToDate(_data.meta["dc:created"]); + _res.created = IriSP.Model.isoToDate(_data.created ? _data.created : _data.meta? _data.meta["dc:created"] : ""); if (typeof _data.color !== "undefined") { var _c = parseInt(_data.color).toString(16); while (_c.length < 6) { @@ -1906,20 +2060,26 @@ serializeAnnotation : function(_data, _source) { var _annType = _data.getAnnotationType(); return { + id: _data.id, begin: _data.begin.milliseconds, end: _data.end.milliseconds, content: { + data: (_data.content ? _data.content.data || {} : {}), description: _data.description, title: _data.title, audio: _data.audio }, + id: _data.id ? _data.id : "", // If annotation is new, id will be undefined tags: _data.getTagTexts(), media: _data.getMedia().id, + project: _data.project_id, type_title: _annType.title, type: ( typeof _annType.dont_send_id !== "undefined" && _annType.dont_send_id ? "" : _annType.id ), meta: { created: _data.created, - creator: _data.creator + creator: _data.creator, + modified: _data.modified, + contributor: _data.contributor } }; }, @@ -1950,11 +2110,13 @@ return _tag.id; }); _ann.setTags(_tagIds); - _ann.setBegin(_anndata.begin); - _ann.setEnd(_anndata.end); + _ann.setBeginEnd(_anndata.begin, _anndata.end); if (typeof _anndata.content.audio !== "undefined" && _anndata.content.audio.href) { _ann.audio = _anndata.content.audio; - } + }; + if (_anndata.content.data) { + _ann.content = { data: _anndata.content.data }; + }; _source.getAnnotations().push(_ann); }, serialize : function(_source) { @@ -1964,7 +2126,7 @@ if (typeof _data == "string") { _data = JSON.parse(_data); } - + _source.addList('tag', new IriSP.Model.List(_source.directory)); _source.addList('annotationType', new IriSP.Model.List(_source.directory)); _source.addList('annotation', new IriSP.Model.List(_source.directory)); @@ -1972,7 +2134,8 @@ } }; -/* End ldt_annotate serializer *//* ldt_localstorage serializer: Used to store personal annotations in local storage */ +/* End ldt_annotate serializer */ +/* ldt_localstorage serializer: Used to store personal annotations in local storage */ if (typeof IriSP.serializers === "undefined") { IriSP.serializers = {}; @@ -1982,9 +2145,11 @@ serializeAnnotation : function(_data, _source) { var _annType = _data.getAnnotationType(); return { + id: _data.id, begin: _data.begin.milliseconds, end: _data.end.milliseconds, content: { + data: (_data.content ? _data.content.data || {} : {}), description: _data.description, title: _data.title, audio: _data.audio @@ -1995,7 +2160,9 @@ type: ( typeof _annType.dont_send_id !== "undefined" && _annType.dont_send_id ? "" : _annType.id ), meta: { created: _data.created, - creator: _data.creator + creator: _data.creator, + modified: _data.modified, + contributor: _data.contributor } }; }, @@ -2005,6 +2172,8 @@ _ann.title = _anndata.content.title || ""; _ann.creator = _anndata.meta.creator || ""; _ann.created = new Date(_anndata.meta.created); + _ann.contributor = _anndata.meta.contributor || ""; + _ann.modified = new Date(_anndata.meta.modified); _ann.setMedia(_anndata.media, _source); var _anntype = _source.getElement(_anndata.type); if (!_anntype) { @@ -2026,11 +2195,13 @@ return _tag.id; }); _ann.setTags(_tagIds); - _ann.setBegin(_anndata.begin); - _ann.setEnd(_anndata.end); + _ann.setBeginEnd(_anndata.begin, _anndata.end); if (typeof _anndata.content.audio !== "undefined" && _anndata.content.audio.href) { _ann.audio = _anndata.content.audio; - } + }; + if (_anndata.content.data) { + _ann.content = { data: _anndata.content.data }; + }; _source.getAnnotations().push(_ann); }, serialize : function(_source) { @@ -2115,8 +2286,8 @@ backboneRelational: "backbone-relational.js", paper: "paper.js", jqueryMousewheel: "jquery.mousewheel.min.js", - splitter: "jquery.splitter.js", - cssSplitter: "jquery.splitter.css", + splitter: "jquery.touchsplitter.js", + cssSplitter: "jquery.touchsplitter.css", renkanPublish: "renkan.js", processing: "processing-1.3.6.min.js", recordMicSwf: "record_mic.swf", @@ -2206,7 +2377,7 @@ }; IriSP.guiDefaults = { - width : 640, + width : 640, container : 'LdtPlayer', spacer_div_height : 0, widgets: [] @@ -2258,46 +2429,45 @@ Metadataplayer.prototype.loadLibs = function() { ns.log("IriSP.Metadataplayer.prototype.loadLibs"); var $L = $LAB - .script(ns.getLib("Mustache")); - + .queueScript(ns.getLib("Mustache")); formerJQuery = !!window.jQuery; former$ = !!window.$; formerUnderscore = !!window._; - + if (typeof ns.jQuery === "undefined") { - $L.script(ns.getLib("jQuery")); - } - - if (typeof ns._ === "undefined") { - $L.script(ns.getLib("underscore")); + $L.queueScript(ns.getLib("jQuery")); } - - if (typeof window.JSON == "undefined") { - $L.script(ns.getLib("json")); + + if (typeof ns._ === "undefined") { + $L.queueScript(ns.getLib("underscore")); } - - $L.wait() - .script(ns.getLib("jQueryUI")); + + if (typeof window.JSON == "undefined") { + $L.queueScript(ns.getLib("json")); + } + $L.queueWait().queueScript(ns.getLib("jQueryUI")).queueWait(); /* widget specific requirements */ for(var _i = 0; _i < this.config.widgets.length; _i++) { var _t = this.config.widgets[_i].type; if (typeof ns.widgetsRequirements[_t] !== "undefined" && typeof ns.widgetsRequirements[_t].requires !== "undefined" ) { for (var _j = 0; _j < ns.widgetsRequirements[_t].requires.length; _j++) { - $L.script(ns.getLib(ns.widgetsRequirements[_t].requires[_j])); + $L.queueScript(ns.getLib(ns.widgetsRequirements[_t].requires[_j])); } } } - + var _this = this; - - $L.wait(function() { + $L.queueWait(function() { _this.onLibsLoaded(); }); + + $L.runQueue(); }; Metadataplayer.prototype.onLibsLoaded = function() { ns.log("IriSP.Metadataplayer.prototype.onLibsLoaded"); + if (typeof ns.jQuery === "undefined" && typeof window.jQuery !== "undefined") { ns.jQuery = window.jQuery; if (former$ || formerJQuery) { @@ -2310,9 +2480,10 @@ _.noConflict(); } } + ns.loadCss(ns.getLib("cssjQueryUI")); ns.loadCss(this.config.css); - + this.$ = ns.jQuery('#' + this.config.container); this.$.css({ "width": this.config.width, @@ -2321,7 +2492,7 @@ if (typeof this.config.height !== "undefined") { this.$.css("height", this.config.height); } - + this.widgets = []; var _this = this; ns._(this.config.widgets).each(function(widgetconf, key) { @@ -2334,9 +2505,9 @@ }); }); this.$.find('.Ldt-Loader').detach(); - + this.widgetsLoaded = false; - + this.on("widget-loaded", function() { if (_this.widgetsLoaded) { return; @@ -2348,7 +2519,44 @@ _this.widgetsLoaded = true; _this.trigger("widgets-loaded"); } - }); + }); +}; + +Metadataplayer.prototype.loadLocalAnnotations = function(localsourceidentifier) { + if (this.localSource === undefined) + this.localSource = this.sourceManager.newLocalSource({serializer: IriSP.serializers['ldt_localstorage']}); + // Load current local annotations + if (localsourceidentifier) { + // Allow to override localsourceidentifier when necessary (usually at init time) + this.localSource.identifier = localsourceidentifier; + } + this.localSource.deSerialize(window.localStorage[this.localSource.identifier] || "[]"); + return this.localSource; +}; + +Metadataplayer.prototype.saveLocalAnnotations = function() { + // Save annotations back to localstorage + window.localStorage[this.localSource.identifier] = this.localSource.serialize(); + // Merge modifications into widget source + // this.source.merge(this.localSource); +}; + +Metadataplayer.prototype.addLocalAnnotation = function(a) { + this.loadLocalAnnotations(); + this.localSource.getAnnotations().push(a); + this.saveLocalAnnotations(); +}; + +Metadataplayer.prototype.deleteLocalAnnotation = function(ident) { + this.localSource.getAnnotations().removeId(ident, true); + this.saveLocalAnnotations(); +}; + +Metadataplayer.prototype.getLocalAnnotation = function (ident) { + this.loadLocalAnnotations(); + // We cannot use .getElement since it fetches + // elements from the global Directory + return IriSP._.first(IriSP._.filter(this.localSource.getAnnotations(), function (a) { return a.id == ident; })); }; Metadataplayer.prototype.loadMetadata = function(_metadataInfo) { @@ -2371,9 +2579,9 @@ var _divs = this.layoutDivs(_widgetConfig.type); _widgetConfig.container = _divs[0]; } - + var _this = this; - + if (typeof ns.Widgets[_widgetConfig.type] !== "undefined") { ns._.defer(function() { _callback(new ns.Widgets[_widgetConfig.type](_this, _widgetConfig)); @@ -2418,7 +2626,7 @@ if (typeof _height !== "undefined") { divHtml.css("height", _height); } - + this.$.append(divHtml); this.$.append(spacerHtml); @@ -2427,7 +2635,8 @@ })(IriSP); -/* End of widgets-container/metadataplayer.js *//* widgetsDefinition of an ancestor for the Widget classes */ +/* End of widgets-container/metadataplayer.js */ +/* widgetsDefinition of an ancestor for the Widget classes */ if (typeof IriSP.Widgets === "undefined") { IriSP.Widgets = {}; @@ -2446,44 +2655,44 @@ IriSP.Widgets.Widget = function(player, config) { - + if( typeof player === "undefined") { /* Probably an abstract call of the class when * individual widgets set their prototype */ return; } - + this.__subwidgets = []; - + /* Setting all the configuration options */ var _type = config.type || "(unknown)", _config = IriSP._.defaults({}, config, (player && player.config ? player.config.default_options : {}), this.defaults), _this = this; - + IriSP._(_config).forEach(function(_value, _key) { _this[_key] = _value; }); - + this.$ = IriSP.jQuery('#' + this.container); - + if (typeof this.width === "undefined") { this.width = this.$.width(); } else { this.$.css("width", this.width); } - + if (typeof this.height !== "undefined") { this.$.css("height", this.height); } - + /* Setting this.player at the end in case it's been overriden * by a configuration option of the same name :-( */ this.player = player || new IriSP.FakeClass(["on","trigger","off","loadWidget","loadMetadata"]); - + /* Adding classes and html attributes */ this.$.addClass("Ldt-TraceMe Ldt-Widget").attr("widget-type", _type); - + this.l10n = ( typeof this.messages[IriSP.language] !== "undefined" ? this.messages[IriSP.language] @@ -2493,10 +2702,14 @@ : this.messages["en"] ) ); - + /* Loading Metadata if required */ - + function onsourceloaded() { + if (_this.localannotations) { + _this.localsource = player.loadLocalAnnotations(_this.localannotations); + _this.source.merge(_this.localsource); + } if (_this.media_id) { _this.media = this.getElement(_this.media_id); } else { @@ -2505,15 +2718,18 @@ }; _this.media = _this.source.getCurrentMedia(_mediaopts); } - - _this.draw(); + if (_this.pre_draw_callback){ + IriSP.jQuery.when(_this.pre_draw_callback()).done(_this.draw()); + } + else { + _this.draw(); + } _this.player.trigger("widget-loaded"); } - + if (this.metadata) { /* Getting metadata */ this.source = player.loadMetadata(this.metadata); - /* Call draw when loaded */ this.source.onLoad(onsourceloaded); } else { @@ -2521,8 +2737,8 @@ onsourceloaded(); } } - - + + }; IriSP.Widgets.Widget.prototype.defaults = {}; @@ -2640,7 +2856,7 @@ // offset is normally either -1 (previous slide) or +1 (next slide) var _this = this; var currentTime = _this.media.getCurrentTime(); - var annotations = _this.source.getAnnotations().sortBy(function(_annotation) { + var annotations = _this.getWidgetAnnotations().sortBy(function(_annotation) { return _annotation.begin; }); for (var i = 0; i < annotations.length; i++) { @@ -2653,6 +2869,51 @@ }; }; +/* + * Propose an export of the widget's annotations + * + * Parameter: a list of annotations. If not specified, the widget's annotations will be exported. + */ +IriSP.Widgets.Widget.prototype.exportAnnotations = function(annotations) { + var widget = this; + if (annotations === undefined) + annotations = this.getWidgetAnnotations(); + var $ = IriSP.jQuery; + + // FIXME: this should belong to a proper serialize/deserialize component? + var content = Mustache.to_html("[video:{{url}}]\n", {url: widget.media.url}) + annotations.map( function(a) { return Mustache.to_html("[{{ a.begin }}]{{ a.title }} {{ a.description }}[{{ a.end }}]", { a: a }); }).join("\n"); + + var el = $("
")
+            .addClass("exportContainer")
+            .text(content)
+            .dialog({
+                title: "Annotation export",
+                open: function( event, ui ) {
+                    // Select text
+                    var range;
+                    if (document.selection) {
+		                range = document.body.createTextRange();
+                        range.moveToElementText(this[0]);
+		                range.select();
+		            } else if (window.getSelection) {
+		                range = document.createRange();
+		                range.selectNode(this[0]);
+		                window.getSelection().addRange(range);
+		            }
+                },
+                autoOpen: true,
+                width: '80%',
+                minHeight: '400',
+                height: 400,
+                buttons: [ { text: "Close", click: function() { $( this ).dialog( "close" ); } },
+                           { text: "Download", click: function () {
+                               a = document.createElement('a');
+                               a.setAttribute('href', 'data:text/plain;base64,' + btoa(content));
+                               a.setAttribute('download', 'Annotations - ' + widget.media.title.replace(/[^ \w]/g, '') + '.txt');
+                               a.click();
+                           } } ]
+            });
+};
 
 /**
  * This method responsible of drawing a widget on screen.
diff -r 20e00017dd60 -r 10974bff4dae web/res/metadataplayer/Markers.css
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/res/metadataplayer/Markers.css	Tue Dec 29 13:25:14 2015 +0100
@@ -0,0 +1,186 @@
+
+.Ldt-Markers-Marker {
+    position: absolute; 
+    margin-left: -1px; 
+    border: 1px solid #ffffff;
+}
+
+.Ldt-Markers-MarkerBall {
+	background: #ffffff;
+}
+
+.Ldt-Markers-MarkerBall:hover {
+	background: #bebebe;
+}
+
+.Ldt-Markers-List{
+	overflow: hidden;
+}
+
+.Ldt-Markers-Position {
+    background: #fc00ff;
+    position: relative;
+    left: 0;
+    margin-left: -1px;
+    width: 2px;
+    bottom: -1px;
+    z-index: 80000;
+}
+
+.Ldt-Markers-Inputs{
+	background-color: #e0e0e0;
+	margin-top: 1px;
+}
+
+.Ldt-Markers-RoundButton{
+	display: inline-block;
+    background-color: #d93c71;
+    color: #ffffff;
+    cursor: pointer;
+    height: 20px;
+    width: 20px;
+    border-radius: 20px;
+    font-size: 25px;
+    font-style: bold;
+    border: 1px solid;
+    border-color: #eca3bc #631e34 #36101c #e16e93;
+    cursor: pointer;
+    margin-right: 0px;
+    margin-left: 13px;
+    margin-bottom: 10px;
+    margin-top: 10px;
+    padding: 4px;
+    text-align: center;
+	vertical-align: top;
+	line-height: 20px;
+}
+
+.Ldt-Markers-RoundButton.Ldt-Markers-CannotCreate,
+.Ldt-Markers-RoundButton.Ldt-Markers-PreviewDelete{
+	background-color: #999999;
+	border-color: #797979 #444444 #222222 #696969;
+}
+
+.Ldt-Markers-RoundButton.Ldt-Markers-Delete{
+	line-height: 23px;
+	text-indent: 2px;
+}
+
+.Ldt-Markers-RoundButton.Ldt-Markers-PreviewDelete{
+	line-height: 23px;
+	text-indent: 2px;
+}
+
+.Ldt-Markers-Info{
+	width: 90%;
+	display: inline-block;
+	margin: 0px;
+}
+
+.Ldt-Markers-Screen{
+	margin: 0px;
+}
+
+.Ldt-Markers-ScreenSending, .Ldt-Markers-ScreenFailure, .Ldt-Markers-ScreenSuccess, 
+.Ldt-Markers-ScreenConfirmDelete, .Ldt-Markers-ScreenDeleteSuccess{
+	text-align: center;
+	vertical-align: middle;
+	line-height: 125px;
+	font-size: 18px;
+	font-weight: bold;
+	color: #68273C;
+}
+
+.Ldt-Markers-Screen-InnerBox{
+    border: 1px solid #CCCCCC;
+    background: #FFFFFF;
+    color: #FF3B77; text-align: center;
+    font-size: 13px; font-weight: bold;
+}
+
+a.Ldt-Markers-Close {
+    position: relative; 
+    float: right;
+    right: 2px;
+    top: 2px;
+    display: inline-block; width: 17px; height: 17px; margin: 4px;
+    background: url(img/widget-control.png);
+}
+
+a.Ldt-Markers-Screen-SubmitDelete, a.Ldt-Markers-Screen-CancelDelete {
+	color: #3366BB;
+	cursor: pointer;
+}
+
+a.Ldt-Markers-Screen-SubmitDelete:hover, a.Ldt-Markers-Screen-CancelDelete:hover {
+	color: #3a75ff;
+}
+
+.Ldt-Markers-MarkerDescription{
+	width: 90%;
+	border: 1px solid #68273c;
+	margin: 10px;
+	padding: 10px;
+	background: #ffffff;
+	overflow: scroll;
+}
+
+.Ldt-Markers-MarkerDescription:hover{
+	border: 2px solid #e87d9f;
+}
+
+.Ldt-Markers-MarkerEdit{
+	width: 100%;
+	margin: 10px;
+}
+
+.Ldt-Markers-MarkerTextArea{
+	height: auto;
+	width: auto;
+	max-width: 82%;
+	max-height: 100%;
+	padding: 10px;
+	background: #ffffff;
+	border: 2px solid #e87d9f;
+	margin: 0px;
+}
+
+.Ldt-Markers-Buttons{
+	display: inline-block;
+	width: 17%;
+	vertical-align: top;
+}
+
+.Ldt-Markers-MarkerSend, .Ldt-Markers-MarkerPreviewSend, .Ldt-Markers-MarkerCancel{
+	display: inline-block;
+    background-color: #d93c71;
+    color: #ffffff;
+    cursor: pointer;
+    height: 20px;
+    width: 80px;
+    font-size: 11;
+    font-style: bold;
+    border: 1px solid;
+    border-color: #eca3bc #631e34 #36101c #e16e93;
+    cursor: pointer;
+    margin-right: 5px;
+    margin-left: 5px;
+    margin-bottom: 10px;
+    margin-top: 0px;
+    padding: 4px;
+    text-align: center;
+	vertical-align: top;
+	line-height: 20px;
+	vertical-align: top;
+}
+
+.Ldt-Markers-RoundButton:hover, .Ldt-Markers-MarkerSend:hover, .Ldt-Markers-MarkerPreviewSend:hover, .Ldt-Markers-MarkerCancel:hover{
+	background-color: #e15581;
+	border-color: #222222 #e87d9f #f0adc3 #68273c;
+}
+
+.Ldt-Markers-RoundButton.Ldt-Markers-CannotCreate:hover, 
+.Ldt-Markers-RoundButton.Ldt-Markers-PreviewDelete:hover{	
+	background-color: #999999;
+	border-color: #797979 #444444 #222222 #696969;
+}
\ No newline at end of file
diff -r 20e00017dd60 -r 10974bff4dae web/res/metadataplayer/Markers.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/res/metadataplayer/Markers.js	Tue Dec 29 13:25:14 2015 +0100
@@ -0,0 +1,632 @@
+
+IriSP.Widgets.Markers = function(player, config) {
+    IriSP.Widgets.Widget.call(this, player, config);
+};
+
+IriSP.Widgets.Markers.prototype = new IriSP.Widgets.Widget();
+
+IriSP.Widgets.Markers.prototype.defaults = {
+    pre_draw_callback: function(){
+        return this.importUsers();
+    },
+    annotation_type: "markers",
+    line_height: 8,
+    background: "#e0e0e0",
+    marker_color: "#ff80fc",
+    placeholder_color: "#ffffff",
+    hover_color: "#e15581",
+    selected_color: "#74d600",
+    ball_radius: 4,
+    pause_on_write: true,
+    play_on_submit: true,
+    api_serializer: "ldt_annotate",
+    api_endpoint_template_create: "",
+    api_endpoint_template_edit: "",
+    api_endpoint_template_delete: "",
+    api_method_create: "POST",
+    api_method_edit: "PUT",
+    api_method_delete: "DELETE",
+    project_id: "",
+    creator_name: "",
+    after_send_timeout: 0,
+    markers_gap: 2000,
+    allow_empty_markers: false,
+    close_after_send: false,
+    custom_send_button: false,
+    custom_cancel_button: false,
+    preview_mode: false,
+    filter_per_user: false,
+    api_users_endpoint: "",
+    make_username_string_function: function(params){
+        return params.username ? params.username : "Anonymous";
+    },
+    hide_if_empty: false,
+};
+
+IriSP.Widgets.Markers.prototype.template = 
+    '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
+
' + + '
+
' + + '{{^preview_mode}}
{{/preview_mode}}' + + '{{#preview_mode}}
{{/preview_mode}}' + + '{{#filter_per_user}}{{#preview_mode}}{{/preview_mode}}{{/filter_per_user}}' + + '
' + + '
' + + '
' + + '
{{l10n.wait_while_processing}}
' + + '
' + + '
' + + '' + + '
{{l10n.annotation_saved}}
' + + '
' + + '
' + + '' + + '
{{l10n.delete_saved}}
' + + '
' + + '
' + + '' + + '
{{l10n.error_while_contacting}}
' + + '
' + + '
' + + '' + + '
' + + '{{l10n.delete_text}} ' + + '{{l10n.submit_delete}} ' + + '{{l10n.cancel}}' + + '
' + + '
' + + '
'; + + +IriSP.Widgets.Markers.prototype.markerTemplate = + '
' + + '
' + + '
'; + +IriSP.Widgets.Markers.prototype.markerPlaceholderTemplate = + '
' + + '
' + + '
'; + +IriSP.Widgets.Markers.prototype.infoTemplate = + '{{^edit}}
{{marker_info}}
{{/edit}}' + + '{{#edit}}
' + + '' + + '
' + + '{{^preview_mode}}
{{send}}
{{/preview_mode}}' + + '{{#preview_mode}}
{{send}}
{{/preview_mode}}' + + '
{{cancel}}
' + + '
' + + '
{{/edit}}' + +IriSP.Widgets.Markers.prototype.messages = { + en : { + send : "Send", + submit_delete: "Delete", + cancel : "Cancel", + preview_mode_submit: "You cannot submit a marker in preview mode.", + preview_mode_delete: "You cannot delete a marker in preview mode", + wait_while_processing: "Please wait while your annotation is being processed...", + delete_text: "The selected marker will be deleted. Continue?", + error_while_contacting: "An error happened while contacting the server. Your annotation has not been saved.", + annotation_saved: "Thank you, your annotation has been saved.", + delete_saved: "Thank you, your annotation has been deleted", + close_widget: "Close", + cannot_create: "Cannot create marker on this timecode" + }, + fr : { + send : "Envoyer", + submit_delete: "Supprimer", + cancel : "Annuler", + preview_mode_submit: "Vous ne pouvez pas créer ou éditer de marqueur en mode aperçu", + preview_mode_delete: "Vous ne pouvez pas supprimer de marqueur en mode aperçu", + wait_while_processing: "Veuillez patienter pendant le traitement de votre annotation...", + delete_text: "Le marqueur sélectionné sera supprimé. Continuer?", + error_while_contacting: "Une erreur s'est produite en contactant le serveur. Votre annotation n'a pas été enregistrée.", + annotation_saved: "Merci, votre annotation a été enregistrée.", + delete_saved: "Merci, votre annotation a été supprimée", + close_widget: "Fermer", + cannot_create: "Impossible de créer un marqueur sur ce timecode" + } +} + +IriSP.Widgets.Markers.prototype.importUsers = function(){ + if (this.filter_per_user && this.preview_mode){ + this.usernames = Array(); + if (!this.source.users_data && this.api_users_endpoint){ + var _this = this, + _list = this.getWidgetAnnotations(), + usernames_list_string = ""; + + _list.forEach(function(_annotation){ + if(_this.usernames.indexOf(_annotation.creator) == -1){ + _this.usernames.push(_annotation.creator); + } + }); + this.usernames.forEach(function(_username){ + usernames_list_string+=_username+"," + }) + usernames_list_string = usernames_list_string.substring(0, usernames_list_string.length - 1); + _url = Mustache.to_html(this.api_users_endpoint, {usernames_list_string: encodeURIComponent(usernames_list_string), usernames_list_length: this.usernames.length}); + return IriSP.jQuery.ajax({ + async: false, + url: _url, + type: "GET", + success: function(_data) { + _this.source.users_data = _data.objects + }, + error: function(_xhr, _error, _thrown) { + console.log(_xhr) + console.log(_error) + console.log(_thrown) + } + }) + } + } +} + +IriSP.Widgets.Markers.prototype.draw = function(){ + var _this = this; + this.renderTemplate(); + if ((!this.filter_per_user) || (!this.preview_mode) || (this.usernames.length <= 1)){ + this.$.find(".Ldt-Markers-userFilter-dropdown").hide(); + } + else { + this.usernames.forEach(function(_user){ + var _users = _this.source.users_data.filter(function(_user_data){ + return _user_data.username == _user; + }), + _user_data = {}; + if (_users.length == 0){ + _user_data.username = _user; + } + else{ + _user_data = _users[0]; + } + _this.$.find(".Ldt-Markers-userFilter-dropdown").append("") + }); + this.$.find(".Ldt-Markers-userFilter-dropdown").change(this.functionWrapper("drawMarkers")) + this.$.find(".Ldt-Markers-userFilter-dropdown").change(this.functionWrapper("clearSelectedMarker")) + + } + + this.markers = this.getWidgetAnnotations().filter(function(_ann) { + return ((_ann.getDuration() == 0) || (_ann.begin == _ann.end)); + }); + if (this.hide_if_empty && this.markers.length <= 0){ + this.$.hide(); + } + else { + this.drawMarkers(); + + this.$.find(".Ldt-Markers-Create").click(this.functionWrapper("onCreateClick")); + this.$.find(".Ldt-Markers-Delete").click(this.functionWrapper("onDeleteClick")); + this.$.find(".Ldt-Markers-RoundButton").hide() + this.updateCreateButtonState(this.media.getCurrentTime()) + this.$.find(".Ldt-Markers-Screen-SubmitDelete").click(this.functionWrapper("sendDelete")); + this.$.find(".Ldt-Markers-Screen-CancelDelete").click(function(){ + _this.showScreen("Main"); + _this.cancelEdit(); + }) + this.showScreen("Main"); + this.$.css({ + margin: "1px 0", + background: this.background + }); + + this.$.find(".Ldt-Markers-Close").click(this.functionWrapper("revertToMainScreen")); + + this.onMediaEvent("timeupdate", this.functionWrapper("updatePosition")); + this.onMediaEvent("timeupdate", this.functionWrapper("updateCreateButtonState")); + this.onMediaEvent("play", this.functionWrapper("clearSelectedMarker")); + this.onMdpEvent("Markers.refresh", this.functionWrapper("drawMarkers")); + + this.newMarkerTimeCode = 0; + this.selectedMarker = false; + } +} + + +IriSP.Widgets.Markers.prototype.updatePosition = function(_time) { + var _x = Math.floor( this.width * _time / this.media.duration); + this.$.find('.Ldt-Markers-Position').css({ + left: _x + "px" + }); +} + +IriSP.Widgets.Markers.prototype.updateCreateButtonState = function(_time){ + _this = this + var can_create = this.preview_mode? false : this.markers.every(function(_marker){ + return ((_time < (_marker.begin-_this.markers_gap))||(_time > (_marker.begin+_this.markers_gap))) + }); + if (can_create){ + if ((this.$.find(".Ldt-Markers-Create").is(":hidden"))&&(this.$.find(".Ldt-Markers-Delete").is(":hidden")||this.$.find(".Ldt-Markers-PreviewDelete").is(":hidden"))){ + this.$.find(".Ldt-Markers-RoundButton").hide(); + this.$.find(".Ldt-Markers-Create").show(); + } + } + else { + if ((this.$.find(".Ldt-Markers-CannotCreate").is(":hidden"))&&(this.$.find(".Ldt-Markers-Delete").is(":hidden")||this.$.find(".Ldt-Markers-PreviewDelete").is(":hidden"))){ + this.$.find(".Ldt-Markers-RoundButton").hide(); + this.$.find(".Ldt-Markers-CannotCreate").show(); + } + } +} + +IriSP.Widgets.Markers.prototype.onCreateClick = function(){ + this.pauseOnWrite(); + if (!this.selectedMarker){ + this.newMarkerCurrentTime = this.media.getCurrentTime(); + this.showPlaceholder(this.media.getCurrentTime()); + this.startEdit(); + } +} + +IriSP.Widgets.Markers.prototype.onDeleteClick = function(){ + _this = this; + this.pauseOnWrite(); + if(this.selectedMarker){ + this.showScreen("ConfirmDelete"); + } + else { + // Click on "x" without a selected marker: back to initial state + this.cancelEdit(); + } +} + +IriSP.Widgets.Markers.prototype.startEdit = function(){ + if (this.selectedMarker){ + _divHtml = Mustache.to_html(this.infoTemplate, { + edit: true, + preview_mode: this.preview_mode, + preview_mode_text: this.l10n.preview_mode_submit, + marker_info: this.selectedMarker.description, + send: this.custom_send_button? this.custom_send_button : this.l10n.send, + cancel: this.custom_cancel_button? this.custom_cancel_button :this.l10n.cancel + }) + } + else { + _divHtml = Mustache.to_html(this.infoTemplate, { + edit: true, + marker_info: "", + preview_mode: this.preview_mode, + preview_mode_text: this.l10n.preview_mode_submit, + send: this.custom_send_button? this.custom_send_button : this.l10n.send, + cancel: this.custom_cancel_button? this.custom_cancel_button :this.l10n.cancel + }) + } + this.$.find(".Ldt-Markers-Info").html(_divHtml); + this.$.find(".Ldt-Markers-MarkerSend").click(this.functionWrapper("onSubmit")); + this.$.find(".Ldt-Markers-MarkerCancel").click(this.functionWrapper("cancelEdit")); + this.$.find(".Ldt-Markers-MarkerTextArea").bind("change keyup input paste", this.functionWrapper("onDescriptionChange")); + this.$.find(".Ldt-Markers-RoundButton").hide(); + if (this.preview_mode){ + this.$.find(".Ldt-Markers-PreviewDelete").show(); + } + else { + this.$.find(".Ldt-Markers-Delete").show(); + } + this.editing = true; +} + +IriSP.Widgets.Markers.prototype.cancelEdit = function(){ + if (this.selectedMarker){ + // Click on "cancel" while editing a marker: back to visualization state + _divHtml = Mustache.to_html(this.infoTemplate, { + edit: false, + marker_info: this.selectedMarker.description, + }) + this.$.find(".Ldt-Markers-Info").html(_divHtml); + if (!this.preview_mode){ + this.$.find(".Ldt-Markers-MarkerDescription").click(this.functionWrapper("startEdit")); + } + } + else { + // Click on "cancel" while editing a marker: back to initial state + this.hidePlaceholder(); + this.$.find(".Ldt-Markers-Info").html(""); + this.$.find(".Ldt-Markers-RoundButton").hide() + this.$.find(".Ldt-Markers-Create").show() + this.updateCreateButtonState(this.media.getCurrentTime()) + } + this.editing = false; +} + +IriSP.Widgets.Markers.prototype.onDescriptionChange = function(){ + // Returns false if the textarea is empty, true if there is text in it + if(!this.allow_empty_markers){ + var _field = this.$.find(".Ldt-Markers-MarkerTextArea"), + _contents = _field.val(); + _field.css("border-color", !!_contents ? "#e87d9f" : "#ff0000"); + if (!!_contents) { + _field.removeClass("empty"); + } else { + _field.addClass("empty"); + } + this.pauseOnWrite(); + return !!_contents; + } + else { + // If the widget is configured to allow to post empty markers, it returns true + return true + } +}; + +IriSP.Widgets.Markers.prototype.pauseOnWrite = function(){ + if (this.pause_on_write && !this.media.getPaused()) { + this.media.pause(); + } +}; + +IriSP.Widgets.Markers.prototype.showScreen = function(_screenName) { + this.$.find('.Ldt-Markers-Screen' + _screenName).show() + .siblings().hide(); +} + +IriSP.Widgets.Markers.prototype.revertToMainScreen = function(){ + if (this.$.find(".Ldt-Markers-ScreenMain").is(":hidden")){ + this.showScreen("Main"); + this.cancelEdit(); + if (this.selectedMarker){ + this.$.find(".Ldt-Markers-RoundButton").hide(); + if (this.preview_mode){ + this.$.find(".Ldt-Markers-PreviewDelete").show(); + } + else { + this.$.find(".Ldt-Markers-Delete").show(); + } + } + else { + this.$.find(".Ldt-Markers-RoundButton").hide(); + this.$.find(".Ldt-Markers-Create").show(); + this.updateCreateButtonState(); + } + } +} + +IriSP.Widgets.Markers.prototype.hidePlaceholder = function(){ + this.$.find(".Ldt-Markers-PlaceholderMarker").remove(); +} + +IriSP.Widgets.Markers.prototype.showPlaceholder = function(_time){ + var _scale = this.width / this.source.getDuration(), + _left = _time * _scale -1, + _data = { + left: _left, + height: this.line_height-1, + ball_top: (this.ball_radius*2 > this.line_height) ? 0 : ((this.line_height - this.ball_radius*2)/2)-1, + ball_radius: (this.ball_radius*2 > this.line_height) ? this.line_height/2 : this.ball_radius, + ball_diameter: (this.ball_radius*2 > this.line_height) ? this.line_height/2 : this.ball_radius*2, + ball_left: -this.ball_radius, + marker_color: this.placeholder_color + }, + _html = Mustache.to_html(this.markerPlaceholderTemplate, _data), + _el = IriSP.jQuery(_html); + + list_$ = this.$.find(".Ldt-Markers-List"); + _el.appendTo(list_$); +} + +IriSP.Widgets.Markers.prototype.clearSelectedMarker = function(){ + if (this.selectedMarker){ + var _divHtml = ""; + + this.selectedMarker = false; + this.$.find(".Ldt-Markers-Info").html(_divHtml); + this.$.find(".Ldt-Markers-RoundButton").hide(); + this.$.find(".Ldt-Markers-Create").show(); + this.$.find(".Ldt-Markers-MarkerBall").toggleClass("selected", false); + this.updateCreateButtonState(this.media.getCurrentTime()) + } +} + +IriSP.Widgets.Markers.prototype.drawMarkers = function(){ + var _this = this, + _scale = this.width / this.source.getDuration(), + list_$ = this.$.find('.Ldt-Markers-List'), + _displayed_markers = this.markers; + + this.$.remove("Ldt-Markers-Marker"); + list_$.html(""); + + if (this.filter_per_user && this.usernames.length > 1){ + var _username = this.$.find(".Ldt-Markers-userFilter-dropdown")[0].options[this.$.find(".Ldt-Markers-userFilter-dropdown")[0].selectedIndex].value; + _displayed_markers = _displayed_markers.filter(function(_marker){ + return _marker.creator == _username; + }) + } + + _displayed_markers.forEach(function(_marker){ + var _left = _marker.begin * _scale -1, + _data = { + left: _left, + height: _this.line_height-1, + ball_top: (_this.ball_radius*2 > _this.line_height) ? 0 : ((_this.line_height - _this.ball_radius*2)/2)-1, + ball_radius: (_this.ball_radius*2 > _this.line_height) ? _this.line_height/2 : _this.ball_radius, + ball_diameter: (_this.ball_radius*2 > _this.line_height) ? _this.line_height/2 : _this.ball_radius*2, + ball_left: -_this.ball_radius, + marker_color: ((_this.selectedMarker)&&(_this.selectedMarker.id == _marker.id))? _this.selected_color : _this.marker_color + }, + _html = Mustache.to_html(_this.markerTemplate, _data), + _el = IriSP.jQuery(_html); + + if ((_this.selectedMarker)&&(_this.selectedMarker.id == _marker.id)){ + _el.children().toggleClass("selected", true); + } + + _el.mouseover(function(){ + if (!((_this.selectedMarker)&&(_this.selectedMarker.id == _marker.id))){ + _el.children().css("background-color", _this.hover_color); + }; + }) + .mouseout(function(){ + if (!((_this.selectedMarker)&&(_this.selectedMarker.id == _marker.id))){ + _el.children().css("background-color", _this.marker_color); + }; + }) + .click(function(){ + _this.showScreen("Main"); + _this.cancelEdit(); + _this.hidePlaceholder(); + if (!((_this.selectedMarker)&&(_this.selectedMarker.id == _marker.id))){ + // if there either is no marker selected or we click a different marker + list_$.find(".Ldt-Markers-MarkerBall").css("background-color", _this.marker_color) + list_$.find(".Ldt-Markers-MarkerBall").toggleClass("selected", false); + _el.children().toggleClass("selected", true); + _el.children().css("background-color", _this.selected_color) + _this.selectedMarker = _marker; + + _divHtml = Mustache.to_html(_this.infoTemplate, { + edit: false, + marker_info: _marker.description, + }) + + _this.$.find(".Ldt-Markers-Info").html(_divHtml); + if (!_this.preview_mode){ + _this.$.find(".Ldt-Markers-MarkerDescription").click(_this.functionWrapper("startEdit")); + } + _this.$.find(".Ldt-Markers-RoundButton").hide(); + if (_this.preview_mode){ + _this.$.find(".Ldt-Markers-PreviewDelete").show(); + } + else { + _this.$.find(".Ldt-Markers-Delete").show(); + } + + } + else { + // if we click the currently selected marker, we unselect it + _el.children().css("background-color", _this.hover_color); + _this.clearSelectedMarker(); + } + + if (_this.selectedMarker) { + // Only if we select a new marker do we pause video and time jump + _this.media.pause(); + _marker.trigger("click"); + } + }) + .appendTo(list_$); + }) +} + + +IriSP.Widgets.Markers.prototype.onSubmit = function(){ + + /* If mandatory fields are empty, we cancel the sending */ + if (!this.allow_empty_markers && !this.onDescriptionChange()){ + return false; + } + + /* We pause the video if it's still playing */ + if (!this.media.getPaused()){ + this.media.pause(); + } + + var _this = this, + _exportedAnnotations = new IriSP.Model.List(this.player.sourceManager), /* We create a List to send to the server that will contains the annotation */ + _export = this.player.sourceManager.newLocalSource({serializer: IriSP.serializers[this.api_serializer]}), /* We create a source object using a specific serializer for export */ + _annotationTypes = this.source.getAnnotationTypes().searchByTitle(this.annotation_type, true), /* We get the AnnotationType in which the annotation will be added */ + _annotationType = (_annotationTypes.length ? _annotationTypes[0] : new IriSP.Model.AnnotationType(false, _export)); /* If it doesn't already exists, we create it */ + if (this.selectedMarker){ + var _annotation = this.selectedMarker, + _url = Mustache.to_html(this.api_endpoint_template_edit, {annotation_id: this.selectedMarker ? this.selectedMarker.id : ""}); + _annotation.source = _export + _annotation.description = this.$.find(".Ldt-Markers-MarkerTextArea").val(); /* Description field */ + } + else { + var _annotation = new IriSP.Model.Annotation(false, _export), + _url = Mustache.to_html(this.api_endpoint_template_create); + + /* If we created an AnnotationType on the spot ... */ + if (!_annotationTypes.length) { + /* ... We must not send its id to the server ... */ + _annotationType.dont_send_id = true; + /* ... And we must include its title. */ + _annotationType.title = this.annotation_type; + } + + _annotation.setMedia(this.source.currentMedia.id); /* Annotated media ID */ + if (!this.selectedMarker){ + _annotation.setBegin(this.newMarkerCurrentTime); + _annotation.setEnd(this.newMarkerCurrentTime); + } + _annotation.setAnnotationType(_annotationType.id); /* AnnotationType ID */ + if (this.project_id != ""){ + /* Project id, only if it's been specifiec in the config */ + _annotation.project_id = this.project_id; + } + _annotation.created = new Date(); /* Creation date */ + _annotation.description = this.$.find(".Ldt-Markers-MarkerTextArea").val(); /* Description field */ + _annotation.creator = this.creator_name; + } + _annotation.project_id = this.project_id; + + _exportedAnnotations.push(_annotation); /* We add the annotation in the list to export */ + _export.addList("annotation",_exportedAnnotations); /* We add the list to the source object */ + + /* We send the AJAX request to the server ! */ + IriSP.jQuery.ajax({ + url: _url, + type: this.selectedMarker ? this.api_method_edit : this.api_method_create, + contentType: 'application/json', + data: _export.serialize(), + success: function(_data) { + _this.showScreen('Success'); + window.setTimeout(_this.functionWrapper("revertToMainScreen"),(_this.after_send_timeout || 5000)); + _export.getAnnotations().removeElement(_annotation, true); /* We delete the sent annotation to avoid redundancy */ + _export.deSerialize(_data); /* Data deserialization */ + _annotation.id = _data.id; + _this.source.merge(_export); /* We merge the deserialized data with the current source data */ + if (_this.pause_on_write && _this.media.getPaused() && _this.play_on_submit) { + _this.media.play(); + } + _this.markers.push(_annotation); + _this.selectedMarker = _annotation; + _this.drawMarkers(); + _this.player.trigger("AnnotationsList.refresh"); + _this.player.trigger("Markers.refresh"); + }, + error: function(_xhr, _error, _thrown) { + IriSP.log("Error when sending annotation", _thrown); + _export.getAnnotations().removeElement(_annotation, true); + _this.showScreen('Failure'); + window.setTimeout(_this.functionWrapper("revertToMainScreen"),(_this.after_send_timeout || 5000)); + } + }); + this.showScreen('Sending'); + + return false; +}; + +IriSP.Widgets.Markers.prototype.sendDelete = function(){ + _this = this; + _url = Mustache.to_html(this.api_endpoint_template_delete, {annotation_id: this.selectedMarker ? this.selectedMarker.id : "", project_id: this.selectedMarker.project_id? this.selectedMarker.project_id : this.project_id}); + IriSP.jQuery.ajax({ + url: _url, + type: this.api_method_delete, + contentType: 'application/json', + success: function(_data) { + _this.showScreen('DeleteSuccess'); + window.setTimeout(_this.functionWrapper("revertToMainScreen"),(_this.after_send_timeout || 5000)); + if (_this.pause_on_write && _this.media.getPaused() && _this.play_on_submit) { + _this.media.play(); + } + _this.markers.removeElement(_this.selectedMarker); + _this.selectedMarker = false + _this.player.trigger("AnnotationsList.refresh"); + _this.player.trigger("Markers.refresh"); + }, + error: function(_xhr, _error, _thrown) { + IriSP.log("Error when sending annotation", _thrown); + _this.showScreen('Failure'); + window.setTimeout(_this.functionWrapper("revertToMainScreen"),(_this.after_send_timeout || 5000)); + } + }); + this.showScreen("Sending") +} \ No newline at end of file diff -r 20e00017dd60 -r 10974bff4dae web/res/metadataplayer/Mediafragment.js --- a/web/res/metadataplayer/Mediafragment.js Fri Dec 11 18:11:13 2015 +0100 +++ b/web/res/metadataplayer/Mediafragment.js Tue Dec 29 13:25:14 2015 +0100 @@ -2,6 +2,9 @@ IriSP.Widgets.Widget.call(this, player, config); this.last_hash_key = ""; this.last_hash_value = ""; + this.last_extra_key = ""; + this.last_extra_value = ""; + window.onhashchange = this.functionWrapper("goToHash"); if (typeof window.addEventListener !== "undefined") { var _this = this; @@ -22,7 +25,7 @@ var _this = this; this.getWidgetAnnotations().forEach(function(_annotation) { _annotation.on("click", function() { - _this.setHashToAnnotation(_annotation.id); + _this.setHashToAnnotation(_annotation); }); }); if (this.media.loadedMetadata) { @@ -48,6 +51,9 @@ if (this.last_hash_key) { _tab.push(this.last_hash_key + '=' + this.last_hash_value); } + if (this.last_extra_key) { + _tab.push(this.last_extra_key + '=' + this.last_extra_value); + } return '#' + _tab.join('&'); }; @@ -63,10 +69,13 @@ var _annotation = this.source.getElement(this.last_hash_value); if (typeof _annotation !== "undefined") { this.media.setCurrentTime(_annotation.begin); + } else { + /* Proceed parsing elements, maybe a t was specified */ + continue; } } if (this.last_hash_key == "t") { - this.media.setCurrentTime(1000*this.last_hash_value); + this.media.setCurrentTime(1000 * this.last_hash_value); } break; } @@ -74,18 +83,21 @@ } }; -IriSP.Widgets.Mediafragment.prototype.setHashToAnnotation = function(_annotationId) { - this.setHash( 'id', _annotationId ); +IriSP.Widgets.Mediafragment.prototype.setHashToAnnotation = function(_annotation) { + this.setHash( 'id', _annotation.id, 't', _annotation.begin / 1000.0 ); }; IriSP.Widgets.Mediafragment.prototype.setHashToTime = function() { this.setHash( 't', this.media.getCurrentTime().getSeconds() ); }; -IriSP.Widgets.Mediafragment.prototype.setHash = function(_key, _value) { +IriSP.Widgets.Mediafragment.prototype.setHash = function(_key, _value, _key2, _value2) { if (!this.blocked && (this.last_hash_key !== _key || this.last_hash_value !== _value)) { this.last_hash_key = _key; this.last_hash_value = _value; + this.last_extra_key = _key2; + this.last_extra_value = _value2; + var _hash = this.getLastHash(); this.setWindowHash(_hash); if (window.parent !== window) { diff -r 20e00017dd60 -r 10974bff4dae web/res/metadataplayer/MultiSegments.js --- a/web/res/metadataplayer/MultiSegments.js Fri Dec 11 18:11:13 2015 +0100 +++ b/web/res/metadataplayer/MultiSegments.js Tue Dec 29 13:25:14 2015 +0100 @@ -27,7 +27,7 @@ }); this.source.getAnnotationTypes().forEach(function(_anntype) { var segments = _anntype.getAnnotations().filter(function(_ann) { - return _ann.getDuration() > 0; + return _ann.getDuration() > 0 && _ann.getMedia().id == _this.media.id; }); if (segments.length) { @@ -80,7 +80,7 @@ IriSP._({ type: "Segments", annotation_type: _anntype, - width: _this.width + width: '100%' }).extend(segmentsopts) ); @@ -89,7 +89,7 @@ IriSP._({ type: "Annotation", annotation_type: _anntype, - width: _this.width + width: '100%' }).extend(annotationopts) ); diff -r 20e00017dd60 -r 10974bff4dae web/res/metadataplayer/NoteTaking.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/res/metadataplayer/NoteTaking.css Tue Dec 29 13:25:14 2015 +0100 @@ -0,0 +1,5 @@ +/* NoteTaking widget */ +.Ldt-NoteTaking-Text { + width: 100%; + min-height: 360px; +} diff -r 20e00017dd60 -r 10974bff4dae web/res/metadataplayer/NoteTaking.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/res/metadataplayer/NoteTaking.js Tue Dec 29 13:25:14 2015 +0100 @@ -0,0 +1,91 @@ +/* This widget displays a note-taking view, that can be saved to localStorage */ + +IriSP.Widgets.NoteTaking = function(player, config) { + IriSP.Widgets.Widget.call(this, player, config); +} + +IriSP.Widgets.NoteTaking.prototype = new IriSP.Widgets.Widget(); + +IriSP.Widgets.NoteTaking.prototype.defaults = { + // Id that will be used as localStorage key + editable_storage: "" +} + +IriSP.Widgets.NoteTaking.prototype.template = ''; + +IriSP.Widgets.NoteTaking.prototype.draw = function() { + var widget = this; + var content; + var $ = IriSP.jQuery; + + widget.renderTemplate(); + content = widget.$.find('.Ldt-NoteTaking-Text'); + + function load_content() { + $(content).val(window.localStorage[widget.editable_storage]); + } + function save_content() { + window.localStorage[widget.editable_storage] = $(content).val(); + } + + // Load current transcript + if (window.localStorage[widget.editable_storage]) { + load_content(); + } + + // Thanks to http://stackoverflow.com/questions/4456545/how-to-insert-text-at-the-current-caret-position-in-a-textarea + $.fn.insertAtCaret = function(text) { + return this.each(function() { + if (this.selectionStart !== undefined) { + // mozilla/netscape support + var startPos = this.selectionStart, + endPos = this.selectionEnd, + scrollTop = this.scrollTop; + this.value = this.value.substring(0, startPos) + text + this.value.substring(endPos, this.value.length); + this.focus(); + this.selectionStart = startPos + text.length; + this.selectionEnd = startPos + text.length; + this.scrollTop = scrollTop; + } else { + // IE input[type=text] and other browsers + this.value += text; + this.focus(); + this.value = this.value; // forces cursor to end + } + }); + }; + + function getAroundCaret(el, length) { + // Return a selection of 2 * length characters around the caret + var startPos = el.selectionStart; + return el.value.substring(startPos - length, startPos + length); + }; + + + $(content).keydown(function (_event) { + if (_event.keyCode == 13 && (_event.ctrlKey || _event.metaKey)) { + // Insert current timestamp + _event.preventDefault(); + // Get current value + var match = /\[([\d:]+)\]/.exec(getAroundCaret(content[0], 8)); + if (match) { + // Found a timecode. Go to position. + widget.media.setCurrentTime(IriSP.timestamp2ms(match[1])); + } else { + $(content).insertAtCaret("[" + (new IriSP.Model.Time(widget.media.getCurrentTime())).toString() + "]"); + save_content(); + } + } + }).on("input", function (_event) { + console.log("Change"); + // Store updated value + save_content(); + }).on("dblclick", function (_event) { + var match = /\[([\d:]+)\]/.exec(getAroundCaret(content[0], 8)); + if (match) { + // Found a timecode. Go to position. + _event.preventDefault(); + widget.media.setCurrentTime(IriSP.timestamp2ms(match[1])); + }; + }); +}; diff -r 20e00017dd60 -r 10974bff4dae web/res/metadataplayer/Polemic.js --- a/web/res/metadataplayer/Polemic.js Fri Dec 11 18:11:13 2015 +0100 +++ b/web/res/metadataplayer/Polemic.js Tue Dec 29 13:25:14 2015 +0100 @@ -24,37 +24,73 @@ annotation_type : "tweet", defaultcolor : "#585858", foundcolor : "#fc00ff", - polemics : [ - { - "name" : "OK", - "keywords" : [ "++" ], - "color" : "#1D973D" - }, - { - "name" : "KO", - "keywords" : [ "--" ], - "color" : "#CE0A15" - }, - { - "name" : "REF", - "keywords" : [ "==", "http://" ], - "color" : "#C5A62D" - }, - { - "name" : "Q", - "keywords" : [ "?" ], - "color" : "#036AAE" - } - ] + default_version : "1", + polemics : { + "1" : [ + { + "name" : "OK", + "keywords" : [ "++" ], + "color" : "#1D973D" + }, + { + "name" : "KO", + "keywords" : [ "--" ], + "color" : "#CE0A15" + }, + { + "name" : "REF", + "keywords" : [ "==", "http://" ], + "color" : "#C5A62D" + }, + { + "name" : "Q", + "keywords" : [ "?" ], + "color" : "#036AAE" + } + ], + "2" : [ + { + "name" : "OK", + "keywords" : [ "++" ], + "color" : "#1D973D" + }, + { + "name" : "KO", + "keywords" : [ "!!" ], + "color" : "#CE0A15" + }, + { + "name" : "REF", + "keywords" : [ "==", "http://" ], + "color" : "#C5A62D" + }, + { + "name" : "Q", + "keywords" : [ "?" ], + "color" : "#036AAE" + } + ] + } +}; + +IriSP.Widgets.Polemic.prototype.getPolemics = function(version) { + if(typeof(version) === "undefined" || !version) { + version = this.default_version; + } + if(this.polemics.constructor === Array) { + return this.polemics; + } else { + return this.polemics[version]; + } }; IriSP.Widgets.Polemic.prototype.draw = function() { - + this.onMediaEvent("timeupdate", "onTimeupdate"); this.$zone = IriSP.jQuery('
'); this.$zone.addClass("Ldt-Polemic"); this.$.append(this.$zone); - + this.$elapsed = IriSP.jQuery('
') .css({ background: '#cccccc', @@ -64,9 +100,9 @@ width: 0, height: "100%" }); - + this.$zone.append(this.$elapsed); - + // we don't filter with null duration anymore var _slices = [], _slice_count = Math.floor( this.width / this.element_width ), @@ -74,7 +110,7 @@ _max = 0, _list = this.getWidgetAnnotations(), _this = this; - + for (var _i = 0; _i < _slice_count; _i++) { var _begin = new IriSP.Model.Time( _i * _duration / _slice_count ), _end = new IriSP.Model.Time( ( _i + 1 ) * _duration / _slice_count ), @@ -87,13 +123,13 @@ }), polemicStacks : [] }; - - for (var _j = 0; _j < this.polemics.length; _j++) { - var _polemic = _res.annotations.searchByDescription(this.polemics[_j].keywords); + + for (var _j = 0; _j < this.getPolemics().length; _j++) { + var _polemic = _res.annotations.searchByDescription(this.getPolemics()[_j].keywords); _count += _polemic.length; _res.polemicStacks.push(_polemic); } - for (var _j = 0; _j < this.polemics.length; _j++) { + for (var _j = 0; _j < this.getPolemics().length; _j++) { _res.annotations.removeElements(_res.polemicStacks[_j]); } _count += _res.annotations.length; @@ -103,16 +139,16 @@ if (_max < this.max_elements) { this.is_stackgraph = false; if (_max) { - + this.height = (2 + _max) * this.element_height; this.$zone.css({ width: this.width + "px", height: this.height + "px", position: "relative" }); - + var _x = 0; - + function displayAnnotation(_elx, _ely, _pol, _col, _annotation) { var _html = Mustache.to_html( '
'; - for (var _i = 0; _i <= _this.polemics.length; _i++) { - var _color = _i ? _this.polemics[_i - 1].color : _this.defaultcolor; + for (var _i = 0; _i <= _this.getPolemics().length; _i++) { + var _color = _i ? _this.getPolemics()[_i - 1].color : _this.defaultcolor; _html += '

' + _nums[_i] + _this.l10n._annotations + '

'; } if (_this.tooltip) { @@ -303,20 +340,20 @@ _this.tooltip.hide(); } }); - + }; - + this.$position = IriSP.jQuery('
').addClass("Ldt-Polemic-Position"); - + this.$zone.append(this.$position); - + this.$zone.click(function(_e) { var _x = _e.pageX - _this.$zone.offset().left; _this.media.setCurrentTime(_this.media.duration * _x / _this.width); }); - + this.$.append('
'); - + this.insertSubwidget( this.$.find(".Ldt-Polemic-Tooltip"), { diff -r 20e00017dd60 -r 10974bff4dae web/res/metadataplayer/PopcornPlayer.js --- a/web/res/metadataplayer/PopcornPlayer.js Fri Dec 11 18:11:13 2015 +0100 +++ b/web/res/metadataplayer/PopcornPlayer.js Tue Dec 29 13:25:14 2015 +0100 @@ -10,26 +10,18 @@ }; IriSP.Widgets.PopcornPlayer.prototype.draw = function() { - - if (typeof this.video === "undefined") { this.video = this.media.video; } - + if (this.url_transform) { this.video = this.url_transform(this.video); } - - if (/^(https?:\/\/)?(www\.)?vimeo\.com/.test(this.video)) { - - /* VIMEO */ - - var _popcorn = Popcorn.vimeo(this.container, this.video); - - } else if (/^(https?:\/\/)?(www\.)?youtube\.com/.test(this.video)) { - + + var _url = this.video; + + if (/^(https?:\/\/)?(www\.)?youtube\.com/.test(this.video)) { /* YOUTUBE */ - var _urlparts = this.video.split(/[?&]/), _params = {}; for (var i = 1; i < _urlparts.length; i++) { @@ -42,97 +34,106 @@ _params.autoplay = 1; } _url = _urlparts[0] + '?' + IriSP.jQuery.param(_params); - - var _popcorn = Popcorn.youtube(this.container, _url); - - } else { - - /* DEFAULT HTML5 */ - - var _tmpId = IriSP._.uniqueId("popcorn"), - _videoEl = IriSP.jQuery('