<commit_before>/* fireSlider (0.1.3). (C) 2014 CJ O'Hara amd Tyler Fowle. MIT @license: en.wikipedia.org/wiki/MIT_License */
!function() {
    fireSlider = function(e, t, i) {
        function n(e, t) {
            ret = [];
            for (var i = 0; i < e.childNodes.length; ++i) "undefined" != typeof e.childNodes[i].tagName && e.childNodes[i].tagName.toLowerCase() === t.toLowerCase() && ret.push(e.childNodes[i]);
            return ret;
        }
        // Add class to node's classList
        function r(e, t) {
            e.classList ? e.classList.add(t) : e.className += " " + t;
        }
        // Remove class from node's classList
        function a(e, t) {
            e.classList ? e.classList.remove(t) : e.className = e.className.replace(new RegExp("(^|\\b)" + t.split(" ").join("|") + "(\\b|$)", "gi"), " ");
        }
        // Returns true if node has className
        function d(e, t) {
            var i = !1;
            return e.classList && e.classList.contains(t) && (i = !0), i;
        }
        function l() {
            N = n(E, t.slide);
        }
        // Duplicates slides based on the multiplier, returns new array
        function o(e, t) {
            var i = j.totalSlides * t - e.length;
            // Add elements if there is a possitive difference
            if (i > 0) for (var n = 0; i > n; n++) {
                var r = e[n % j.totalSlides].cloneNode(!0);
                d(r, "fire-slider-active") && a(r, "fire-slider-active"), E.appendChild(r);
            }
            // Remove elements if there is a negative difference
            if (0 > i) for (var l = e.length - 1; l >= e.length + i; l--) E.removeChild(N[l]);
            return i;
        }
        // Updates show and active based on breakpoints set in options
        function s() {
            if (// Reset show and active
            j.show = t.show, j.active = t.active, "undefined" != typeof i) {
                for (var e = -1, n = -1, r = 0; r < i.length; r++) i[r].breakpoint && i[r].breakpoint >= j.windowWidth && (i[r].breakpoint < n || -1 === n) && (e = r,
                n = i[r].breakpoint);
                -1 !== e && (i[e].show && (j.show = i[e].show), i[e].active && (j.active = i[e].active));
            }
        }
        // Returns the amount of times the slides should be duplicated to fit within the window width
        function c() {
            var e = 1, t = 0;
            // How many additional slides do we need to cover the width of the screen plus 2 more for the next transition
            // Create a multiply based on the number of additional slides needed
            return j.windowWidth = window.innerWidth, j.slideWidth * j.totalSlides < j.windowWidth && (t = Math.ceil((j.windowWidth - j.slideWidth * j.totalSlides) / j.slideWidth)),
            t += 2 * j.totalSlides, t > 0 && (e += Math.ceil(t / j.totalSlides)), e;
        }
        // Position Slides
        function u(e) {
            var i = -100 * Math.ceil(e.length / 2) + 100 * (j.active - 1), n = [], r = [];
            j.minX = i, j.maxX = i + 100 * (e.length - 1);
            for (var a = Math.floor(e.length / 2); a < e.length; a++) M(e[a], {
                translateX: i + "%"
            }, {
                duration: 0,
                queue: t.effect
            }), e[a].style.width = j.slideWidthPercent + "%", e[a].style.position = "absolute",
            r.push(i), i += 100;
            for (a = 0; a < Math.floor(e.length / 2); a++) M(e[a], {
                translateX: i + "%"
            }, {
                duration: 0,
                queue: t.effect
            }), e[a].style.width = j.slideWidthPercent + "%", e[a].style.position = "absolute",
            n.push(i), i += 100;
            k = n.concat(r), window.jQuery ? $(e).dequeue(t.effect) : M.Utilities.dequeue(e, t.effect);
        }
        // Calculates positions for revolution amount
        function f(e, i) {
            for (var n = 0; n < N.length; n++) {
                for (var r = k.shift(), a = r, d = 0; i > d; d++) a -= 100, a < j.minX && (a = j.maxX),
                a > j.maxX && (a = j.minX);
                M(N[n], {
                    translateX: a + "%"
                }, {
                    duration: 0,
                    queue: t.effect
                }), k.push(a);
            }
        }
        // Create and trigger an event
        function p(e, t) {
            var i = {};
            document.createEvent ? (i = document.createEvent("HTMLEvents"), i.initEvent(t, !0, !1)) : (i = document.createEventObject(),
            i.eventType = t), i.eventName = t, document.createEvent ? e.dispatchEvent(i) : e.fireEvent("on" + i.eventType, i);
        }
        // Fills pager with empty spans based on total slides, adds active class to the first slide
        function h() {
            if ("undefined" != typeof j.pager) {
                for (var e = 0; e < j.totalSlides; e++) {
                    var t = document.createElement("span");
                    j.pager.appendChild(t);
                }
                j.pagerSpans = n(j.pager, "span"), r(j.pagerSpans[0], "fire-pager-active");
            }
        }
        // Gets the index of a DOM element relative to it's parent element
        function v(e) {
            for (var t = -1, i = e.parentNode.childNodes, n = 0; n < i.length; n++) e === i[n] && (t = n);
            return t;
        }
        // Starts the timer
        function g() {
            0 !== t.delay && (b = setInterval(q, t.delay));
        }
        // Stops the timer
        function w() {
            0 !== t.delay && clearInterval(b);
        }
        // Set up the inital state of fireSlider
        function S() {
            h(), // Check Breakpoints
            s(), j.slideWidthPercent = 1 / j.show * 100, j.slideWidth = j.sliderWidth / j.show;
            // Caluculate the multiplyer
            var e = c();
            o(N, e), // Set the first active slide
            j.currentSlide = 0, r(N[j.currentSlide], "fire-slider-active"), // position the elements of the array
            l(), u(N), p(E, "fire-slider-init"), g();
        }
        // Refresh positions, breakpoints and slide count
        function m() {
            // Pause transitions
            w(), // Update breakpoints and width settings
            j.windowWidth = window.innerWidth, j.sliderWidth = E.offsetWidth, s(), j.slideWidthPercent = 1 / j.show * 100,
            j.slideWidth = j.sliderWidth / j.show;
            var e = c();
            if (N.length !== e * j.totalSlides) {
                // Remove active class
                a(N[j.currentSlide], "fire-slider-active");
                // Multipy slides and calculate difference
                var i = o(N, e);
                // Fetch new slider
                l(), // Position slides
                u(N), j.currentSlide > N.length && (// Calculate current slide
                j.currentSlide = j.currentSlide % N.length, // Get new positions
                f(E, Math.abs(i)), window.jQuery ? $(N).dequeue(t.effect) : M.Utilities.dequeue(N, t.effect)),
                // Re-add active class
                r(N[j.currentSlide], "fire-slider-active");
            } else u(N), f(E, j.currentSlide), window.jQuery ? $(N).dequeue(t.effect) : M.Utilities.dequeue(N, t.effect);
            // Play Transitions
            g();
        }
        // Basic slide transition effect
        function y(e, i) {
            var n = 0;
            i.multiplier && (n = 100 * i.multiplier), M(e, {
                translateX: i.oldPosition + "%"
            }, {
                duration: 0,
                queue: t.effect
            }), i.snapping ? M(e, {
                translateX: i.newPosition + "%"
            }, {
                duration: 0,
                queue: t.effect
            }) : M(e, {
                translateX: i.newPosition + "%"
            }, {
                duration: t.speed,
                queue: t.effect
            });
        }
        // Routes slide to correct transition
        function X(e, i) {
            switch (t.effect) {
              case "slideInOut":
                y(e, i);
                break;

              default:
                y(e, i);
            }
        }
        // Go to previous slide
        function W() {
            // Stop timer
            w(), // Remove active classes
            a(N[j.currentSlide], "fire-slider-active"), "undefined" != typeof j.pager && a(j.pagerSpans[j.currentSlide % j.totalSlides], "fire-pager-active"),
            j.currentSlide -= 1, j.currentSlide < 0 && (j.currentSlide = N.length - 1);
            // Calculate New Position
            for (var e = 0; e < N.length; e++) {
                var i = k.shift(), n = i + 100, d = !1;
                n < j.minX && (n = j.maxX, d = !0), n > j.maxX && (n = j.minX, d = !0), X(N[e], {
                    oldPosition: i,
                    newPosition: n,
                    snapping: d
                }), k.push(n);
            }
            window.jQuery ? $(N).dequeue(t.effect) : M.Utilities.dequeue(N, t.effect), // Add active classes
            r(N[j.currentSlide], "fire-slider-active"), "undefined" != typeof j.pager && r(j.pagerSpans[j.currentSlide % j.totalSlides], "fire-pager-active"),
            // Trigger event fire-slider-prev
            p(E, "fire-slider-prev"), // Restart timer
            g();
        }
        // Go to next slide
        function q() {
            // Stop timer
            w(), // Remove active classes
            a(N[j.currentSlide], "fire-slider-active"), "undefined" != typeof j.pager && a(j.pagerSpans[j.currentSlide % j.totalSlides], "fire-pager-active"),
            j.currentSlide += 1, j.currentSlide > N.length - 1 && (j.currentSlide = 0);
            // Calculate next position
            for (var e = 0; e < N.length; e++) {
                var i = k.shift(), n = i - 100, d = !1;
                n < j.minX && (n = j.maxX, d = !0), n > j.maxX && (n = j.minX, d = !0), X(N[e], {
                    oldPosition: i,
                    newPosition: n,
                    snapping: d
                }), k.push(n);
            }
            window.jQuery ? $(N).dequeue(t.effect) : M.Utilities.dequeue(N, t.effect), // Add active classes
            r(N[j.currentSlide], "fire-slider-active"), "undefined" != typeof j.pager && r(j.pagerSpans[j.currentSlide % j.totalSlides], "fire-pager-active"),
            // Trigger event fire-slider-prev
            p(E, "fire-slider-prev"), // Restart timer
            g();
        }
        // Go to the slide relative to the index of a pager span
        function P(e) {
            var i = j.currentSlide % j.totalSlides, n = e - i;
            if (0 !== n) {
                // Using the difference, determine where the slides' next position will be and send to transition manager
                if (// Stop Timer
                w(), // Re-load slides
                l(), // Remove active classes
                a(N[j.currentSlide], "fire-slider-active"), a(j.pagerSpans[j.currentSlide % j.totalSlides], "fire-pager-active"),
                0 > n) // Previous Direction
                for (var d = 0; d < N.length; d++) {
                    for (var o = k.shift(), s = o, c = !1, u = 0; u < Math.abs(n); u++) s += 100, s < j.minX && (s = j.maxX,
                    c = !0), s > j.maxX && (s = j.minX, c = !0);
                    X(N[d], {
                        oldPosition: o,
                        newPosition: s,
                        snapping: c
                    }), k.push(s);
                } else // Next Direction
                for (var f = 0; f < N.length; f++) {
                    for (var p = k.shift(), h = p, v = !1, S = 0; S < Math.abs(n); S++) h -= 100, h < j.minX && (h = j.maxX,
                    v = !0), h > j.maxX && (h = j.minX, v = !0);
                    X(N[f], {
                        oldPosition: p,
                        newPosition: h,
                        snapping: v
                    }), k.push(h);
                }
                // Perform transitions
                window.jQuery ? $(N).dequeue(t.effect) : M.Utilities.dequeue(N, t.effect), // Set current slide
                j.currentSlide = (j.currentSlide + n) % N.length, // Add new active classes
                r(N[j.currentSlide], "fire-slider-active"), r(j.pagerSpans[j.currentSlide % j.totalSlides], "fire-pager-active"),
                // Restart timer
                g();
            }
        }
        var L = {
            slide: "li",
            show: 1,
            active: 1,
            speed: 500,
            delay: 5e3,
            effect: "slideInOut",
            hoverPause: !1,
            disableLinks: !0
        };
        // Merge defaults with options
        t = t || {};
        for (var x in L) L.hasOwnProperty(x) && !t.hasOwnProperty(x) && (t[x] = L[x]);
        var E = document.querySelectorAll(e)[0], N = n(E, t.slide), b = {}, k = [], j = {
            show: t.show,
            active: t.active,
            pagerSpans: [],
            totalSlides: N.length,
            windowWidth: window.innerWidth,
            sliderWidth: E.offsetWidth,
            slideWidth: E.offsetWidth / t.show,
            slideWidthPercent: 1 / t.show * 100,
            currentSlide: 0,
            minX: 0,
            maxX: 0
        };
        "undefined" != typeof t.prev && (j.prev = document.querySelectorAll(t.prev)[0]),
        "undefined" != typeof t.next && (j.next = document.querySelectorAll(t.next)[0]),
        "undefined" != typeof t.pager && (j.pager = document.querySelectorAll(t.pager)[0]);
        // Set up V
        var M;
        M = window.jQuery ? $.Velocity : Velocity, S(), // Click events
        "undefined" != typeof j.next && j.next.addEventListener("click", function(e) {
            e.preventDefault(), q();
        }), "undefined" != typeof j.prev && j.prev.addEventListener("click", function(e) {
            e.preventDefault(), W();
        }), "undefined" != typeof j.pager && j.pager.addEventListener("click", function(e) {
            e.preventDefault(), "SPAN" === e.target.tagName && P(v(e.target));
        }), // Pause on hover events
        E.addEventListener("mouseover", function() {
            t.hoverPause && w();
        }), E.addEventListener("mouseout", function() {
            t.hoverPause && g();
        }), // Disable link interaction if slide is not active slide
        t.disableLinks && E.addEventListener("click", function(e) {
            "A" === e.target.tagName && (d(e.target.parentNode, "fire-slider-active") || e.preventDefault());
        }), // Window resize event
        window.addEventListener("resize", function() {
            m();
        });
    };
}(), // Example listeners
document.addEventListener("fire-slider-init", function() {}), document.addEventListener("fire-slider-next", function() {});<commit_msg>updated version number<commit_after>/* fireSlider (0.1.4). (C) 2014 CJ O'Hara amd Tyler Fowle. MIT @license: en.wikipedia.org/wiki/MIT_License */
!function() {
    fireSlider = function(e, t, i) {
        function n(e, t) {
            ret = [];
            for (var i = 0; i < e.childNodes.length; ++i) "undefined" != typeof e.childNodes[i].tagName && e.childNodes[i].tagName.toLowerCase() === t.toLowerCase() && ret.push(e.childNodes[i]);
            return ret;
        }
        // Add class to node's classList
        function r(e, t) {
            e.classList ? e.classList.add(t) : e.className += " " + t;
        }
        // Remove class from node's classList
        function a(e, t) {
            e.classList ? e.classList.remove(t) : e.className = e.className.replace(new RegExp("(^|\\b)" + t.split(" ").join("|") + "(\\b|$)", "gi"), " ");
        }
        // Returns true if node has className
        function d(e, t) {
            var i = !1;
            return e.classList && e.classList.contains(t) && (i = !0), i;
        }
        function l() {
            N = n(E, t.slide);
        }
        // Duplicates slides based on the multiplier, returns new array
        function o(e, t) {
            var i = j.totalSlides * t - e.length;
            // Add elements if there is a possitive difference
            if (i > 0) for (var n = 0; i > n; n++) {
                var r = e[n % j.totalSlides].cloneNode(!0);
                d(r, "fire-slider-active") && a(r, "fire-slider-active"), E.appendChild(r);
            }
            // Remove elements if there is a negative difference
            if (0 > i) for (var l = e.length - 1; l >= e.length + i; l--) E.removeChild(N[l]);
            return i;
        }
        // Updates show and active based on breakpoints set in options
        function s() {
            if (// Reset show and active
            j.show = t.show, j.active = t.active, "undefined" != typeof i) {
                for (var e = -1, n = -1, r = 0; r < i.length; r++) i[r].breakpoint && i[r].breakpoint >= j.windowWidth && (i[r].breakpoint < n || -1 === n) && (e = r,
                n = i[r].breakpoint);
                -1 !== e && (i[e].show && (j.show = i[e].show), i[e].active && (j.active = i[e].active));
            }
        }
        // Returns the amount of times the slides should be duplicated to fit within the window width
        function c() {
            var e = 1, t = 0;
            // How many additional slides do we need to cover the width of the screen plus 2 more for the next transition
            // Create a multiply based on the number of additional slides needed
            return j.windowWidth = window.innerWidth, j.slideWidth * j.totalSlides < j.windowWidth && (t = Math.ceil((j.windowWidth - j.slideWidth * j.totalSlides) / j.slideWidth)),
            t += 2 * j.totalSlides, t > 0 && (e += Math.ceil(t / j.totalSlides)), e;
        }
        // Position Slides
        function u(e) {
            var i = -100 * Math.ceil(e.length / 2) + 100 * (j.active - 1), n = [], r = [];
            j.minX = i, j.maxX = i + 100 * (e.length - 1);
            for (var a = Math.floor(e.length / 2); a < e.length; a++) M(e[a], {
                translateX: i + "%"
            }, {
                duration: 0,
                queue: t.effect
            }), e[a].style.width = j.slideWidthPercent + "%", e[a].style.position = "absolute",
            r.push(i), i += 100;
            for (a = 0; a < Math.floor(e.length / 2); a++) M(e[a], {
                translateX: i + "%"
            }, {
                duration: 0,
                queue: t.effect
            }), e[a].style.width = j.slideWidthPercent + "%", e[a].style.position = "absolute",
            n.push(i), i += 100;
            k = n.concat(r), window.jQuery ? $(e).dequeue(t.effect) : M.Utilities.dequeue(e, t.effect);
        }
        // Calculates positions for revolution amount
        function f(e, i) {
            for (var n = 0; n < N.length; n++) {
                for (var r = k.shift(), a = r, d = 0; i > d; d++) a -= 100, a < j.minX && (a = j.maxX),
                a > j.maxX && (a = j.minX);
                M(N[n], {
                    translateX: a + "%"
                }, {
                    duration: 0,
                    queue: t.effect
                }), k.push(a);
            }
        }
        // Create and trigger an event
        function p(e, t) {
            var i = {};
            document.createEvent ? (i = document.createEvent("HTMLEvents"), i.initEvent(t, !0, !1)) : (i = document.createEventObject(),
            i.eventType = t), i.eventName = t, document.createEvent ? e.dispatchEvent(i) : e.fireEvent("on" + i.eventType, i);
        }
        // Fills pager with empty spans based on total slides, adds active class to the first slide
        function h() {
            if ("undefined" != typeof j.pager) {
                for (var e = 0; e < j.totalSlides; e++) {
                    var t = document.createElement("span");
                    j.pager.appendChild(t);
                }
                j.pagerSpans = n(j.pager, "span"), r(j.pagerSpans[0], "fire-pager-active");
            }
        }
        // Gets the index of a DOM element relative to it's parent element
        function v(e) {
            for (var t = -1, i = e.parentNode.childNodes, n = 0; n < i.length; n++) e === i[n] && (t = n);
            return t;
        }
        // Starts the timer
        function g() {
            0 !== t.delay && (b = setInterval(q, t.delay));
        }
        // Stops the timer
        function w() {
            0 !== t.delay && clearInterval(b);
        }
        // Set up the inital state of fireSlider
        function S() {
            h(), // Check Breakpoints
            s(), j.slideWidthPercent = 1 / j.show * 100, j.slideWidth = j.sliderWidth / j.show;
            // Caluculate the multiplyer
            var e = c();
            o(N, e), // Set the first active slide
            j.currentSlide = 0, r(N[j.currentSlide], "fire-slider-active"), // position the elements of the array
            l(), u(N), p(E, "fire-slider-init"), g();
        }
        // Refresh positions, breakpoints and slide count
        function m() {
            // Pause transitions
            w(), // Update breakpoints and width settings
            j.windowWidth = window.innerWidth, j.sliderWidth = E.offsetWidth, s(), j.slideWidthPercent = 1 / j.show * 100,
            j.slideWidth = j.sliderWidth / j.show;
            var e = c();
            if (N.length !== e * j.totalSlides) {
                // Remove active class
                a(N[j.currentSlide], "fire-slider-active");
                // Multipy slides and calculate difference
                var i = o(N, e);
                // Fetch new slider
                l(), // Position slides
                u(N), j.currentSlide > N.length && (// Calculate current slide
                j.currentSlide = j.currentSlide % N.length, // Get new positions
                f(E, Math.abs(i)), window.jQuery ? $(N).dequeue(t.effect) : M.Utilities.dequeue(N, t.effect)),
                // Re-add active class
                r(N[j.currentSlide], "fire-slider-active");
            } else u(N), f(E, j.currentSlide), window.jQuery ? $(N).dequeue(t.effect) : M.Utilities.dequeue(N, t.effect);
            // Play Transitions
            g();
        }
        // Basic slide transition effect
        function y(e, i) {
            var n = 0;
            i.multiplier && (n = 100 * i.multiplier), M(e, {
                translateX: i.oldPosition + "%"
            }, {
                duration: 0,
                queue: t.effect
            }), i.snapping ? M(e, {
                translateX: i.newPosition + "%"
            }, {
                duration: 0,
                queue: t.effect
            }) : M(e, {
                translateX: i.newPosition + "%"
            }, {
                duration: t.speed,
                queue: t.effect
            });
        }
        // Routes slide to correct transition
        function X(e, i) {
            switch (t.effect) {
              case "slideInOut":
                y(e, i);
                break;

              default:
                y(e, i);
            }
        }
        // Go to previous slide
        function W() {
            // Stop timer
            w(), // Remove active classes
            a(N[j.currentSlide], "fire-slider-active"), "undefined" != typeof j.pager && a(j.pagerSpans[j.currentSlide % j.totalSlides], "fire-pager-active"),
            j.currentSlide -= 1, j.currentSlide < 0 && (j.currentSlide = N.length - 1);
            // Calculate New Position
            for (var e = 0; e < N.length; e++) {
                var i = k.shift(), n = i + 100, d = !1;
                n < j.minX && (n = j.maxX, d = !0), n > j.maxX && (n = j.minX, d = !0), X(N[e], {
                    oldPosition: i,
                    newPosition: n,
                    snapping: d
                }), k.push(n);
            }
            window.jQuery ? $(N).dequeue(t.effect) : M.Utilities.dequeue(N, t.effect), // Add active classes
            r(N[j.currentSlide], "fire-slider-active"), "undefined" != typeof j.pager && r(j.pagerSpans[j.currentSlide % j.totalSlides], "fire-pager-active"),
            // Trigger event fire-slider-prev
            p(E, "fire-slider-prev"), // Restart timer
            g();
        }
        // Go to next slide
        function q() {
            // Stop timer
            w(), // Remove active classes
            a(N[j.currentSlide], "fire-slider-active"), "undefined" != typeof j.pager && a(j.pagerSpans[j.currentSlide % j.totalSlides], "fire-pager-active"),
            j.currentSlide += 1, j.currentSlide > N.length - 1 && (j.currentSlide = 0);
            // Calculate next position
            for (var e = 0; e < N.length; e++) {
                var i = k.shift(), n = i - 100, d = !1;
                n < j.minX && (n = j.maxX, d = !0), n > j.maxX && (n = j.minX, d = !0), X(N[e], {
                    oldPosition: i,
                    newPosition: n,
                    snapping: d
                }), k.push(n);
            }
            window.jQuery ? $(N).dequeue(t.effect) : M.Utilities.dequeue(N, t.effect), // Add active classes
            r(N[j.currentSlide], "fire-slider-active"), "undefined" != typeof j.pager && r(j.pagerSpans[j.currentSlide % j.totalSlides], "fire-pager-active"),
            // Trigger event fire-slider-prev
            p(E, "fire-slider-prev"), // Restart timer
            g();
        }
        // Go to the slide relative to the index of a pager span
        function P(e) {
            var i = j.currentSlide % j.totalSlides, n = e - i;
            if (0 !== n) {
                // Using the difference, determine where the slides' next position will be and send to transition manager
                if (// Stop Timer
                w(), // Re-load slides
                l(), // Remove active classes
                a(N[j.currentSlide], "fire-slider-active"), a(j.pagerSpans[j.currentSlide % j.totalSlides], "fire-pager-active"),
                0 > n) // Previous Direction
                for (var d = 0; d < N.length; d++) {
                    for (var o = k.shift(), s = o, c = !1, u = 0; u < Math.abs(n); u++) s += 100, s < j.minX && (s = j.maxX,
                    c = !0), s > j.maxX && (s = j.minX, c = !0);
                    X(N[d], {
                        oldPosition: o,
                        newPosition: s,
                        snapping: c
                    }), k.push(s);
                } else // Next Direction
                for (var f = 0; f < N.length; f++) {
                    for (var p = k.shift(), h = p, v = !1, S = 0; S < Math.abs(n); S++) h -= 100, h < j.minX && (h = j.maxX,
                    v = !0), h > j.maxX && (h = j.minX, v = !0);
                    X(N[f], {
                        oldPosition: p,
                        newPosition: h,
                        snapping: v
                    }), k.push(h);
                }
                // Perform transitions
                window.jQuery ? $(N).dequeue(t.effect) : M.Utilities.dequeue(N, t.effect), // Set current slide
                j.currentSlide = (j.currentSlide + n) % N.length, // Add new active classes
                r(N[j.currentSlide], "fire-slider-active"), r(j.pagerSpans[j.currentSlide % j.totalSlides], "fire-pager-active"),
                // Restart timer
                g();
            }
        }
        var L = {
            slide: "li",
            show: 1,
            active: 1,
            speed: 500,
            delay: 5e3,
            effect: "slideInOut",
            hoverPause: !1,
            disableLinks: !0
        };
        // Merge defaults with options
        t = t || {};
        for (var x in L) L.hasOwnProperty(x) && !t.hasOwnProperty(x) && (t[x] = L[x]);
        var E = document.querySelectorAll(e)[0], N = n(E, t.slide), b = {}, k = [], j = {
            show: t.show,
            active: t.active,
            pagerSpans: [],
            totalSlides: N.length,
            windowWidth: window.innerWidth,
            sliderWidth: E.offsetWidth,
            slideWidth: E.offsetWidth / t.show,
            slideWidthPercent: 1 / t.show * 100,
            currentSlide: 0,
            minX: 0,
            maxX: 0
        };
        "undefined" != typeof t.prev && (j.prev = document.querySelectorAll(t.prev)[0]),
        "undefined" != typeof t.next && (j.next = document.querySelectorAll(t.next)[0]),
        "undefined" != typeof t.pager && (j.pager = document.querySelectorAll(t.pager)[0]);
        // Set up V
        var M;
        M = window.jQuery ? $.Velocity : Velocity, S(), // Click events
        "undefined" != typeof j.next && j.next.addEventListener("click", function(e) {
            e.preventDefault(), q();
        }), "undefined" != typeof j.prev && j.prev.addEventListener("click", function(e) {
            e.preventDefault(), W();
        }), "undefined" != typeof j.pager && j.pager.addEventListener("click", function(e) {
            e.preventDefault(), "SPAN" === e.target.tagName && P(v(e.target));
        }), // Pause on hover events
        E.addEventListener("mouseover", function() {
            t.hoverPause && w();
        }), E.addEventListener("mouseout", function() {
            t.hoverPause && g();
        }), // Disable link interaction if slide is not active slide
        t.disableLinks && E.addEventListener("click", function(e) {
            "A" === e.target.tagName && (d(e.target.parentNode, "fire-slider-active") || e.preventDefault());
        }), // Window resize event
        window.addEventListener("resize", function() {
            m();
        });
    };
}(), // Example listeners
document.addEventListener("fire-slider-init", function() {}), document.addEventListener("fire-slider-next", function() {});<|endoftext|>


