alcatel/static/js/annotation-article.js
author Nicolas Sauret <nicolas.sauret@iri.centrepompidou.fr>
Fri, 18 Apr 2014 14:31:58 +0200
changeset 51 79833eaa394a
parent 44 3648b6dea2cc
permissions -rw-r--r--
set up second level for navigation

$(function() {

    $(".fancybox").fancybox();
    $('.font-up a').click(function(){
        var taille_police=parseFloat($('.content').css('font-size'),100)+2;
        if(taille_police<30){
            var taille_ligne=parseFloat($('.content').css('line-height'),100)+2;
            $('.content').css({
                'line-height':taille_ligne+'px',
                'font-size':taille_police+'px'
            });
        }
        return false;
    });
    $('.font-down a').click(function(){
        var taille_police=parseFloat($('.content').css('font-size'),100)-2;
        if(taille_police>11){
            var taille_ligne=parseFloat($('.content').css('line-height'),100)-2;
            $('.content').css({
                'line-height':taille_ligne+'px',
                'font-size':taille_police+'px'
            });
        }
        return false;
    });
    
    /* ANNOTATION HANDLING */
    
    var basenode = $(".content")[0],
        cleanHtml = cleanTextNodes(basenode).innerHtml,
        textinfo = parseContents(basenode);
        
    window.annotations = window.annotations || [];
    
    var colors = ["#ff8", "#f88", "#8f8", "#8ff", "#f8f", "#88f"],
        currentVisibleFrame = null,
        ncol = 0,
        mousedown = false,
        shownByClick = false,
        dragging = false;
    
    function cleanText(txt, keepbefore, keepafter) {
        var res = txt.replace(/[\n\r\t]+/gm,' ').replace(/ {2,}/g,' ');
        if (!keepbefore) {
            res = res.replace(/^ +/,'');
        }
        if (!keepafter) {
            res = res.replace(/ +$/,'');
        }
        return res;
    }
    
    function recursiveParse(node, info) {
        var children = node.childNodes;
        for (var i = 0, l = children.length; i < l; i++) {
            var childnode = children[i];
            switch(childnode.nodeType) {
                case node.ELEMENT_NODE:
                    recursiveParse(childnode, info);
                break;
                case node.TEXT_NODE:
                    var startpos = info.text.length;
                    info.text += childnode.textContent;
                    var endpos = info.text.length,
                        nodeinfo = {
                            start: startpos,
                            end: endpos,
                            length: endpos - startpos,
                            textNode: childnode
                        };
                    childnode._nodeInfo = nodeinfo;
                    info.nodes.push(nodeinfo);
                break;
            }
        }
    }
    
    
    function parseContents(node) {
        var res = {
            text: '',
            nodes: []
        };
        recursiveParse(node, res);
        return res;
    }
    
    function cleanTextNodes(node) {
        var children = node.childNodes;
        for (var i = 0, l = children.length; i < l; i++) {
            var childnode = children[i];
            switch(childnode.nodeType) {
                case node.ELEMENT_NODE:
                    cleanTextNodes(childnode);
                break;
                case node.TEXT_NODE:
                    var keepbefore = (i && children[i-1].nodeType == node.ELEMENT_NODE),
                        keepafter = (i < l-1 && children[i+1].nodeType == node.ELEMENT_NODE);
                    childnode.textContent = cleanText(childnode.textContent, keepbefore, keepafter);
                break;
            }
        }
        return node;
    }
    
    function highlightText(start, end, color) {
		alert('start'+start);
		alert('end'+end);
		alert('color'+color);

		alert('textinfo.text.substring(start, end)'+textinfo.text.substring(start, end));
		alert('currentDocumentaryFile'+currentDocumentaryFile);
		
		
        var annotation = {
            startOffset: start,
            length: end - start,
            color: color,
            comment: "",
            creator: "cobled",
            tags: [],
            annotatedText: textinfo.text.substring(start, end),
            beforeText: textinfo.text.substring(start - 40, start).replace(/^[\S]*\s+/,''),
            afterText: textinfo.text.substring(end, end + 40).replace(/\s+[\S]*$/,''),
            documentaryFile: currentDocumentaryFile
        }
			alert('highlightText');
        annotations.push(annotation);
			alert('highlightText');
        showAnnotation(annotation, true);
			alert('highlightText');
        updateAnnotationCounts();
			alert('highlightText');
    }
    
    var frameTpl = _.template(
        '<div class="annotation-frame" style="border-color: <%- annotation.color %>; top: <%-top %>px; left: <%- left %>px;">'
        + '<div class="annotation-area" style="background-color: <%- annotation.color %>; height: <%- height %>px;"></div>'
        + '<form class="annotation-form"><h3>Annoté par&nbsp;: <em><%- annotation.creator.name %></em></h3>'
        + '<h3>Dossier documentaire&nbsp;: <em><%- annotation.documentaryFile.name %></em></h3><h3>Commentaire&nbsp;:</h3>'
        + '<% if (editable) { %><textarea class="annotation-textarea" placeholder="Mon commentaire&hellip;"><%- annotation.comment || "" %></textarea>'
        + '<% } else { %><p><%- annotation.comment || "(sans commentaire)" %></p><% } %>'
        + '<h3>Mots-clés&nbsp;:</h3>'
        + '<ul class="<%- editable ? "annotation-tags-form" : "" %>"><% _(annotation.tags).forEach(function(tag) { %><li><%- tag %></li><% }) %></ul>'
        + '<% if (editable) { %><h3><input class="annotation-public" type="checkbox" <% if (annotation.isPublic) {%>checked <% } %>/>Annotation publique</h3><div><a class="annotation-remove" href="#">Supprimer</a><input class="annotation-submit" type="submit" value="Enregistrer" /></div><% } %>'
        + '</form></div>'
    );
    
    var liTpl = _.template(
        '<li style="border-color: <%- annotation.color %>;"><div class="annotation-longview"><h3>Texte annoté&nbsp;:</h3></div>'
        + '<p class="annotation-text"><%- annotation.beforeText %><b><%- annotation.annotatedText %></b><%- annotation.afterText %></p>'
        + '<h3>Annoté par&nbsp;: <em><%- annotation.creator.name %></em></h3>'
        + '<div class="annotation-longview"><h3>Commentaire&nbsp;:</h3><p class="annotation-comment"><%- annotation.comment || "(Sans commentaire)" %></p>'
        + '<h3>Mots-clés&nbsp;:</h3><p class="annotation-tags"><%- (annotation.tags || []).join(", ") || "(aucun mot-clé)" %></p></div>'
        + '</li>'
    );
    
    function showFrameBox() {
        if (currentVisibleFrame) {
            $(".annotation-frame-box").show();
            var offset = currentVisibleFrame.offset(),
                width = currentVisibleFrame.outerWidth(),
                height = currentVisibleFrame.outerHeight();
            $(".annotation-fb-top").css({
                height: offset.top - 77
            });
            $(".annotation-fb-left").css({
                top: offset.top,
                height: height,
                width: offset.left
            });
            $(".annotation-fb-right").css({
                top: offset.top,
                height: height,
                left: offset.left + width
            });
            var fbbtop = offset.top + height;
            $(".annotation-fb-bottom").css({
                top: fbbtop,
                height: ($("body").height() - fbbtop)
            });
            currentVisibleFrame.find(".annotation-textarea").focus();
        } else {
            $(".annotation-frame-box").hide();
        }
    }
    
    function hideAllFrames() {
        if (currentVisibleFrame) {
            currentVisibleFrame.hide();
        }
        
        currentVisibleFrame = null;
        showFrameBox();
        $(".annotation-blocks li").removeClass("selected");
    }
    
    function showAnnotation(annotation, editAfterShow) {
        var start = annotation.startOffset,
            end = annotation.length + start,
            color = annotation.color;
        var spans = [];
        
        for (var i = 0, l = textinfo.nodes.length; i < l; i++) {
            var nodeinfo = textinfo.nodes[i];
            if (nodeinfo.end > start && nodeinfo.start <= end) {
                var r = document.createRange(),
                    s = document.createElement('span'),
                    rangestart = Math.max(0, start - nodeinfo.start),
                    rangeend = Math.min(nodeinfo.length, end - nodeinfo.start);
                s.style.backgroundColor = color;
                r.setStart(nodeinfo.textNode, rangestart);
                r.setEnd(nodeinfo.textNode, rangeend);
                r.surroundContents(s);
                spans.push(s);
            }
        }
        
        textinfo = parseContents(basenode);
        var top = Math.min.apply(Math, spans.map(function(s) { return s.offsetTop })),
            height = Math.max.apply(Math, spans.map(function(s) { return s.offsetHeight + s.offsetTop })) - top,
            frame = $(frameTpl({
                annotation: annotation,
                editable: (currentUser.id === annotation.creator.id),
                top: top,
                height: height,
                left: basenode.offsetLeft
            })),
            li = $(liTpl({
                annotation: annotation
            }));
        
        $(".annotation-frames").append(frame);
        $(annotation.documentaryFile.id === currentDocumentaryFile.id ? ".annotation-file-list" : ".annotation-other-list").append(li);
        
        frame.find(".annotation-textarea").on("keyup paste input change", function() {
            annotation.comment = $(this).val();
            li.find(".annotation-comment").text(annotation.comment || "(Sans commentaire)");
        });
        
        frame.find(".annotation-public").change(function() {
            annotation.isPublic = $(this).is(":checked");
        });
        
        frame.find("")
        
        var ontagchange = function(evt, ui) {
            annotation.tags = $(this).tagit("assignedTags");
            li.find(".annotation-tags").text((annotation.tags || []).join(", ") || "(aucun mot-clé)");
        };
        
        frame.find(".annotation-tags-form").tagit({
            afterTagAdded: ontagchange,
            afterTagRemoved: ontagchange
        });
        
        var show = function() {
            if (mousedown) {
                return;
            }
            shownByClick = false;
            currentVisibleFrame = frame;
            frame.show();
            showFrameBox();
            li.addClass("selected");
        }
                
        $(spans).mouseenter(show);
        
        frame
            .mouseleave(function() {
                if (!shownByClick) {
                    hideAllFrames();
                }
            })
            .click(function() {
                shownByClick = true;
            });
        
        frame.find(".annotation-form").submit(function() {
            hideAllFrames();
            return false;
        });
        
        frame.find(".annotation-remove").click(function() {
            annotations = _(annotations).reject(function(a) {
                return a === annotation
            });
            $(spans).css("background-color","").off("mouseenter",show);
            li.remove();
            frame.remove();
            hideAllFrames();
            updateAnnotationCounts();
            return false;
        });
        
        li
            .mouseenter(function() {
                $(spans).addClass("annotation-selected");
                li.addClass("selected");
                li.find(".annotation-longview").stop().slideDown();
            })
            .mouseleave(function() {
                $(spans).removeClass("annotation-selected");
                li.removeClass("selected");
                li.find(".annotation-longview").stop().slideUp();
            })
            .click(function() {
                show();
                shownByClick = true;
                $(window).scrollTop(currentVisibleFrame.offset().top - 100);
            });
        
        if (editAfterShow) {
            show();
            shownByClick = true;
        }
        
    }
    
    function updateAnnotationCounts() {
        $(".annotation-blocks .block").each(function() {
            var $this = $(this), n = $this.find("li").length;
            $this.find(".annotations-count").text(n || "aucune");
            if (n > 1) {
                $this.find(".annotation-plural").show();
            } else {
                $this.find(".annotation-plural").hide();
            }
        })
    }
    
    annotations.forEach(function(annotation) {
        showAnnotation(annotation);
    });
    updateAnnotationCounts();
    
    var range = null;
        
    $(".content").mouseup(function(e) {
        range = document.getSelection().getRangeAt(0);
        var addann = $(".add-annotation");
        if (!range.collapsed && range.startContainer._nodeInfo && range.endContainer._nodeInfo && range.toString() !== " ") {
            addann.show();
            var doc = $(document), rect = range.getBoundingClientRect();
            addann.css({
                left: doc.scrollLeft() + rect.right + 5,
                top: doc.scrollTop() + (rect.top + rect.bottom - addann.outerHeight()) / 2,
            });
        } else {
            range = null;
            $(".add-annotation").hide();
        }
    }).mousedown(function() {
        $(".add-annotation").hide();
    });
    
    $(".add-annotation").click(function() {
		
        $(".add-annotation").hide();
        if (range) {
			
            var start = range.startOffset + range.startContainer._nodeInfo.start,
                end = range.endOffset + range.endContainer._nodeInfo.start;
				
            highlightText(start, end, colors[ncol++ % colors.length]);
            document.getSelection().removeAllRanges();
        }
    });
            
    $(window).mouseup(function() {
        mousedown = false;
        dragging = false;
    });
    
    $(".annotation-frame-box").click(hideAllFrames);
    
    $(window).resize(function() {
        showFrameBox();
        $(".annotation-frame").css({
            left: basenode.offsetLeft
        })
    });
    
    $(".add-annotation").css({
        left: (basenode.offsetLeft + 500)
    });

});