rework transcript component to correct various bugs
authorymh <ymh.work@gmail.com>
Fri, 02 Dec 2016 00:22:31 +0100
changeset 454 710a2ae08a74
parent 453 1059a7ae018a
child 455 a8bed1c7df8e
rework transcript component to correct various bugs
cms/app-client/app/components/transcript-annotation-component.js
cms/app-client/app/components/transcript-component.js
cms/app-client/app/components/transcript-section-component.js
cms/app-client/app/components/transcript-turn-component.js
cms/app-client/app/serializers/transcript.js
cms/app-client/app/styles/components/notice-location-component.scss
cms/app-client/app/styles/components/transcript-component.scss
cms/app-client/app/templates/components/transcript-annotation-component.hbs
cms/app-client/app/templates/components/transcript-component.hbs
cms/app-client/app/templates/components/transcript-section-component.hbs
cms/app-client/app/templates/components/transcript-turn-component.hbs
cms/app-client/mirage/fixtures/bnfs.js
cms/app-client/mirage/fixtures/dateminmax.js
cms/app-client/mirage/fixtures/datestats.js
cms/app-client/mirage/fixtures/discourses.js
cms/app-client/mirage/fixtures/documents.js
cms/app-client/mirage/fixtures/geonames.js
cms/app-client/mirage/fixtures/geostats.js
cms/app-client/mirage/fixtures/languages.js
cms/app-client/mirage/fixtures/lexvos.js
cms/app-client/mirage/fixtures/themes.js
cms/app-client/mirage/fixtures/transcripts.js
cms/app-client/mirage/fixtures/viafs.js
cms/app-client/tests/integration/components/transcript-annotation-component-test.js
cms/app-client/tests/integration/components/transcript-section-component-test.js
cms/app-client/tests/integration/components/transcript-turn-component-test.js
common/corpus-common-addon/lib/commands/dl-fixtures.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cms/app-client/app/components/transcript-annotation-component.js	Fri Dec 02 00:22:31 2016 +0100
@@ -0,0 +1,23 @@
+import Ember from 'ember';
+
+export default Ember.Component.extend({
+
+  classNameBindings: ['isPlaying:active'],
+
+  hasPlayer: Ember.computed.bool('player'),
+
+  begin: Ember.computed.readOnly('annotation.begin'),
+  end: Ember.computed.readOnly('annotation.end'),
+  title: Ember.computed.readOnly('annotation.title'),
+  original: Ember.computed.readOnly('annotation.original'),
+  speaker: Ember.computed.readOnly('annotation.speaker'),
+  showSpeaker: Ember.computed.readOnly('annotation.showSpeaker'),
+  literal: Ember.computed.readOnly('annotation.literal'),
+  translation: Ember.computed.readOnly('annotation.translation'),
+
+  isPlaying: Ember.computed("hasPlayer","player.progress", "begin", "end", function() {
+    var progress = this.get('player.progress');
+    return this.get('hasPlayer') && progress && (progress >= this.get('begin')) && (progress < this.get('end'));
+  })
+
+});
--- a/cms/app-client/app/components/transcript-component.js	Mon Nov 28 23:11:54 2016 +0100
+++ b/cms/app-client/app/components/transcript-component.js	Fri Dec 02 00:22:31 2016 +0100
@@ -11,8 +11,15 @@
     autoscroll: true,
     timeout: null,
 
+    hasSections: Ember.computed('player', 'player.transcript', function() {
+      var sections = this.get('player.transcript.sections');
+      return sections && sections.length > 0;
+    }),
+
     itemObserver: Ember.observer('player.item', function () {
-        this.set('autoscroll', true);
+      if ( !(this.get('isDestroyed') || this.get('isDestroying')) ) {
+          this.set('autoscroll', true);
+      }
     }),
 
     didInsertElement: function() {
@@ -20,25 +27,30 @@
     },
 
     onScroll: function() {
-        this.set('autoscroll', false);
-        Ember.$('#' + this.elementId).parent().off('scroll');
+        if ( !(this.get('isDestroyed') || this.get('isDestroying')) ) {
+          this.set('autoscroll', false);
+        }
+        if(this.elementId) {
+          Ember.$('#' + this.elementId).parent().off('scroll');
+        }
     },
 