<commit_before>{
	"translatorID": "a515a220-6fef-0111-1974-8025dfebbb8f",
	"label": "@Item URI with note (TiddlyWiki)",
	"creator": "Dariusz Bobak",
	"target": "txt",
	"minVersion": "4.0.27",
	"translatorType": 2,
	"browserSupport": "gcsv",
	"priority": 100,
	"displayOptions": {
		"quickCopyMode": ""
	},
	"inRepository": false,
	"lastUpdated": "2020-08-30 21:03:52"
}

function doExport() {
	var item;
	while(item = Zotero.nextItem()) {
		const date = Zotero.BetterBibTeX.parseDate(item.date);
		Zotero.write("<<fnote '");
		if (item.creators[2]) {
			Zotero.write(item.creators[0].lastName + ", " + item.creators[1].lastName + " et al., ");
			}
		else if (item.creators[1]) {
			Zotero.write(item.creators[0].lastName + " and " + item.creators[1].lastName + ", ");
			}
		else {
			Zotero.write(item.creators[0].lastName + ", ");
			}
		Zotero.write(date.year + ", " + item["title"] + " [[zotero|");
		Zotero.write(item.uri + "]] [ext[local|");
		Zotero.write("zotero://select/items/");
		var library_id = item.libraryID ? item.libraryID : 0;
		Zotero.write(library_id + "_" + item.key + "]]'>>");
	}
}
<commit_msg>Update @item_uri_with_note.js<commit_after>{
	"translatorID": "a515a220-6fef-0111-1974-8025dfebbb8f",
	"label": "@Item URI with note",
	"creator": "Emiliano Heyns, Dariusz Bobak",
	"target": "txt",
	"minVersion": "4.0.27",
	"translatorType": 2,
	"browserSupport": "gcsv",
	"priority": 100,
	"displayOptions": {
		"quickCopyMode": ""
	},
	"inRepository": false,
	"lastUpdated": "2020-08-30 21:03:52"
}

