2 |
2 |
3 import Mustache from "mustache"; |
3 import Mustache from "mustache"; |
4 import _ from "lodash"; |
4 import _ from "lodash"; |
5 import jQuery from "jquery"; |
5 import jQuery from "jquery"; |
6 |
6 |
|
7 const IsImageOk = function (img) { |
|
8 // During the onload event, IE correctly identifies any images that |
|
9 // weren’t downloaded as not complete. Others should too. Gecko-based |
|
10 // browsers act like NS4 in that they report this incorrectly. |
|
11 if (!img.complete) { |
|
12 return false; |
|
13 } |
|
14 |
|
15 // However, they do have two very useful properties: naturalWidth and |
|
16 // naturalHeight. These give the true size of the image. If it failed |
|
17 // to load, either of these should be zero. |
|
18 if (img.naturalWidth === 0) { |
|
19 return false; |
|
20 } |
|
21 |
|
22 // No other way of checking: assume it’s ok. |
|
23 return true; |
|
24 } |
|
25 |
7 const AnnotationsList = function (ns) { |
26 const AnnotationsList = function (ns) { |
|
27 |
|
28 const thumbnailBuffer = {}; |
|
29 |
8 return class extends ns.Widgets.Widget { |
30 return class extends ns.Widgets.Widget { |
9 constructor(player, config) { |
31 constructor(player, config) { |
10 super(player, config); |
32 super(player, config); |
11 this.lastIds = []; |
33 this.lastIds = []; |
12 var _this = this; |
34 var _this = this; |
276 |
298 |
277 static annotationTemplate = |
299 static annotationTemplate = |
278 '<li class="Ldt-AnnotationsList-li Ldt-Highlighter-Annotation Ldt-TraceMe" data-annotation="{{ id }}" data-begin="{{ begin_ms }}" data-end="{{ end_ms }}" trace-info="annotation-id:{{id}}, media-id:{{media_id}}" style="{{specific_style}}">' + |
300 '<li class="Ldt-AnnotationsList-li Ldt-Highlighter-Annotation Ldt-TraceMe" data-annotation="{{ id }}" data-begin="{{ begin_ms }}" data-end="{{ end_ms }}" trace-info="annotation-id:{{id}}, media-id:{{media_id}}" style="{{specific_style}}">' + |
279 '<div data-annotation="{{ id }}" class="Ldt-AnnotationsList-ThumbContainer Ldt-AnnotationsList-Annotation-Screen Ldt-AnnotationsList-Annotation-ScreenMain">' + |
301 '<div data-annotation="{{ id }}" class="Ldt-AnnotationsList-ThumbContainer Ldt-AnnotationsList-Annotation-Screen Ldt-AnnotationsList-Annotation-ScreenMain">' + |
280 '<a {{#url}}href="{{url}}"{{/url}} draggable="true">' + |
302 '<a {{#url}}href="{{url}}"{{/url}} draggable="true">' + |
281 '<img title="{{^external}}{{ begin }} - {{ end }}{{/external}}{{#external}}{{l10n.external_annotation}}{{/external}}" class="Ldt-AnnotationsList-Thumbnail" src="{{thumbnail}}" />' + |
303 '<img title="{{^external}}{{ begin }} - {{ end }}{{/external}}{{#external}}{{l10n.external_annotation}}{{/external}}" class="Ldt-AnnotationsList-Thumbnail" id="{{thumbnailId}}" />' + |
282 '{{#external}}<div title="{{l10n.external_annotation}}" class="Ldt-AnnotationsList-External-Icon"></div>{{/external}}' + |
304 '{{#external}}<div title="{{l10n.external_annotation}}" class="Ldt-AnnotationsList-External-Icon"></div>{{/external}}' + |
283 "</a>" + |
305 "</a>" + |
284 "</div>" + |
306 "</div>" + |
285 "{{#allow_annotations_deletion}}" + |
307 "{{#allow_annotations_deletion}}" + |
286 '<div data-annotation="{{ id }}" class="Ldt-AnnotationsList-DeleteButton">✖</div>' + |
308 '<div data-annotation="{{ id }}" class="Ldt-AnnotationsList-DeleteButton">✖</div>' + |
384 * Import annotations |
406 * Import annotations |
385 */ |
407 */ |
386 importAnnotations() { |
408 importAnnotations() { |
387 var widget = this; |
409 var widget = this; |
388 var $ = jQuery; |
410 var $ = jQuery; |
389 var textarea = $("<textarea>"); |
411 var textarea = jQuery("<textarea>"); |
390 var el = $("<div>") |
412 var el = jQuery("<div>") |
391 .append( |
413 .append( |
392 $("<span>") |
414 jQuery("<span>") |
393 .addClass("importAnnotationsLabel") |
415 .addClass("importAnnotationsLabel") |
394 .text(widget.messages.import_annotations) |
416 .text(widget.messages.import_annotations) |
395 ) |
417 ) |
396 .addClass("importContainer") |
418 .addClass("importContainer") |
397 .dialog({ |
419 .dialog({ |
654 _annotation.begin / 1000.0, |
676 _annotation.begin / 1000.0, |
655 _external = |
677 _external = |
656 _annotation.project != _this.source.projectId ? true : false, |
678 _annotation.project != _this.source.projectId ? true : false, |
657 _title = "", |
679 _title = "", |
658 _description = _annotation.description, |
680 _description = _annotation.description, |
|
681 _thumbnailId = `thumb_${_annotation.id}`, |
659 _thumbnail = |
682 _thumbnail = |
660 typeof _annotation.thumbnail !== "undefined" && |
683 typeof _annotation.thumbnail !== "undefined" && |
661 _annotation.thumbnail |
684 _annotation.thumbnail |
662 ? _annotation.thumbnail |
685 ? _annotation.thumbnail |
663 : _this.default_thumbnail; |
686 : _this.default_thumbnail; |
|
687 |
664 if (_this.show_creator) { |
688 if (_this.show_creator) { |
665 if (_annotation.creator) { |
689 if (_annotation.creator) { |
666 var _users = [], |
690 var _users = [], |
667 _user = {}, |
691 _user = {}, |
668 _creator = ""; |
692 _creator = ""; |
719 end: _annotation.end.toString(), |
743 end: _annotation.end.toString(), |
720 created: _created, |
744 created: _created, |
721 show_timecode: _this.show_timecode, |
745 show_timecode: _this.show_timecode, |
722 show_end_time: _this.show_end_time, |
746 show_end_time: _this.show_end_time, |
723 show_title: _this.show_title && _title, |
747 show_title: _this.show_title && _title, |
724 thumbnail: _thumbnail, |
748 thumbnailId: _thumbnailId, |
725 url: _url, |
749 url: _url, |
726 tags: _tags, |
750 tags: _tags, |
727 specific_style: |
751 specific_style: |
728 typeof _bgcolor !== "undefined" |
752 typeof _bgcolor !== "undefined" |
729 ? "background-color: " + _bgcolor |
753 ? "background-color: " + _bgcolor |
794 }, |
818 }, |
795 _onunselect = function () { |
819 _onunselect = function () { |
796 _this.$.find(".Ldt-AnnotationsList-li").removeClass("selected"); |
820 _this.$.find(".Ldt-AnnotationsList-li").removeClass("selected"); |
797 }; |
821 }; |
798 _el |
822 _el |
799 .mouseover(function () { |
823 .on("mouseover",function () { |
800 _annotation.trigger("select"); |
824 _annotation.trigger("select"); |
801 }) |
825 }) |
802 .mouseout(function () { |
826 .on("mouseout",function () { |
803 _annotation.trigger("unselect"); |
827 _annotation.trigger("unselect"); |
804 }) |
828 }) |
805 .click(function () { |
829 .on("click",function () { |
806 if (_this.filter_by_segments && _this.media.getTimeRange()) { |
830 if (_this.filter_by_segments && _this.media.getTimeRange()) { |
807 _ann_time = (_annotation.begin + _annotation.end) / 2; |
831 _ann_time = (_annotation.begin + _annotation.end) / 2; |
808 if ( |
832 if ( |
809 _ann_time <= _this.media.getTimeRange()[0] || |
833 _ann_time <= _this.media.getTimeRange()[0] || |
810 _ann_time >= _this.media.getTimeRange()[1] |
834 _ann_time >= _this.media.getTimeRange()[1] |
813 } |
837 } |
814 } |
838 } |
815 _annotation.trigger("click"); |
839 _annotation.trigger("click"); |
816 }) |
840 }) |
817 .appendTo(_this.list_$); |
841 .appendTo(_this.list_$); |
|
842 |
|
843 |
|
844 let img = thumbnailBuffer[_thumbnail]; |
|
845 if(typeof(img) == "undefined") { |
|
846 img = new Image(); |
|
847 thumbnailBuffer[_thumbnail] = img; |
|
848 } |
|
849 console.log("Thumnailimg", jQuery(`#${_thumbnailId}`,_el).attr('src')); |
|
850 if(img.src && IsImageOk(img)) { |
|
851 jQuery(`#${_thumbnailId}`,_el).attr('src', img.src); |
|
852 } else { |
|
853 img.onload = function() { |
|
854 jQuery(`#${_thumbnailId}`,_el).attr('src', img.src); |
|
855 }; |
|
856 img.onerror = function() { |
|
857 img.src = _this.default_thumbnail; |
|
858 const elthumbnail = jQuery(`#${_thumbnailId}`,_el); |
|
859 elthumbnail.attr('src', _this.default_thumbnail); |
|
860 |
|
861 }; |
|
862 img.src = _thumbnail; |
|
863 } |
818 ns.attachDndData(_el.find("[draggable]"), { |
864 ns.attachDndData(_el.find("[draggable]"), { |
819 title: _title, |
865 title: _title, |
820 description: _description, |
866 description: _description, |
821 uri: _url, |
867 uri: _url, |
822 image: _annotation.thumbnail, |
868 image: _annotation.thumbnail, |
853 // have to specify the ancestor before which we can |
899 // have to specify the ancestor before which we can |
854 // insert the input widget. |
900 // insert the input widget. |
855 if (insertion_point === undefined) insertion_point = _this; |
901 if (insertion_point === undefined) insertion_point = _this; |
856 |
902 |
857 // Insert input element |
903 // Insert input element |
858 var input_element = $( |
904 var input_element = jQuery( |
859 _this.dataset.editable_type === "multiline" |
905 _this.dataset.editable_type === "multiline" |
860 ? "<textarea>" |
906 ? "<textarea>" |
861 : "<input>" |
907 : "<input>" |
862 ) |
908 ) |
863 .addClass("editableInput") |
909 .addClass("editableInput") |
864 .insertBefore($(insertion_point)); |
910 .insertBefore(jQuery(insertion_point)); |
865 input_element[0].value = _this.dataset.editable_value; |
911 input_element[0].value = _this.dataset.editable_value; |
866 $(input_element).show().focus(); |
912 jQuery(input_element).show().focus(); |
867 $(_this).addClass("editing"); |
913 jQuery(_this).addClass("editing"); |
868 |
914 |
869 function feedback(color) { |
915 function feedback(color) { |
870 // Give some feedback |
916 // Give some feedback |
871 $(_this).removeClass("editing"); |
917 jQuery(_this).removeClass("editing"); |
872 input_element.remove(); |
918 input_element.remove(); |
873 var previous_color = $(_this).css("background-color"); |
919 var previous_color = jQuery(_this).css("background-color"); |
874 $(_this) |
920 jQuery(_this) |
875 .stop() |
921 .stop() |
876 .css("background-color", color) |
922 .css("background-color", color) |
877 .animate({ backgroundColor: previous_color }, 1000); |
923 .animate({ backgroundColor: previous_color }, 1000); |
878 } |
924 } |
879 |
925 |
929 widget.player.addLocalAnnotation(an); |
975 widget.player.addLocalAnnotation(an); |
930 widget.player.trigger("Annotation.update", an); |
976 widget.player.trigger("Annotation.update", an); |
931 feedback(feedback_ok); |
977 feedback(feedback_ok); |
932 } |
978 } |
933 } |
979 } |
934 $(input_element) |
980 jQuery(input_element) |
935 .bind("keydown", function (e) { |
981 .bind("keydown", function (e) { |
936 if (e.which == 13) { |
982 if (e.which == 13) { |
937 e.preventDefault(); |
983 e.preventDefault(); |
938 validateChanges(); |
984 validateChanges(); |
939 } else if (e.which == 27) { |
985 } else if (e.which == 27) { |
979 if (widget.on_edit) { |
1025 if (widget.on_edit) { |
980 var _annotation = get_local_annotation(this.dataset.editable_id); |
1026 var _annotation = get_local_annotation(this.dataset.editable_id); |
981 widget.on_edit(_annotation); |
1027 widget.on_edit(_annotation); |
982 } else { |
1028 } else { |
983 // Edit annotation title. We have to specify the insertion point. |
1029 // Edit annotation title. We have to specify the insertion point. |
984 var element = $(this) |
1030 var element = jQuery(this) |
985 .parents(".Ldt-AnnotationsList-li") |
1031 .parents(".Ldt-AnnotationsList-li") |
986 .find(".Ldt-AnnotationsList-TitleContent.Ldt-live-editable"); |
1032 .find(".Ldt-AnnotationsList-TitleContent.Ldt-live-editable"); |
987 edit_element(element[0]); |
1033 edit_element(element[0]); |
988 } |
1034 } |
989 }); |
1035 }); |
1028 url: _url, |
1074 url: _url, |
1029 type: widget.api_method, |
1075 type: widget.api_method, |
1030 contentType: "application/json", |
1076 contentType: "application/json", |
1031 data: _export.serialize(), |
1077 data: _export.serialize(), |
1032 success: function (_data) { |
1078 success: function (_data) { |
1033 $(this).addClass("published"); |
1079 jQuery(this).addClass("published"); |
1034 // Save the published information |
1080 // Save the published information |
1035 var an = get_local_annotation(_annotation.id); |
1081 var an = get_local_annotation(_annotation.id); |
1036 // FIXME: handle "published" tag |
1082 // FIXME: handle "published" tag |
1037 an.setTags(["published"]); |
1083 an.setTags(["published"]); |
1038 save_local_annotations(); |
1084 save_local_annotations(); |