-    didUpdate: function() {
-        var self = this;
-        var target = Ember.$('.sentence.active');
-        if(this.get('autoscroll') && target.length && target.attr('data-ember-action') !== this.get('previousElement')) {
-            Ember.$('#' + self.elementId).parent().off('scroll');
-            Ember.$(this.get('autoscrollElement')).animate({
-                scrollTop: target.offset().top + Ember.$(this.get('autoscrollElement')).scrollTop() - Ember.$(this.get('autoscrollElement')).offset().top - 154
-            }, 150, 'swing', function() {
-                setTimeout(function() {
-                    Ember.$('#' + self.elementId).parent().on('scroll', Ember.run.bind(self, self.onScroll));
-                }, 100);
-            });
-            this.set('previousElement', target.attr('data-ember-action'));
-        }
-    },
+    scroll: Ember.observer('player.progress', function() {
+      var self = this;
+      var target = this.$('.sentence.active');
+      if(this.get('autoscroll') && target.length && target.attr('id') !== this.get('previousElement')) {
+          Ember.$('#' + self.elementId).parent().off('scroll');
+          Ember.$(this.get('autoscrollElement')).animate({
+              scrollTop: target.offset().top + Ember.$(this.get('autoscrollElement')).scrollTop() - Ember.$(this.get('autoscrollElement')).offset().top - 154
+          }, 150, 'swing', function() {
+              setTimeout(function() {
+                  Ember.$('#' + self.elementId).parent().on('scroll', Ember.run.bind(self, self.onScroll));
+              }, 100);
+          });
+          this.set('previousElement', target.attr('id'));
+      }
+    }),
+
 
     actions: {
 
@@ -46,7 +58,6 @@
             this.get('player').trigger('progressupdate', progress);
             this.get('player').set('playing', true);
         }