function doExport() {
	var item;
	while(item = Zotero.nextItem()) {
		const date = Zotero.BetterBibTeX.parseDate(item.date);
		Zotero.write("(");
		if (item.creators[2]) {
			Zotero.write(item.creators[0].lastName + ", " + item.creators[1].lastName + " et al., ");
			}
		else if (item.creators[1]) {
			Zotero.write(item.creators[0].lastName + " and " + item.creators[1].lastName + ", ");
			}
		else {
			Zotero.write(item.creators[0].lastName + ", ");
			}
		Zotero.write(date.year + ")");
		Zotero.write(" <<fnote '");
		if (item.creators[2]) {
			Zotero.write(item.creators[0].lastName + ", " + item.creators[1].lastName + " et al., ");
			}
		else if (item.creators[1]) {
			Zotero.write(item.creators[0].lastName + " and " + item.creators[1].lastName + ", ");
			}
		else {
			Zotero.write(item.creators[0].lastName + ", ");
			}
		Zotero.write(date.year + ", " + item["title"] + ". [[zotero|");
		Zotero.write(item.uri + "]] [ext[local|");
		Zotero.write("zotero://select/items/");
		var library_id = item.libraryID ? item.libraryID : 0;
		Zotero.write(library_id + "_" + item.key + "]]'>>");
	}
}
<|endoftext|>


<commit_before>/** ---------------------------------------------------------------------------
 *  SonosJS
 *  Copyright 2014 Dennis Alund
 *  http://github.com/oddbit/sonosjs
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * ------------------------------------------------------------------------- */

define(function (require) {
        "use strict";

        var net = require("net");
        var getPositionInfoXml = require("text!soap/templates/getPositionInfo.xml");
        var playXml = require("text!soap/templates/play.xml");
        var pauseXml = require("text!soap/templates/pause.xml");
        var nextTrackXml = require("text!soap/templates/nextTrack.xml");
        var seekXml = require("text!soap/templates/seek.xml");
        var setVolumeXml = require("text!soap/templates/setVolume.xml");
        var setMuteXml = require("text!soap/templates/setMute.xml");
        var setPlayModeXml = require("text!soap/templates/setPlayMode.xml");

        function mediaBase(opts) {
            opts = opts || {};
            var that = net.http.request(opts);

            that.serviceUri = "/MediaRenderer/AVTransport/Control";

            return that;
        }

        /**
         * This SOAP request will return the current media state from a device. The type of the returned information
         * depends on the type of media that is being played. For closer inspection of the returned data see
         * @see models.media.info
         *
         *   - What is currently playing
         *   - Length of current song
         *   - Current time into the song
         *   - Track number
         *   - Meta data (url to album art etc)
         *
         * @param {object}    opts          Object initialization options (@see net.http.request)
         * @returns {object}  Position info SOAP request
         */
        function positionInfo(opts) {
            var that = mediaBase(opts);

            that.headers.setHeaderValue("SOAPACTION", "urn:schemas-upnp-org:service:AVTransport:1#GetPositionInfo");
            that.body = getPositionInfoXml;

            return that;
        }

        /**
         * This SOAP request will request a device to start playing whatever is currently paused. The action will fail
         * in case there aren't any song "currently playing" on the device.
         *
         * @param {object}    opts          Object initialization options (@see net.http.request)
         * @returns {object}  Play music SOAP request
         */
        function play(opts) {
            var that = mediaBase(opts);

            that.headers.setHeaderValue("SOAPACTION", "urn:schemas-upnp-org:service:AVTransport:1#Play");
            that.body = playXml;

            return that;
        }

        /**
         * This SOAP request will request a device to pause the playback of whatever is currently playing.
         *
         * @param {object}    opts          Object initialization options (@see net.http.request)
         * @returns {object}  Play music SOAP request
         */
        function pause(opts) {
            var that = mediaBase(opts);

            that.headers.setHeaderValue("SOAPACTION", "urn:schemas-upnp-org:service:AVTransport:1#Pause");
            that.body = pauseXml;

            return that;
        }

        /**
         * This SOAP request will request a device to skip one track forward.
         *
         * @param {object}    opts          Object initialization options (@see net.http.request)
         * @returns {object}  Play music SOAP request
         */
        function nextTrack(opts) {
            var that = mediaBase(opts);

            that.headers.setHeaderValue("SOAPACTION", "urn:schemas-upnp-org:service:AVTransport:1#Next");
            that.body = nextTrackXml;

            return that;
        }

        /**
         * This SOAP request will set a media stream to start at a certain offset
         *
         * @param {object}    opts          Object initialization options (@see net.http.request)
         * @returns {object}  Play music SOAP request
         */
        function seek(opts) {
            var that = mediaBase(opts);

            that.headers.setHeaderValue("SOAPACTION", "urn:schemas-upnp-org:service:AVTransport:1#Seek");
            that.body = seekXml;

            that.setSeconds = function (seekSeconds) {
                seekSeconds = seekSeconds || 0;
                var hours = Math.floor(seekSeconds / 3600);
                var minutes = Math.floor((seekSeconds % 3600) / 60);
                var seconds = seekSeconds % 60;
                that.body = that.body.replace(/\d+:\d+:\d+/, [hours, minutes, seconds].join(":"));
            };

            return that;
        }

        /**
         * This SOAP request will set the volume on a device
         *
         * @param {object}    opts          Object initialization options (@see net.http.request)
         * @returns {object}  Play music SOAP request
         */
        function setVolume(opts) {
            var that = mediaBase(opts);

            that.headers.setHeaderValue("SOAPACTION", "urn:schemas-upnp-org:service:AVTransport:1#SetVolume");
            that.body = setVolumeXml;

            that.setDesiredVolume = function (volume) {
                that.body = that.body.replace(/<DesiredVolume>\s*\d+\s*<\/DesiredVolume>/,
                        "<DesiredVolume>" + volume + "</DesiredVolume>");
            };

            return that;
        }

        /**
         * This SOAP request will mute or unmute the volume on a device
         *
         * @param {object}    opts          Object initialization options (@see net.http.request)
         * @returns {object}  Play music SOAP request
         */
        function setMute(opts) {
            var that = mediaBase(opts);

            that.headers.setHeaderValue("SOAPACTION", "urn:schemas-upnp-org:service:AVTransport:1#SetMute");
            that.body = setMuteXml;

            that.setDesiredMute = function (isMuted) {
                var muteFlag = isMuted === true ? 1 : 0;
                that.body = that.body.replace(/<DesiredMute>\s*\d+\s*<\/DesiredMute>/,
                        "<DesiredMute>" + muteFlag + "</DesiredMute>");
            };

            return that;
        }

        /**
         * This SOAP request will set play mode such as repeat, shuffle, etc of a device
         *
         * @param {object}    opts          Object initialization options (@see net.http.request)
         * @returns {object}  Play music SOAP request
         */
        function setPlayMode(opts) {
            var that = mediaBase(opts);

            that.headers.setHeaderValue("SOAPACTION", "urn:schemas-upnp-org:service:AVTransport:1#SetPlayMode");
            that.body = setPlayModeXml;

            that.setNewPlayMode = function (playMode) {
                that.body = that.body.replace(/<NewPlayMode>\s*\w+\s*<\/NewPlayMode>/,
                        "<NewPlayMode>" + playMode + "</NewPlayMode>");
            };

            return that;
        }

        return {
            play: play,
            pause: pause,
            nextTrack: nextTrack,
            seek: seek,
            setVolume: setVolume,
            setMute: setMute,
            setPlayMode: setPlayMode,
            positionInfo: positionInfo
        };
    }
);
<commit_msg>Updating the SOAP media object collection<commit_after>/** ---------------------------------------------------------------------------
 *  SonosJS
 *  Copyright 2014 Dennis Alund
 *  http://github.com/oddbit/sonosjs
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * ------------------------------------------------------------------------- */