-
     }
 
 });
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cms/app-client/app/components/transcript-section-component.js	Fri Dec 02 00:22:31 2016 +0100
@@ -0,0 +1,6 @@
+import Ember from 'ember';
+
+export default Ember.Component.extend({
+  turns: Ember.computed.readOnly("section.turns"),
+  title: Ember.computed.readOnly("section.title"),
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cms/app-client/app/components/transcript-turn-component.js	Fri Dec 02 00:22:31 2016 +0100
@@ -0,0 +1,18 @@
+import Ember from 'ember';
+
+export default Ember.Component.extend({
+  tagName: 'li',
+
+  classNames: ['sentence'],
+  classNameBindings: ['isPlaying:active'],
+
+  begin: Ember.computed.readOnly('turn.begin'),
+  end: Ember.computed.readOnly('turn.end'),
+  title: Ember.computed.readOnly('turn.title'),
+  annotations: Ember.computed.readOnly('turn.annotations'),
+
+  isPlaying: Ember.computed("player.progress", "begin", "end", function() {
+    var progress = this.get('player.progress');
+    return progress && progress >= this.get('begin') && progress < this.get('end');
+  })
+});
--- a/cms/app-client/app/serializers/transcript.js	Mon Nov 28 23:11:54 2016 +0100
+++ b/cms/app-client/app/serializers/transcript.js	Fri Dec 02 00:22:31 2016 +0100
@@ -1,109 +1,103 @@
 import JSONAPISerializer from 'ember-data/serializers/json-api';
+import _ from 'lodash/lodash';
 
 export default JSONAPISerializer.extend({
 
     normalizeResponse: function(store, primaryModelClass, payload, id) {
-        var speakers = payload['resources'].find(resource => resource['id'] === 'speakers');
-        var topics = payload['resources'].find(resource => resource['id'] === 'topics');
+        var speakerResources = payload['resources'].find(resource => resource['id'] === 'speakers') || {'content': { 'data': []}};
+        var speakers = _.reduce(
+          speakerResources['content']['data'],
+          function(res, s) { res[s.id] = s; return res;},
+          {});
+        var topicsResources = payload['resources'].find(resource => resource['id'] === 'topics') || {'content': { 'data': []}};
+        var topics = _.reduce(
+          topicsResources['content']['data'],
+          function(res, r) { res[r.id] = r; return res;},
+          {});
+
         var translationISO = false;
 
-        var buildFragment = function(annotation) {
-            var fragment = {
-                'original': annotation['content']['data']['content']
+        var turns = _.reduce(payload['annotation-types'] || [], function(res, t) {
+            res[t['id']] = {
+                title: t['dc:title'],
+                begin: t['corpus:begin'],
+                end: t['corpus:end'],
+                annotations: []
+            };
+            return res;
+        },{});
+
+        var sections = _.map(payload['lists'] || [], function(list){
+          var topic = topics[list['meta']['corpus:topic']['id-ref']];
+          return {
+            title: (topic && topic['desc'])?topic['desc'] : null,
+            begin: list['meta']['corpus:begin'],
+            end: list['meta']['corpus:end'],
+            turns: _.reduce((list['items'] || []), function(res,item) {
+              if(item['id-ref'] && turns[item['id-ref']]) {
+                res.push(turns[item['id-ref']]);
+              }
+              return res;
+            }, [])
+          };
+        });
+
+        var currentSpeaker = null;
+        var annotations = _.map(payload['annotations'] || [], function(annotation) {
+            var annot = {
+              original: annotation['content']['data']['content'],
+              begin: annotation['begin'],
+              end: annotation['end']
             };
             if(annotation['content']['data']['transl']) {
-                fragment['translation'] = annotation['content']['data']['transl']['@value'];
+                annot['translation'] = annotation['content']['data']['transl']['@value'];
             }
             if(annotation['content']['data']['words']) {
-                var words = [];
-                annotation['content']['data']['words'].forEach(function(word) {
-                    words.push({
+                var words = _.map(annotation['content']['data']['words'], function(word) {
+                    return {
                         'original': word['content'],
                         'translation': word['transl']['@value']
-                    });
+                    };
                 });
-                fragment['literal'] = words;
+                annot['literal'] = words;
             }
             if(annotation['content']['data']['speaker']) {
                 if(typeof annotation['content']['data']['speaker'] === 'object') {
-                    var speaker = speakers['content']['data'].find(speaker => speaker['id'] === annotation['content']['data']['speaker']['id-ref']);
+                    var speaker = speakers[annotation['content']['data']['speaker']['id-ref']];
                     if(speaker) {
-                        fragment['speaker'] = speaker['name'];
+                        annot['speaker'] = speaker['name'];
                     }
                 } else {
-                    fragment['speaker'] = annotation['content']['data']['speaker'];
+                    annot['speaker'] = annotation['content']['data']['speaker'];
                 }
+                annot['showSpeaker'] = (annot['speaker'] === currentSpeaker);
+                currentSpeaker = annot['speaker'];
             }
-            return fragment;
-        };
-
-        var annotations = [];
-        payload['annotations'].forEach(function(annotation) {
-            var previous = annotations[annotations.length - 1];
-            if(previous && annotation['begin'] === previous.begin && annotation['end'] === previous.end) {
-                previous.fragments.push(buildFragment(annotation));
-            } else {
-                var object = {
-                    'fragments': [buildFragment(annotation)],
-                    'begin': annotation['begin'],
-                    'end': annotation['end'],
-                };
-                annotations.push(object);
+            if(annotation['type'] && turns[annotation['type']]) {
+              var type = turns[annotation['type']];
+              annot['type'] = type;
+              type.annotations.push(annot);
             }
             if(!translationISO && annotation['content']['data']['transl']) {
                 translationISO = annotation['content']['data']['transl']['@language'];
             }
+
+            return annot;
         });
 
-        if(payload['annotation-types'].length) {
-            var types = [];
-            payload['annotation-types'].forEach(function(t) {
-                var object = {
-                    'title': t['dc:title'],
-                    'begin': t['corpus:begin'],
-                    'end': t['corpus:end']
-                };
-                var fragments = annotations.find(function(annotation) { return annotation['begin'] === t['corpus:begin'] && annotation['end'] === t['corpus:end']; });
-                if(fragments) {
-                    object['fragments'] = fragments['fragments'];
-                }
-                types.push(object);
-            });
-            annotations = types;
-        }
-
-        var sections = [];
-        if(payload['lists'].length) {
-            var lists = [];
-            payload['lists'].forEach(function(list) {
-                var topic = topics['content']['data'].find(topic => topic.id === list['meta']['corpus:topic']['id-ref']);
-                sections.push({
-                    'title': topic['desc'],
-                    'begin': list['meta']['corpus:begin'],
-                    'end': list['meta']['corpus:end']
-                });
-                lists.push(annotations.filter(annotation => annotation['begin'] >= list['meta']['corpus:begin'] && annotation['end'] <= list['meta']['corpus:end']));
-            });
-            annotations = lists;
-        } else {
-            annotations = [annotations];
-        }
-
         var response = {
             'data': {
-                'id': id,
-                'type': 'transcript',
-                'attributes': {
-                    'title': {},
-                    'annotations': annotations
+                id: id,
+                type: 'transcript',
+                attributes: {
+                    title: {},
+                    annotations: annotations,
+                    sections: sections,
+                    turns: turns
                 }
             }
         };
 
-        if(sections.length) {
-            response.data.attributes.sections = sections;
-        }
-
         if(Array.isArray(payload['meta']['dc:title'])) {
             var original = payload['meta']['dc:title'].find(function(title) { return title['@language'] !== translationISO; });
             if(original) {
--- a/cms/app-client/app/styles/components/notice-location-component.scss	Mon Nov 28 23:11:54 2016 +0100
+++ b/cms/app-client/app/styles/components/notice-location-component.scss	Fri Dec 02 00:22:31 2016 +0100
@@ -3,6 +3,9 @@
   .notice-location-meta {
     float: left;
     width: 60%;
+    box-sizing: border-box;
+    overflow-wrap: break-word;
+    padding-right: 5px;
   }
 
   .notice-location-map {
@@ -33,10 +36,6 @@
     font-size: 10px;
   }
 
-  .notice-location-meta {
-    overflow-wrap: break-word;
-  }
-
   .notice-location-ext-link {
     color: $corpus-grey;
     text-decoration: none;
--- a/cms/app-client/app/styles/components/transcript-component.scss	Mon Nov 28 23:11:54 2016 +0100
+++ b/cms/app-client/app/styles/components/transcript-component.scss	Fri Dec 02 00:22:31 2016 +0100
@@ -13,9 +13,9 @@
     position: absolute;
     z-index: 1;
     width: inherit;
-    background: linear-gradient($corpus-light-grey, $corpus-light-grey 50%, transparent);
+    //background: linear-gradient($corpus-light-grey, $corpus-light-grey 50%, transparent);
     padding-top: 12px;
-    padding-bottom: 66px;
+    padding-bottom: 20px;
     line-height: 30px;
     margin: 0px!important;
     color: $corpus-blue;
@@ -32,9 +32,14 @@
     position: static;
 }
 
+body.videoscreen .transcript-component .transcript {
+    margin: 0px;
+    padding: 154px 20px 0px 20px;
+}
+
 .transcript-component .transcript {
     margin: 0px;
-    padding: 154px 20px 0px 20px;
+    padding: 70px 20px 0px 20px;
 }
 
 body.videoscreen .transcript-component .transcript {
@@ -42,7 +47,7 @@
 }
 
 .transcript-component .transcript h3 {
-    padding: 20px 20px 20px 64px;
+    padding: 10px 10px 10px 32px;
     font-weight: bold;
     color: $corpus-blue;
     font-size: 12px;
@@ -56,7 +61,7 @@
 }
 
 .transcript-component .transcript .annotations .sentence {
-    padding: 20px 20px 20px 64px;
+    padding: 10px 10px 10px 32px;
     color: $corpus-black;
     position: relative;
     background-color: transparent;
@@ -84,7 +89,7 @@
 
 .transcript-component .transcript .annotations .sentence .words {
     font-size: 0px;
-    margin: 10px 0px;
+    margin: 5px 0px;
 }
 
 .transcript-component .transcript .annotations .sentence .words .word {
@@ -141,7 +146,7 @@
     width: 24px;
     height: 24px;
     line-height: 20px;
-    left: 20px;
+    left: 0;
     cursor: pointer;
     opacity: 1;
     color: $corpus-black;
@@ -165,6 +170,10 @@
     font-weight: bold;
 }
 
+.transcript-component .transcript .annotations .sentence .hidden-speaker {
+    visibility: hidden;
+}
+
 .transcript-component .transcript .annotations .sentence .title {
     float: right;
     line-height: 24px;
@@ -179,4 +188,4 @@
 
 .transcript-component .transcript .annotations .sentence:not(.active):hover .title {
     color: $corpus-white;
-}
\ No newline at end of file
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cms/app-client/app/templates/components/transcript-annotation-component.hbs	Fri Dec 02 00:22:31 2016 +0100
@@ -0,0 +1,28 @@
+{{#if hasPlayer }}
+  {{#unless isPlaying}}
+  <i class="fa fa-play" {{action play begin}}>Play</i>
+  {{/unless}}
+  {{#if title}}<span class="title">{{title}}</span>{{/if}}
+{{/if}}
+<div class="fragment">
+  {{#if original}}
+  <p class="original">
+      {{#if speaker}}<span class="speaker {{if hideSpeaker 'hidden-speaker'}}">{{speaker}} :</span>{{/if}}
+      {{original}}
+  </p>
+  {{/if}}
+  {{#if literal}}
+  <div class="words">
+      {{#each literal as |word|}}
+      <div class="word">
+          <p class="original">{{word.original}}</p>
+          <p class="translation">{{word.translation}}</p>
+      </div>
+      {{/each}}
+  </div>
+  {{/if}}
+  {{#if translation}}
+    <p class="translation">{{translation}}</p>
+  {{/if}}
+</div>
+
--- a/cms/app-client/app/templates/components/transcript-component.hbs	Mon Nov 28 23:11:54 2016 +0100
+++ b/cms/app-client/app/templates/components/transcript-component.hbs	Fri Dec 02 00:22:31 2016 +0100
@@ -6,43 +6,15 @@
 </h2>
 
 <div class="transcript">
-    {{#each player.transcript.annotations as |annotations index|}}
-    {{#if player.transcript.sections}}
-    <h3>{{array-index (array-index player.transcript.sections index) 'title'}}</h3>
-    {{/if}}
+  {{#if hasSections }}
+    {{#each player.transcript.sections as |section|}}
+      {{transcript-section-component section=section player=player play=(action 'play')}}
+    {{/each}}
+  {{else}}
     <ol class="annotations">
-        {{#each annotations as |annotation|}}
-        <li class="sentence {{if (if-and (if-operator player.progress '>=' annotation.begin) (if-operator player.progress '<' annotation.end)) 'active'}}" {{action 'play' annotation.begin}}>
-            {{#unless (if-and (if-operator player.progress '>=' annotation.begin) (if-operator player.progress '<' annotation.end))}}
-            <i class="fa fa-play" {{action 'play' annotation.begin}}>Play</i>
-            {{/unless}}
-            {{#if annotation.title}}<span class="title">{{annotation.title}}</span>{{/if}}
-            {{#each annotation.fragments as |fragment|}}
-            <div class="fragment">
-                
-                {{#if fragment.original}}
-                <p class="original">
-                    {{#if fragment.speaker}}<span class="speaker">{{fragment.speaker}} :</span>{{/if}}
-                    {{fragment.original}}
-                </p>
-                {{/if}}
-                {{#if fragment.literal}}
-                <div class="words">
-                    {{#each fragment.literal as |word|}}
-                    <div class="word">
-                        <p class="original">{{word.original}}</p>
-                        <p class="translation">{{word.translation}}</p>
-                    </div>
-                    {{/each}}
-                </div>
-                {{/if}}
-                {{#if fragment.translation}}
-                <p class="translation">{{fragment.translation}}</p>
-                {{/if}}
-            </div>
-            {{/each}}   
-        </li>
-        {{/each}}
+    {{#each player.transcript.annotations as |annotation|}}
+      {{transcript-annotation-component annotation=annotation player=player play=(action 'play') tagName='li' class='sentence'}}
+    {{/each}}
     </ol>
-    {{/each}}
+  {{/if}}
 </div>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cms/app-client/app/templates/components/transcript-section-component.hbs	Fri Dec 02 00:22:31 2016 +0100
@@ -0,0 +1,7 @@
+<h3>{{title}}</h3>
+<ol class="annotations">
+  {{#each turns as |turn|}}
+  {{transcript-turn-component turn=turn player=player play=(action play)}}
+  {{/each}}
+</ol>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cms/app-client/app/templates/components/transcript-turn-component.hbs	Fri Dec 02 00:22:31 2016 +0100
@@ -0,0 +1,8 @@
+{{#unless isPlaying}}
+  <i class="fa fa-play" {{action play begin}}>Play</i>
+{{/unless}}
+{{#if title}}<span class="title">{{title}}</span>{{/if}}
+{{#each annotations as |annotation|}}
+{{transcript-annotation-component annotation=annotation}}
+{{/each}}
+
--- a/cms/app-client/mirage/fixtures/bnfs.js	Mon Nov 28 23:11:54 2016 +0100
+++ b/cms/app-client/mirage/fixtures/bnfs.js	Fri Dec 02 00:22:31 2016 +0100
@@ -1,3 +1,4 @@
+// jshint ignore: start
 export default [
     {'id': 'ark:/12148/cb11965628b', 'label': 'frères et soeurs'},
     {'id': 'ark:/12148/cb11946662b', 'label': 'parents et enfants'},
--- a/cms/app-client/mirage/fixtures/dateminmax.js	Mon Nov 28 23:11:54 2016 +0100
+++ b/cms/app-client/mirage/fixtures/dateminmax.js	Fri Dec 02 00:22:31 2016 +0100
@@ -1,3 +1,4 @@
+// jshint ignore: start
 export default [
   { 'id': "1948" },
   { 'id': "2015" }
--- a/cms/app-client/mirage/fixtures/datestats.js	Mon Nov 28 23:11:54 2016 +0100
+++ b/cms/app-client/mirage/fixtures/datestats.js	Fri Dec 02 00:22:31 2016 +0100
@@ -1,3 +1,4 @@
+// jshint ignore: start
 export default [
   { 'id': "1948", "count": 3 },
   { 'id': "1957", "count": 29 },
--- a/cms/app-client/mirage/fixtures/discourses.js	Mon Nov 28 23:11:54 2016 +0100
+++ b/cms/app-client/mirage/fixtures/discourses.js	Fri Dec 02 00:22:31 2016 +0100
@@ -1,3 +1,4 @@
+// jshint ignore: start
 export default [
   {
     "id": "http://ark.bnf.fr/ark:/12148/cb12481481z",
@@ -99,4 +100,4 @@
     "count": 1,
     "label": "fables"
   }
-];
\ No newline at end of file
+];
--- a/cms/app-client/mirage/fixtures/documents.js	Mon Nov 28 23:11:54 2016 +0100
+++ b/cms/app-client/mirage/fixtures/documents.js	Fri Dec 02 00:22:31 2016 +0100
@@ -1,3 +1,4 @@
+// jshint ignore: start
 export default [
   {
     "id": "11280.100/crdo-UVE_MOCIKA_SOUND",
@@ -5821,4 +5822,4 @@
       "longitude": "2.43528"
     }
   }
-];
\ No newline at end of file
+];
--- a/cms/app-client/mirage/fixtures/geonames.js	Mon Nov 28 23:11:54 2016 +0100
+++ b/cms/app-client/mirage/fixtures/geonames.js	Fri Dec 02 00:22:31 2016 +0100
@@ -1,3 +1,4 @@
+// jshint ignore: start
 export default [
     { 'id': '3038033', 'label': 'Alsace' },
     { 'id': '6617404', 'label': 'Andlau' },
--- a/cms/app-client/mirage/fixtures/geostats.js	Mon Nov 28 23:11:54 2016 +0100
+++ b/cms/app-client/mirage/fixtures/geostats.js	Fri Dec 02 00:22:31 2016 +0100
@@ -1,3 +1,4 @@
+// jshint ignore: start
 export default [{
     'id': "6295630", //earth (world)
     areas: [
--- a/cms/app-client/mirage/fixtures/languages.js	Mon Nov 28 23:11:54 2016 +0100
+++ b/cms/app-client/mirage/fixtures/languages.js	Fri Dec 02 00:22:31 2016 +0100
@@ -1,3 +1,4 @@
+// jshint ignore: start
 export default [
   { 'id': "http://lexvo.org/id/iso639-3/fra", 'count': 1559 },
   { 'id': "http://lexvo.org/id/iso639-3/gsw", 'count': 851 },
--- a/cms/app-client/mirage/fixtures/lexvos.js	Mon Nov 28 23:11:54 2016 +0100
+++ b/cms/app-client/mirage/fixtures/lexvos.js	Fri Dec 02 00:22:31 2016 +0100
@@ -1,3 +1,4 @@
+// jshint ignore: start
 export default [
     { 'id': "http://lexvo.org/id/iso639-3/fra", 'name': "français" },
     { 'id': "http://lexvo.org/id/iso639-3/gsw", 'name': "alémanique" },
--- a/cms/app-client/mirage/fixtures/themes.js	Mon Nov 28 23:11:54 2016 +0100
+++ b/cms/app-client/mirage/fixtures/themes.js	Fri Dec 02 00:22:31 2016 +0100
@@ -1,3 +1,4 @@
+// jshint ignore: start
 export default [
   {
     "id": "http://ark.bnf.fr/ark:/12148/cb13318415c",
@@ -4594,4 +4595,4 @@
     "count": 1,
     "label": "communisme municipal"
   }
-];
\ No newline at end of file
+];
--- a/cms/app-client/mirage/fixtures/transcripts.js	Mon Nov 28 23:11:54 2016 +0100
+++ b/cms/app-client/mirage/fixtures/transcripts.js	Fri Dec 02 00:22:31 2016 +0100
@@ -1,3 +1,4 @@
+// jshint ignore: start
 export default [
   {
     "id": "11280.100/crdo-UVE_MOCIKA_SOUND",
--- a/cms/app-client/mirage/fixtures/viafs.js	Mon Nov 28 23:11:54 2016 +0100
+++ b/cms/app-client/mirage/fixtures/viafs.js	Fri Dec 02 00:22:31 2016 +0100
@@ -1,3 +1,4 @@
+// jshint ignore: start
 export default [
   { id: "http://viaf.org/viaf/7444539", name: "Bernard Vernier" },
   { id: "http://viaf.org/viaf/10920079", name: "Isabelle Bril" },
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cms/app-client/tests/integration/components/transcript-annotation-component-test.js	Fri Dec 02 00:22:31 2016 +0100
@@ -0,0 +1,24 @@
+import { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('transcript-annotation-component', 'Integration | Component | transcript annotation component', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });
+
+  this.render(hbs`{{transcript-annotation-component}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:
+  this.render(hbs`
+    {{#transcript-annotation-component}}
+      template block text
+    {{/transcript-annotation-component}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cms/app-client/tests/integration/components/transcript-section-component-test.js	Fri Dec 02 00:22:31 2016 +0100
@@ -0,0 +1,24 @@
+import { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('transcript-section-component', 'Integration | Component | transcript section component', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });
+
+  this.render(hbs`{{transcript-section-component}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:
+  this.render(hbs`
+    {{#transcript-section-component}}
+      template block text
+    {{/transcript-section-component}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cms/app-client/tests/integration/components/transcript-turn-component-test.js	Fri Dec 02 00:22:31 2016 +0100
@@ -0,0 +1,24 @@
+import { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('transcript-turn-component', 'Integration | Component | transcript turn component', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });
+
+  this.render(hbs`{{transcript-turn-component}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:
+  this.render(hbs`
+    {{#transcript-turn-component}}
+      template block text
+    {{/transcript-turn-component}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});
--- a/common/corpus-common-addon/lib/commands/dl-fixtures.js	Mon Nov 28 23:11:54 2016 +0100
+++ b/common/corpus-common-addon/lib/commands/dl-fixtures.js	Fri Dec 02 00:22:31 2016 +0100
@@ -61,7 +61,7 @@
                 []
             );
             var prefix = (that.format==='es6')?'export default ':'module.exports = ';
-            fs.writeFile(that.dest, prefix + JSON.stringify(objectList,null,2) + ';', function(err) {
+            fs.writeFile(that.dest, "// jshint ignore: start\n" + prefix + JSON.stringify(objectList,null,2) + ';', function(err) {
                 if(err) {
                     return done.reject(err);
                 }
@@ -138,7 +138,7 @@
         }).then(function(res) {
             var deferred = Q.defer();
             var prefix = (this.format==='es6')?'export default ':'module.exports = ';
-            fs.writeFile(this.dest, prefix + JSON.stringify(res,null,2) + ';', function(err) {
+            fs.writeFile(this.dest, "// jshint ignore: start\n" + prefix + JSON.stringify(res,null,2) + ';', function(err) {
                 if(err) {
                     return deferred.reject(err);
                 }
@@ -220,7 +220,7 @@
                 if(key in destFiles) {
                     ui.writeLine(chalk.green('Writing ' + key + ' in file ' + destFiles[key]));
                     var prefix = (format==='es6')?'export default ':'module.exports = ';
-                    fs.writeFile(destFiles[key], prefix + JSON.stringify(res,null,2) + ';', function(err) {
+                    fs.writeFile(destFiles[key], "// jshint ignore: start\n" + prefix + JSON.stringify(res,null,2) + ';', function(err) {
                         if(err) {
                             return deferred.reject(err);
                         }