define(function (require) {
        "use strict";

        var net = require("net");
        var models = require("models");
        var getPositionInfoXml = require("text!soap/templates/getPositionInfo.xml");
        var playXml = require("text!soap/templates/play.xml");
        var pauseXml = require("text!soap/templates/pause.xml");
        var nextTrackXml = require("text!soap/templates/nextTrack.xml");
        var seekXml = require("text!soap/templates/seek.xml");
        var setVolumeXml = require("text!soap/templates/setVolume.xml");
        var setMuteXml = require("text!soap/templates/setMute.xml");
        var setPlayModeXml = require("text!soap/templates/setPlayMode.xml");

        function mediaBase(opts) {
            opts = opts || {};
            var that = net.http.request(opts);

            that.serviceUri = "/MediaRenderer/AVTransport/Control";

            return that;
        }

        /**
         * This SOAP request will return the current media state from a device. The type of the returned information
         * depends on the type of media that is being played. For closer inspection of the returned data see
         * @see models.media.info
         *
         *   - What is currently playing
         *   - Length of current song
         *   - Current time into the song
         *   - Track number
         *   - Meta data (url to album art etc)
         *
         * @param {object}    opts          Object initialization options (@see net.http.request)
         * @returns {object}  Position info SOAP request
         */
        function positionInfo(opts) {
            var that = mediaBase(opts);

            that.headers.setHeaderValue("SOAPACTION", "urn:schemas-upnp-org:service:AVTransport:1#GetPositionInfo");
            that.body = getPositionInfoXml;

            return that;
        }

        /**
         * This SOAP request will request a device to start playing whatever is currently paused. The action will fail
         * in case there aren't any song "currently playing" on the device.
         *
         * @param {object}    opts          Object initialization options (@see net.http.request)
         * @returns {object}  Play music SOAP request
         */
        function play(opts) {
            var that = mediaBase(opts);

            that.headers.setHeaderValue("SOAPACTION", "urn:schemas-upnp-org:service:AVTransport:1#Play");
            that.body = playXml;

            return that;
        }

        /**
         * This SOAP request will request a device to pause the playback of whatever is currently playing.
         *
         * @param {object}    opts          Object initialization options (@see net.http.request)
         * @returns {object}  Play music SOAP request
         */
        function pause(opts) {
            var that = mediaBase(opts);

            that.headers.setHeaderValue("SOAPACTION", "urn:schemas-upnp-org:service:AVTransport:1#Pause");
            that.body = pauseXml;

            return that;
        }

        /**
         * This SOAP request will request a device to skip one track forward.
         *
         * @param {object}    opts          Object initialization options (@see net.http.request)
         * @returns {object}  Play music SOAP request
         */
        function nextTrack(opts) {
            var that = mediaBase(opts);

            that.headers.setHeaderValue("SOAPACTION", "urn:schemas-upnp-org:service:AVTransport:1#Next");
            that.body = nextTrackXml;

            return that;
        }

        /**
         * This SOAP request will set a media stream to start at a certain offset
         *
         * @param {object}    opts          Object initialization options (@see net.http.request)
         * @returns {object}  Play music SOAP request
         */
        function seek(opts) {
            var that = mediaBase(opts);

            that.headers.setHeaderValue("SOAPACTION", "urn:schemas-upnp-org:service:AVTransport:1#Seek");
            that.body = seekXml;

            /**
             * Set playback offset into the music stream in seconds.
             *
             * @param {number}  seekSeconds     A number between 0 and the length of the stream
             */
            that.setSeconds = function (seekSeconds) {
                seekSeconds = Number(seekSeconds) || 0;
                var hours = Math.floor(seekSeconds / 3600);
                var minutes = Math.floor((seekSeconds % 3600) / 60);
                var seconds = seekSeconds % 60;
                that.body = that.body.replace(/\d+:\d+:\d+/, [hours, minutes, seconds].join(":"));
            };

            return that;
        }

        /**
         * This SOAP request will set the volume on a device
         *
         * @param {object}    opts          Object initialization options (@see net.http.request)
         * @returns {object}  Play music SOAP request
         */
        function setVolume(opts) {
            var that = mediaBase(opts);

            that.headers.setHeaderValue("SOAPACTION", "urn:schemas-upnp-org:service:AVTransport:1#SetVolume");
            that.body = setVolumeXml;

            /**
             * Set level of volume on the device.
             * @param {number}  volume  A number between 0..100
             */
            that.setDesiredVolume = function (volume) {
                volume = Number(volume) || 0;
                if (volume < 0) {
                    volume = 0;
                }
                else if (volume > 100) {
                    volume = 100;
                }

                that.body = that.body.replace(/<DesiredVolume>\s*\d+\s*<\/DesiredVolume>/,
                        "<DesiredVolume>" + volume + "</DesiredVolume>");
            };

            return that;
        }

        /**
         * This SOAP request will mute or unmute the volume on a device
         *
         * @param {object}    opts          Object initialization options (@see net.http.request)
         * @returns {object}  Play music SOAP request
         */
        function setMute(opts) {
            var that = mediaBase(opts);

            that.headers.setHeaderValue("SOAPACTION", "urn:schemas-upnp-org:service:AVTransport:1#SetMute");
            that.body = setMuteXml;

            /**
             * Set mute flag on or off.
             *
             * @param {boolean} isMuted     True if the device should be muted
             */
            that.setDesiredMute = function (isMuted) {
                var muteFlag = isMuted === true ? 1 : 0;
                that.body = that.body.replace(/<DesiredMute>\s*\d+\s*<\/DesiredMute>/,
                        "<DesiredMute>" + muteFlag + "</DesiredMute>");
            };

            return that;
        }

        /**
         * This SOAP request will set play mode such as repeat, shuffle, etc of a device
         *
         * @param {object}    opts          Object initialization options (@see net.http.request)
         * @returns {object}  Play music SOAP request
         */
        function setPlayMode(opts) {
            var that = mediaBase(opts);

            that.headers.setHeaderValue("SOAPACTION", "urn:schemas-upnp-org:service:AVTransport:1#SetPlayMode");
            that.body = setPlayModeXml;

            /**
             * Sets the play mode in the SOAP body
             *
             * @param {PlayMode}    playMode
             * @param {RepeatMode}  repeatMode
             */
            that.setNewPlayMode = function (playMode, repeatMode) {
                var playModeString;
                if (playMode === models.state.playMode.ORDERED &&
                    repeatMode === models.state.repeatMode.ALL) {
                    playModeString = "REPEAT_ALL";
                }
                else if (playMode === models.state.playMode.SHUFFLE &&
                    repeatMode === models.state.repeatMode.ALL) {
                    playModeString = "SHUFFLE";
                }
                else if (playMode === models.state.playMode.SHUFFLE &&
                    repeatMode === models.state.repeatMode.OFF) {
                    playModeString = "SHUFFLE_NOREPEAT";
                }
                else {
                    playModeString = "NORMAL";
                }

                that.body = that.body.replace(/<NewPlayMode>\s*\w+\s*<\/NewPlayMode>/,
                        "<NewPlayMode>" + playModeString + "</NewPlayMode>");
            };

            return that;
        }

        return {
            play: play,
            pause: pause,
            nextTrack: nextTrack,
            seek: seek,
            setVolume: setVolume,
            setMute: setMute,
            setPlayMode: setPlayMode,
            positionInfo: positionInfo
        };
    }
);
<|endoftext|>


<commit_before>/* Copyright Théo Zimmermann 2014
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

define(["app/dom", "app/i18n", "app/utils", "he", "diff_match_patch"], function($, i18n, utils, he) {

    "use strict";

    // ATTRIBUTES

    // mode can take values "reading", "reading_modification" and "commenting"
    var mode = "reading";
    // if mode is "reading_modification", currently_showing stores id of comment
    var currently_showing;

    // there must be only one
 on the page
    var article = $("article");
    // but there can be many blocks in an article
    var blocks = $(".block", article, false);
    // in the case there is no block, current_block will always represent the full article
    var current_block = article;

    // we will also save the comment html elements and their associated block
    var comments = [];

    var original_content, new_content;

    // button to show the original version
    var original_button;
    var create_original_button = function() {
        if (typeof original_button === "undefined") {
            original_button = $.htmlify(
                '<button type="button">' +
                i18n.translate("show-original") +
                '</button>'
            );
            original_button.on("click", show_original);
            original_button.style.visibility = "hidden";
        }
        return original_button;
    };

    // remember some of the DOM elements
    var cancel_button, comment_field;

    // the block slider is used to choose which block is currently selected
    var current_position;
    (function() {
        // having a slider makes no sense with no blocks
        if (blocks === null) { return null; }

        var slider = $.htmlify('

');
        // slider position
        slider.style.left =
            ((article.getBoundingClientRect().right
              + $("#isso-thread").getBoundingClientRect().left) / 2
             - 10) + "px";
        article.insertAfter(slider);

        var cursor = $.htmlify('

');
        slider.append(cursor);
        // cursor position
        var set_cursor_position = function(y) {
            var slider_rect = slider.getBoundingClientRect();
            var slider_height = slider_rect.bottom - slider_rect.top;
            var raw_position = y - slider_rect.top - 10;
            var corrected_position =
                (raw_position < 0) ?
                0 : ((raw_position > slider_height - 20) ?
                     slider_height - 20 : raw_position);
            cursor.style.top = corrected_position + "px";
            // current_position is useful to determine the current block
            current_position = y + slider_rect.top + 10;
        };

        var first_block = blocks[0].getBoundingClientRect();
        setTimeout(function() {
            set_cursor_position((first_block.top + first_block.bottom) / 2);
        }, 0);

        // define events on slider
        var follow_mouse = function(e) {
            set_cursor_position(e.clientY);
        };
        cursor.addEventListener("mousedown", function(e) {
            document.addEventListener("mousemove", follow_mouse);
            e.preventDefault();
        });
        document.addEventListener("mouseup", function() {
            document.removeEventListener("mousemove", follow_mouse);
            show_block_comments();
        });
    })();

    // INITIALIZE LIBRARIES

    // make a diff_match_patch object once and for all
    var dmp = new diff_match_patch();

    // CKEDITOR is not required thus we must check if it is available
    if (typeof CKEDITOR !== "undefined") {
        // turn off automatic editor creation once and for all
        CKEDITOR.disableAutoInline = true;
    }
    var editor;

    // AUXILIARY FUNCTIONS

    var highlight_current_block = function() {
        for (var i = 0; i < blocks.length; i++) {
            blocks[i].style.background = "transparent";
        }
        current_block.style.background = "rgba(211,211,211,0.5)";
    };

    // content after CKEditor reformatting
    // after decoding html entities
    // and after removing extra whitespace and new lines
    var getEditorContent = function() {
        return utils.clean_html(editor.getData());
    };

    var getBlockContent = function() {
        return utils.clean_html(current_block.innerHTML);
    }

    // FUNCTIONS WHICH ENABLE COMMENTING AND EDITING

    var init = function(comment_postbox) {
        comment_field = $(".textarea", comment_postbox);
        // let's curry!
        return function() {
            show_original();
            if (mode === "reading" && comment_field.innerHTML !== "") {
                mode = "commenting";
                original_content = getBlockContent();
                new_content = null;
                current_block.setAttribute("contenteditable", true);
                if (typeof CKEDITOR !== "undefined") {
                    editor = CKEDITOR.inline(current_block);
                    editor.on("instanceReady", function() {
                        editor.dataProcessor.writer.setRules("p", {
                            ident: false,
                            breakBeforeOpen: false,
                            breakAfterOpen: false,
                            breakBeforeClose: false,
                            breakAfterClose: false
                        });
                        original_content = getEditorContent();
                    });
                    editor.on("change", maybe_article_just_changed);
                }
                // first time : create cancel button and associate event
                if (!cancel_button) {
                    cancel_button = $(".post-action", comment_postbox).prepend(
                      '<input type="reset" value="' + i18n.translate("postbox-cancel") + '"></input>');
                    cancel_button.on("click", function(e) {
                        if (new_content === null ||
                            confirm(i18n.translate("postbox-confirm-cancel"))) {
                            comment_field.innerHTML = "";
                            cancel();
                        }
                    });
                }
                else {
                  cancel_button.style.display = "inline";
                }
            }
            else if (mode === "commenting" && comment_field.innerHTML === ""
                                           && new_content === null) {
                cancel();
            }
        };
    };

    var maybe_article_just_changed = function() {
        var current = typeof CKEDITOR === "undefined" ?
                        getBlockContent() :
                        getEditorContent();
        if (current !== original_content) {
            new_content = current;
        }
        else {
            new_content = null;
            if (comment_field.innerHTML === i18n.translate("postbox-text") ||
                comment_field.innerHTML === "") {
                current_block.blur();
                cancel();
            }
        }
    };

    var cancel = function() {
        if (mode === "commenting") {
            if (typeof editor !== "undefined") {
                editor.destroy();
            }
            current_block.setAttribute("contenteditable", false);
            if (new_content !== null) {
                current_block.innerHTML = original_content;
                new_content = null;
            }
            cancel_button.hide();
            mode = "reading";
        }
    };

    // FUNCTIONS TO SHOW COMMENTS / EDITS

    var save_comment = function(el, block_id) {
        comments.push({el: el, block: block_id});
    };

    var show_block_comments = function() {
        // when showing an edit or commenting, the current block is locked
        // this function is useless if there are no blocks
        if (mode == "reading" && blocks !== null) {
            // current block = block at current_position
            var i = 0;
            while (i < blocks.length &&
                   blocks[i].getBoundingClientRect().top <= current_position) {
                i++;
            }
            current_block = blocks[i - 1];
            highlight_current_block();
            // mask all comments that are not associated with the current block
            for (var i = 0 ; i < comments.length ; i++ ) {
                comments[i].el.style.display =
                    (comments[i].block === current_block.id) ?
                    "block" :
                    "none";
            }
        }
    };

    var show_edit = function(el, comment) {
        // let's curry!
        return function() {
            if (mode === "reading" || mode === "reading_modification") {
                if (currently_showing === comment.id) {
                    show_original();
                }
                else {
                    var previous_block = current_block;

                    // first check that the block associated with the comment
                    // exists or that there is no associated block simply
                    // because the page has no blocks
                    if (comment.block === "") {
                        if (blocks !== null) { return; }
                    }
                    else {
                        if (blocks === null) { return; }
                        var i = 0;
                        while (
                            i < blocks.length &&
                            blocks[i].id !== comment.block
                        ) { i++; }
                        if (i === blocks.length) { return; }
                        current_block = blocks[i];
                        highlight_current_block();
                    }

                    // save original content for later if it was not already
                    if (mode === "reading") {
                        original_content = getBlockContent();
                    }
                    else if (previous_block !== current_block) {
                        // restore original content for previous block
                        previous_block.innerHTML = original_content;
                        original_content = getBlockContent();
                    }

                    mode = "reading_modification";
                    currently_showing = comment.id;

                    // print diffs
                    var array = JSON.parse(he.decode(comment.edit));
                    var html = dmp.diff_prettyHtml(array);
                    current_block.innerHTML = html;

                    // add button to go back to standard reading mode
                    original_button.style.visibility = "visible";

                    // display selected comment in green and all others are set back to default
                    var comments = $(".isso-comment", null, false);
                    for (var i = 0; i < comments.length; i++) {
                        comments[i].classList.remove("selected");
                    }
                    el.classList.add("selected");

                    // scroll to block then to first change
                    var edit_top = $("#edit");
                    if (!edit_top.topIsVisible()) {
                        current_block.scrollIntoView();
                    }
                    if (!edit_top.topIsVisible()) {
                        edit_top.scrollIntoView();
                    }
                }
            }
        };
    };

    var show_original = function() {
        if (mode === "reading_modification") {
            // restore original display
            current_block.innerHTML = original_content;
            original_button.style.visibility = "hidden";
            var comments = $(".isso-comment", null, false);
            for (var i = 0; i < comments.length; i++) {
                comments[i].classList.remove("selected");
            }
            mode = "reading";
            currently_showing = null;
            // now show the current block like if we had just scrolled
            show_block_comments();
        }
    };

    // DEFINE EVENTS

    // fallback if we cannot use CKEditor change event
    if (typeof CKEDITOR === "undefined") {
        article.on("keyup", maybe_article_just_changed);
    }

    document.addEventListener("keydown", function(e) {
        if (e.keyCode === 27) {
            show_original();
        }
    });

    window.addEventListener("scroll", show_block_comments);

    // PUBLIC METHODS

    return {
        init: init,
        new_content: function() {
            if (new_content === null) {
                return null;
            }
            // otherwise we apply some pre-treatment before returning
            var splitted = dmp.diff_wordsToChars_(original_content, new_content);
            var diffs = dmp.diff_main(splitted.chars1, splitted.chars2);
            dmp.diff_cleanupSemantic(diffs);
            dmp.diff_charsToLines_(diffs, splitted.wordArray);
            return JSON.stringify(diffs);
        },
        block_id: function() { return current_block.id; },
        save_comment: save_comment,
        show_block_comments: show_block_comments,
        cancel: cancel,
        show: show_edit,
        original_button: create_original_button,
        show_original: show_original
    };
});

<commit_msg>invert highlighting for current block<commit_after>/* Copyright Théo Zimmermann 2014
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

define(["app/dom", "app/i18n", "app/utils", "he", "diff_match_patch"], function($, i18n, utils, he) {

    "use strict";

    // ATTRIBUTES

    // mode can take values "reading", "reading_modification" and "commenting"
    var mode = "reading";
    // if mode is "reading_modification", currently_showing stores id of comment
    var currently_showing;

    // there must be only one
 on the page
    var article = $("article");
    // but there can be many blocks in an article
    var blocks = $(".block", article, false);
    // in the case there is no block, current_block will always represent the full article
    var current_block = article;

    // we will also save the comment html elements and their associated block
    var comments = [];

    var original_content, new_content;

    // button to show the original version
    var original_button;
    var create_original_button = function() {
        if (typeof original_button === "undefined") {
            original_button = $.htmlify(
                '<button type="button">' +
                i18n.translate("show-original") +
                '</button>'
            );
            original_button.on("click", show_original);
            original_button.style.visibility = "hidden";
        }
        return original_button;
    };

    // remember some of the DOM elements
    var cancel_button, comment_field;

    // the block slider is used to choose which block is currently selected
    var current_position;
    (function() {
        // having a slider makes no sense with no blocks
        if (blocks === null) { return null; }

        var slider = $.htmlify('

');
        // slider position
        slider.style.left =
            ((article.getBoundingClientRect().right
              + $("#isso-thread").getBoundingClientRect().left) / 2
             - 10) + "px";
        article.insertAfter(slider);

        var cursor = $.htmlify('

');
        slider.append(cursor);
        // cursor position
        var set_cursor_position = function(y) {
            var slider_rect = slider.getBoundingClientRect();
            var slider_height = slider_rect.bottom - slider_rect.top;
            var raw_position = y - slider_rect.top - 10;
            var corrected_position =
                (raw_position < 0) ?
                0 : ((raw_position > slider_height - 20) ?
                     slider_height - 20 : raw_position);
            cursor.style.top = corrected_position + "px";
            // current_position is useful to determine the current block
            current_position = y + slider_rect.top + 10;
        };

        var first_block = blocks[0].getBoundingClientRect();
        setTimeout(function() {
            set_cursor_position((first_block.top + first_block.bottom) / 2);
        }, 0);

        // define events on slider
        var follow_mouse = function(e) {
            set_cursor_position(e.clientY);
        };
        cursor.addEventListener("mousedown", function(e) {
            document.addEventListener("mousemove", follow_mouse);
            e.preventDefault();
        });
        document.addEventListener("mouseup", function() {
            document.removeEventListener("mousemove", follow_mouse);
            show_block_comments();
        });
    })();

    // INITIALIZE LIBRARIES

    // make a diff_match_patch object once and for all
    var dmp = new diff_match_patch();

    // CKEDITOR is not required thus we must check if it is available
    if (typeof CKEDITOR !== "undefined") {
        // turn off automatic editor creation once and for all
        CKEDITOR.disableAutoInline = true;
    }
    var editor;

    // AUXILIARY FUNCTIONS

    var highlight_current_block = function() {
        for (var i = 0; i < blocks.length; i++) {
            blocks[i].style.background = "rgba(211,211,211,0.5)";
        }
        current_block.style.background = "rgba(255,255,255,0.5)";
    };

    // content after CKEditor reformatting
    // after decoding html entities
    // and after removing extra whitespace and new lines
    var getEditorContent = function() {
        return utils.clean_html(editor.getData());
    };

    var getBlockContent = function() {
        return utils.clean_html(current_block.innerHTML);
    }

    // FUNCTIONS WHICH ENABLE COMMENTING AND EDITING

    var init = function(comment_postbox) {
        comment_field = $(".textarea", comment_postbox);
        // let's curry!
        return function() {
            show_original();
            if (mode === "reading" && comment_field.innerHTML !== "") {
                mode = "commenting";
                original_content = getBlockContent();
                new_content = null;
                current_block.setAttribute("contenteditable", true);
                if (typeof CKEDITOR !== "undefined") {
                    editor = CKEDITOR.inline(current_block);
                    editor.on("instanceReady", function() {
                        editor.dataProcessor.writer.setRules("p", {
                            ident: false,
                            breakBeforeOpen: false,
                            breakAfterOpen: false,
                            breakBeforeClose: false,
                            breakAfterClose: false
                        });
                        original_content = getEditorContent();
                    });
                    editor.on("change", maybe_article_just_changed);
                }
                // first time : create cancel button and associate event
                if (!cancel_button) {
                    cancel_button = $(".post-action", comment_postbox).prepend(
                      '<input type="reset" value="' + i18n.translate("postbox-cancel") + '"></input>');
                    cancel_button.on("click", function(e) {
                        if (new_content === null ||
                            confirm(i18n.translate("postbox-confirm-cancel"))) {
                            comment_field.innerHTML = "";
                            cancel();
                        }
                    });
                }
                else {
                  cancel_button.style.display = "inline";
                }
            }
            else if (mode === "commenting" && comment_field.innerHTML === ""
                                           && new_content === null) {
                cancel();
            }
        };
    };

    var maybe_article_just_changed = function() {
        var current = typeof CKEDITOR === "undefined" ?
                        getBlockContent() :
                        getEditorContent();
        if (current !== original_content) {
            new_content = current;
        }
        else {
            new_content = null;
            if (comment_field.innerHTML === i18n.translate("postbox-text") ||
                comment_field.innerHTML === "") {
                current_block.blur();
                cancel();
            }
        }
    };

    var cancel = function() {
        if (mode === "commenting") {
            if (typeof editor !== "undefined") {
                editor.destroy();
            }
            current_block.setAttribute("contenteditable", false);
            if (new_content !== null) {
                current_block.innerHTML = original_content;
                new_content = null;
            }
            cancel_button.hide();
            mode = "reading";
        }
    };

    // FUNCTIONS TO SHOW COMMENTS / EDITS

    var save_comment = function(el, block_id) {
        comments.push({el: el, block: block_id});
    };

    var show_block_comments = function() {
        // when showing an edit or commenting, the current block is locked
        // this function is useless if there are no blocks
        if (mode == "reading" && blocks !== null) {
            // current block = block at current_position
            var i = 0;
            while (i < blocks.length &&
                   blocks[i].getBoundingClientRect().top <= current_position) {
                i++;
            }
            current_block = blocks[i - 1];
            highlight_current_block();
            // mask all comments that are not associated with the current block
            for (var i = 0 ; i < comments.length ; i++ ) {
                comments[i].el.style.display =
                    (comments[i].block === current_block.id) ?
                    "block" :
                    "none";
            }
        }
    };

    var show_edit = function(el, comment) {
        // let's curry!
        return function() {
            if (mode === "reading" || mode === "reading_modification") {
                if (currently_showing === comment.id) {
                    show_original();
                }
                else {
                    var previous_block = current_block;

                    // first check that the block associated with the comment
                    // exists or that there is no associated block simply
                    // because the page has no blocks
                    if (comment.block === "") {
                        if (blocks !== null) { return; }
                    }
                    else {
                        if (blocks === null) { return; }
                        var i = 0;
                        while (
                            i < blocks.length &&
                            blocks[i].id !== comment.block
                        ) { i++; }
                        if (i === blocks.length) { return; }
                        current_block = blocks[i];
                        highlight_current_block();
                    }

                    // save original content for later if it was not already
                    if (mode === "reading") {
                        original_content = getBlockContent();
                    }
                    else if (previous_block !== current_block) {
                        // restore original content for previous block
                        previous_block.innerHTML = original_content;
                        original_content = getBlockContent();
                    }

                    mode = "reading_modification";
                    currently_showing = comment.id;

                    // print diffs
                    var array = JSON.parse(he.decode(comment.edit));
                    var html = dmp.diff_prettyHtml(array);
                    current_block.innerHTML = html;

                    // add button to go back to standard reading mode
                    original_button.style.visibility = "visible";

                    // display selected comment in green and all others are set back to default
                    var comments = $(".isso-comment", null, false);
                    for (var i = 0; i < comments.length; i++) {
                        comments[i].classList.remove("selected");
                    }
                    el.classList.add("selected");

                    // scroll to block then to first change
                    var edit_top = $("#edit");
                    if (!edit_top.topIsVisible()) {
                        current_block.scrollIntoView();
                    }
                    if (!edit_top.topIsVisible()) {
                        edit_top.scrollIntoView();
                    }
                }
            }
        };
    };

    var show_original = function() {
        if (mode === "reading_modification") {
            // restore original display
            current_block.innerHTML = original_content;
            original_button.style.visibility = "hidden";
            var comments = $(".isso-comment", null, false);
            for (var i = 0; i < comments.length; i++) {
                comments[i].classList.remove("selected");
            }
            mode = "reading";
            currently_showing = null;
            // now show the current block like if we had just scrolled
            show_block_comments();
        }
    };

    // DEFINE EVENTS

    // fallback if we cannot use CKEditor change event
    if (typeof CKEDITOR === "undefined") {
        article.on("keyup", maybe_article_just_changed);
    }

    document.addEventListener("keydown", function(e) {
        if (e.keyCode === 27) {
            show_original();
        }
    });

    window.addEventListener("scroll", show_block_comments);

    // PUBLIC METHODS

    return {
        init: init,
        new_content: function() {
            if (new_content === null) {
                return null;
            }
            // otherwise we apply some pre-treatment before returning
            var splitted = dmp.diff_wordsToChars_(original_content, new_content);
            var diffs = dmp.diff_main(splitted.chars1, splitted.chars2);
            dmp.diff_cleanupSemantic(diffs);
            dmp.diff_charsToLines_(diffs, splitted.wordArray);
            return JSON.stringify(diffs);
        },
        block_id: function() { return current_block.id; },
        save_comment: save_comment,
        show_block_comments: show_block_comments,
        cancel: cancel,
        show: show_edit,
        original_button: create_original_button,
        show_original: show_original
    };
});

<|endoftext|>