window.wp = window.wp || {}, function (a) {
    var b;
    b = wp.revisions = {
        model: {},
        view: {},
        controller: {}
    }, b.settings = window._wpRevisionsSettings || {}, b.debug = !1, b.log = function () {
        window.console && b.debug && window.console.log.apply(window.console, arguments)
    }, a.fn.allOffsets = function () {
        var b = this.offset() || {top: 0, left: 0}, c = a(window);
        return _.extend(b, {
            right: c.width() - b.left - this.outerWidth(),
            bottom: c.height() - b.top - this.outerHeight()
        })
    }, a.fn.allPositions = function () {
        var a = this.position() || {top: 0, left: 0}, b = this.parent();
        return _.extend(a, {
            right: b.outerWidth() - a.left - this.outerWidth(),
            bottom: b.outerHeight() - a.top - this.outerHeight()
        })
    }, b.model.Slider = Backbone.Model.extend({
        defaults: {
            value: null,
            values: null,
            min: 0,
            max: 1,
            step: 1,
            range: !1,
            compareTwoMode: !1
        }, initialize: function (a) {
            this.frame = a.frame, this.revisions = a.revisions, this.listenTo(this.frame, "update:revisions", this.receiveRevisions), this.listenTo(this.frame, "change:compareTwoMode", this.updateMode), this.on("change:from", this.handleLocalChanges), this.on("change:to", this.handleLocalChanges), this.on("change:compareTwoMode", this.updateSliderSettings), this.on("update:revisions", this.updateSliderSettings), this.on("change:hoveredRevision", this.hoverRevision), this.set({
                max: this.revisions.length - 1,
                compareTwoMode: this.frame.get("compareTwoMode"),
                from: this.frame.get("from"),
                to: this.frame.get("to")
            }), this.updateSliderSettings()
        }, getSliderValue: function (a, b) {
            return isRtl ? this.revisions.length - this.revisions.indexOf(this.get(a)) - 1 : this.revisions.indexOf(this.get(b))
        }, updateSliderSettings: function () {
            this.get("compareTwoMode") ? this.set({
                values: [this.getSliderValue("to", "from"), this.getSliderValue("from", "to")],
                value: null,
                range: !0
            }) : this.set({
                value: this.getSliderValue("to", "to"),
                values: null,
                range: !1
            }), this.trigger("update:slider")
        }, hoverRevision: function (a, b) {
            this.trigger("hovered:revision", b)
        }, updateMode: function (a, b) {
            this.set({compareTwoMode: b})
        }, handleLocalChanges: function () {
            this.frame.set({from: this.get("from"), to: this.get("to")})
        }, receiveRevisions: function (a, b) {
            (this.get("from") !== a || this.get("to") !== b) && (this.set({
                from: a,
                to: b
            }, {silent: !0}), this.trigger("update:revisions", a, b))
        }
    }), b.model.Tooltip = Backbone.Model.extend({
        defaults: {revision: null, offset: {}, hovering: !1, scrubbing: !1},
        initialize: function (a) {
            this.frame = a.frame, this.revisions = a.revisions, this.slider = a.slider, this.listenTo(this.slider, "hovered:revision", this.updateRevision), this.listenTo(this.slider, "change:hovering", this.setHovering), this.listenTo(this.slider, "change:scrubbing", this.setScrubbing)
        },
        updateRevision: function (a) {
            this.set({revision: a})
        },
        setHovering: function (a, b) {
            this.set({hovering: b})
        },
        setScrubbing: function (a, b) {
            this.set({scrubbing: b})
        }
    }), b.model.Revision = Backbone.Model.extend({}), b.model.Revisions = Backbone.Collection.extend({
        model: b.model.Revision,
        initialize: function () {
            _.bindAll(this, "next", "prev")
        },
        next: function (a) {
            var b = this.indexOf(a);
            return -1 !== b && b !== this.length - 1 ? this.at(b + 1) : void 0
        },
        prev: function (a) {
            var b = this.indexOf(a);
            return -1 !== b && 0 !== b ? this.at(b - 1) : void 0
        }
    }), b.model.Field = Backbone.Model.extend({}), b.model.Fields = Backbone.Collection.extend({model: b.model.Field}), b.model.Diff = Backbone.Model.extend({
        initialize: function () {
            var a = this.get("fields");
            this.unset("fields"), this.fields = new b.model.Fields(a)
        }
    }), b.model.Diffs = Backbone.Collection.extend({
        initialize: function (a, b) {
            _.bindAll(this, "getClosestUnloaded"), this.loadAll = _.once(this._loadAll), this.revisions = b.revisions, this.postId = b.postId, this.requests = {}
        }, model: b.model.Diff, ensure: function (b, c) {
            var d = this.get(b), e = this.requests[b], f = a.Deferred(), g = {}, h = b.split(":")[0], i = b.split(":")[1];
            return g[b] = !0, wp.revisions.log("ensure", b), this.trigger("ensure", g, h, i, f.promise()), d ? f.resolveWith(c, [d]) : (this.trigger("ensure:load", g, h, i, f.promise()), _.each(g, _.bind(function (a) {
                this.requests[a] && delete g[a], this.get(a) && delete g[a]
            }, this)), e || (g[b] = !0, e = this.load(_.keys(g))), e.done(_.bind(function () {
                f.resolveWith(c, [this.get(b)])
            }, this)).fail(_.bind(function () {
                f.reject()
            }))), f.promise()
        }, getClosestUnloaded: function (a, b) {
            var c = this;
            return _.chain([0].concat(a)).initial().zip(a).sortBy(function (a) {
                return Math.abs(b - a[1])
            }).map(function (a) {
                return a.join(":")
            }).filter(function (a) {
                return _.isUndefined(c.get(a)) && !c.requests[a]
            }).value()
        }, _loadAll: function (b, c, d) {
            var e = this, f = a.Deferred(), g = _.first(this.getClosestUnloaded(b, c), d);
            return _.size(g) > 0 ? this.load(g).done(function () {
                e._loadAll(b, c, d).done(function () {
                    f.resolve()
                })
            }).fail(function () {
                1 === d ? f.reject() : e._loadAll(b, c, Math.ceil(d / 2)).done(function () {
                    f.resolve()
                })
            }) : f.resolve(), f
        }, load: function (a) {
            return wp.revisions.log("load", a), this.fetch({data: {compare: a}, remove: !1}).done(function () {
                wp.revisions.log("load:complete", a)
            })
        }, sync: function (a, b, c) {
            if ("read" === a) {
                c = c || {}, c.context = this, c.data = _.extend(c.data || {}, {
                    action: "get-revision-diffs",
                    post_id: this.postId
                });
                var d = wp.ajax.send(c), e = this.requests;
                return c.data.compare && _.each(c.data.compare, function (a) {
                    e[a] = d
                }), d.always(function () {
                    c.data.compare && _.each(c.data.compare, function (a) {
                        delete e[a]
                    })
                }), d
            }
            return Backbone.Model.prototype.sync.apply(this, arguments)
        }
    }), b.model.FrameState = Backbone.Model.extend({
        defaults: {loading: !1, error: !1, compareTwoMode: !1},
        initialize: function (a, c) {
            var d = this.get("initialDiffState");
            _.bindAll(this, "receiveDiff"), this._debouncedEnsureDiff = _.debounce(this._ensureDiff, 200), this.revisions = c.revisions, this.diffs = new b.model.Diffs([], {
                revisions: this.revisions,
                postId: this.get("postId")
            }), this.diffs.set(this.get("diffData")), this.listenTo(this, "change:from", this.changeRevisionHandler), this.listenTo(this, "change:to", this.changeRevisionHandler), this.listenTo(this, "change:compareTwoMode", this.changeMode), this.listenTo(this, "update:revisions", this.updatedRevisions), this.listenTo(this.diffs, "ensure:load", this.updateLoadingStatus), this.listenTo(this, "update:diff", this.updateLoadingStatus), this.set({
                to: this.revisions.get(d.to),
                from: this.revisions.get(d.from),
                compareTwoMode: d.compareTwoMode
            }), window.history && window.history.pushState && (this.router = new b.Router({model: this}), Backbone.history.start({pushState: !0}))
        },
        updateLoadingStatus: function () {
            this.set("error", !1), this.set("loading", !this.diff())
        },
        changeMode: function (a, b) {
            var c = this.revisions.indexOf(this.get("to"));
            b && 0 === c && this.set({
                from: this.revisions.at(c),
                to: this.revisions.at(c + 1)
            }), b || 0 === c || this.set({from: this.revisions.at(c - 1), to: this.revisions.at(c)})
        },
        updatedRevisions: function (a, b) {
            this.get("compareTwoMode") || this.diffs.loadAll(this.revisions.pluck("id"), b.id, 40)
        },
        diff: function () {
            return this.diffs.get(this._diffId)
        },
        updateDiff: function (b) {
            var c, d, e, f;
            return b = b || {}, c = this.get("from"), d = this.get("to"), e = (c ? c.id : 0) + ":" + d.id, this._diffId === e ? a.Deferred().reject().promise() : (this._diffId = e, this.trigger("update:revisions", c, d), f = this.diffs.get(e), f ? (this.receiveDiff(f), a.Deferred().resolve().promise()) : b.immediate ? this._ensureDiff() : (this._debouncedEnsureDiff(), a.Deferred().reject().promise()))
        },
        changeRevisionHandler: function () {
            this.updateDiff()
        },
        receiveDiff: function (a) {
            _.isUndefined(a) || _.isUndefined(a.id) ? this.set({
                loading: !1,
                error: !0
            }) : this._diffId === a.id && this.trigger("update:diff", a)
        },
        _ensureDiff: function () {
            return this.diffs.ensure(this._diffId, this).always(this.receiveDiff)
        }
    }), b.view.Frame = wp.Backbone.View.extend({
        className: "revisions",
        template: wp.template("revisions-frame"),
        initialize: function () {
            this.listenTo(this.model, "update:diff", this.renderDiff), this.listenTo(this.model, "change:compareTwoMode", this.updateCompareTwoMode), this.listenTo(this.model, "change:loading", this.updateLoadingStatus), this.listenTo(this.model, "change:error", this.updateErrorStatus), this.views.set(".revisions-control-frame", new b.view.Controls({model: this.model}))
        },
        render: function () {
            return wp.Backbone.View.prototype.render.apply(this, arguments), a("html").css("overflow-y", "scroll"), a("#wpbody-content .wrap").append(this.el), this.updateCompareTwoMode(), this.renderDiff(this.model.diff()), this.views.ready(), this
        },
        renderDiff: function (a) {
            this.views.set(".revisions-diff-frame", new b.view.Diff({model: a}))
        },
        updateLoadingStatus: function () {
            this.$el.toggleClass("loading", this.model.get("loading"))
        },
        updateErrorStatus: function () {
            this.$el.toggleClass("diff-error", this.model.get("error"))
        },
        updateCompareTwoMode: function () {
            this.$el.toggleClass("comparing-two-revisions", this.model.get("compareTwoMode"))
        }
    }), b.view.Controls = wp.Backbone.View.extend({
        className: "revisions-controls", initialize: function () {
            _.bindAll(this, "setWidth"), this.views.add(new b.view.Buttons({model: this.model})), this.views.add(new b.view.Checkbox({model: this.model}));
            var a = new b.model.Slider({
                frame: this.model,
                revisions: this.model.revisions
            }), c = new b.model.Tooltip({frame: this.model, revisions: this.model.revisions, slider: a});
            this.views.add(new b.view.Tooltip({model: c})), this.views.add(new b.view.Tickmarks({model: c})), this.views.add(new b.view.Slider({model: a})), this.views.add(new b.view.Metabox({model: this.model}))
        }, ready: function () {
            this.top = this.$el.offset().top, this.window = a(window), this.window.on("scroll.wp.revisions", {controls: this}, function (a) {
                var b = a.data.controls, c = b.$el.parent(), d = b.window.scrollTop(), e = b.views.parent;
                d >= b.top ? (e.$el.hasClass("pinned") || (b.setWidth(), c.css("height", c.height() + "px"), b.window.on("resize.wp.revisions.pinning click.wp.revisions.pinning", {controls: b}, function (a) {
                    a.data.controls.setWidth()
                })), e.$el.addClass("pinned")) : e.$el.hasClass("pinned") ? (b.window.off(".wp.revisions.pinning"), b.$el.css("width", "auto"), e.$el.removeClass("pinned"), c.css("height", "auto"), b.top = b.$el.offset().top) : b.top = b.$el.offset().top
            })
        }, setWidth: function () {
            this.$el.css("width", this.$el.parent().width() + "px")
        }
    }), b.view.Tickmarks = wp.Backbone.View.extend({
        className: "revisions-tickmarks",
        direction: isRtl ? "right" : "left",
        initialize: function () {
            this.listenTo(this.model, "change:revision", this.reportTickPosition)
        },
        reportTickPosition: function (a, b) {
            var c, d, e, f, g = this.model.revisions.indexOf(b);
            d = this.$el.allOffsets(), e = this.$el.parent().allOffsets(), g === this.model.revisions.length - 1 ? c = {
                rightPlusWidth: d.left - e.left + 1,
                leftPlusWidth: d.right - e.right + 1
            } : (f = this.$("div:nth-of-type(" + (g + 1) + ")"), c = f.allPositions(), _.extend(c, {
                left: c.left + d.left - e.left,
                right: c.right + d.right - e.right
            }), _.extend(c, {
                leftPlusWidth: c.left + f.outerWidth(),
                rightPlusWidth: c.right + f.outerWidth()
            })), this.model.set({offset: c})
        },
        ready: function () {
            var a, b;
            a = this.model.revisions.length - 1, b = 1 / a, this.$el.css("width", 50 * this.model.revisions.length + "px"), _(a).times(function (a) {
                this.$el.append('<div style="' + this.direction + ": " + 100 * b * a + '%"></div>')
            }, this)
        }
    }), b.view.Metabox = wp.Backbone.View.extend({
        className: "revisions-meta", initialize: function () {
            this.views.add(new b.view.MetaFrom({
                model: this.model,
                className: "diff-meta diff-meta-from"
            })), this.views.add(new b.view.MetaTo({model: this.model}))
        }
    }), b.view.Meta = wp.Backbone.View.extend({
        template: wp.template("revisions-meta"),
        events: {"click .restore-revision": "restoreRevision"},
        initialize: function () {
            this.listenTo(this.model, "update:revisions", this.render)
        },
        prepare: function () {
            return _.extend(this.model.toJSON()[this.type] || {}, {type: this.type})
        },
        restoreRevision: function () {
            document.location = this.model.get("to").attributes.restoreUrl
        }
    }), b.view.MetaFrom = b.view.Meta.extend({
        className: "diff-meta diff-meta-from",
        type: "from"
    }), b.view.MetaTo = b.view.Meta.extend({
        className: "diff-meta diff-meta-to",
        type: "to"
    }), b.view.Checkbox = wp.Backbone.View.extend({
        className: "revisions-checkbox",
        template: wp.template("revisions-checkbox"),
        events: {"click .compare-two-revisions": "compareTwoToggle"},
        initialize: function () {
            this.listenTo(this.model, "change:compareTwoMode", this.updateCompareTwoMode)
        },
        ready: function () {
            this.model.revisions.length < 3 && a(".revision-toggle-compare-mode").hide()
        },
        updateCompareTwoMode: function () {
            this.$(".compare-two-revisions").prop("checked", this.model.get("compareTwoMode"))
        },
        compareTwoToggle: function () {
            this.model.set({compareTwoMode: a(".compare-two-revisions").prop("checked")})
        }
    }), b.view.Tooltip = wp.Backbone.View.extend({
        className: "revisions-tooltip",
        template: wp.template("revisions-meta"),
        initialize: function () {
            this.listenTo(this.model, "change:offset", this.render), this.listenTo(this.model, "change:hovering", this.toggleVisibility), this.listenTo(this.model, "change:scrubbing", this.toggleVisibility)
        },
        prepare: function () {
            return _.isNull(this.model.get("revision")) ? void 0 : _.extend({type: "tooltip"}, {attributes: this.model.get("revision").toJSON()})
        },
        render: function () {
            var a, b, c, d, e = {}, f = this.model.revisions.indexOf(this.model.get("revision")) + 1;
            d = f / this.model.revisions.length > .5, isRtl ? (b = d ? "left" : "right", c = d ? "leftPlusWidth" : b) : (b = d ? "right" : "left", c = d ? "rightPlusWidth" : b), a = "right" === b ? "left" : "right", wp.Backbone.View.prototype.render.apply(this, arguments), e[b] = this.model.get("offset")[c] + "px", e[a] = "", this.$el.toggleClass("flipped", d).css(e)
        },
        visible: function () {
            return this.model.get("scrubbing") || this.model.get("hovering")
        },
        toggleVisibility: function () {
            this.visible() ? this.$el.stop().show().fadeTo(100 - 100 * this.el.style.opacity, 1) : this.$el.stop().fadeTo(300 * this.el.style.opacity, 0, function () {
                a(this).hide()
            })
        }
    }), b.view.Buttons = wp.Backbone.View.extend({
        className: "revisions-buttons",
        template: wp.template("revisions-buttons"),
        events: {
            "click .revisions-next .button": "nextRevision",
            "click .revisions-previous .button": "previousRevision"
        },
        initialize: function () {
            this.listenTo(this.model, "update:revisions", this.disabledButtonCheck)
        },
        ready: function () {
            this.disabledButtonCheck()
        },
        gotoModel: function (a) {
            var b = {to: this.model.revisions.at(a)};
            a ? b.from = this.model.revisions.at(a - 1) : this.model.unset("from", {silent: !0}), this.model.set(b)
        },
        nextRevision: function () {
            var a = this.model.revisions.indexOf(this.model.get("to")) + 1;
            this.gotoModel(a)
        },
        previousRevision: function () {
            var a = this.model.revisions.indexOf(this.model.get("to")) - 1;
            this.gotoModel(a)
        },
        disabledButtonCheck: function () {
            var b = this.model.revisions.length - 1, c = 0, d = a(".revisions-next .button"), e = a(".revisions-previous .button"), f = this.model.revisions.indexOf(this.model.get("to"));
            d.prop("disabled", b === f), e.prop("disabled", c === f)
        }
    }), b.view.Slider = wp.Backbone.View.extend({
        className: "wp-slider",
        direction: isRtl ? "right" : "left",
        events: {mousemove: "mouseMove"},
        initialize: function () {
            _.bindAll(this, "start", "slide", "stop", "mouseMove", "mouseEnter", "mouseLeave"), this.listenTo(this.model, "update:slider", this.applySliderSettings)
        },
        ready: function () {
            this.$el.css("width", 50 * this.model.revisions.length + "px"), this.$el.slider(_.extend(this.model.toJSON(), {
                start: this.start,
                slide: this.slide,
                stop: this.stop
            })), this.$el.hoverIntent({
                over: this.mouseEnter,
                out: this.mouseLeave,
                timeout: 800
            }), this.applySliderSettings()
        },
        mouseMove: function (b) {
            var c = this.model.revisions.length - 1, d = this.$el.allOffsets()[this.direction], e = this.$el.width(), f = e / c, g = (isRtl ? a(window).width() - b.pageX : b.pageX) - d, h = Math.floor((g + f / 2) / f);
            0 > h ? h = 0 : h >= this.model.revisions.length && (h = this.model.revisions.length - 1), this.model.set({hoveredRevision: this.model.revisions.at(h)})
        },
        mouseLeave: function () {
            this.model.set({hovering: !1})
        },
        mouseEnter: function () {
            this.model.set({hovering: !0})
        },
        applySliderSettings: function () {
            this.$el.slider(_.pick(this.model.toJSON(), "value", "values", "range"));
            var a = this.$("a.ui-slider-handle");
            this.model.get("compareTwoMode") ? (a.first().toggleClass("to-handle", !!isRtl).toggleClass("from-handle", !isRtl), a.last().toggleClass("from-handle", !!isRtl).toggleClass("to-handle", !isRtl)) : a.removeClass("from-handle to-handle")
        },
        start: function (b, c) {
            this.model.set({scrubbing: !0}), a(window).on("mousemove.wp.revisions", {view: this}, function (b) {
                var d, e = b.data.view, f = e.$el.offset().left, g = f, h = f + e.$el.width(), i = h, j = "0", k = "100%", l = a(c.handle);
                e.model.get("compareTwoMode") && (d = l.parent().find(".ui-slider-handle"), l.is(d.first()) ? (i = d.last().offset().left, k = i - g) : (f = d.first().offset().left + d.first().width(), j = f - g)), b.pageX < f ? l.css("left", j) : b.pageX > i ? l.css("left", k) : l.css("left", b.pageX - g)
            })
        },
        getPosition: function (a) {
            return isRtl ? this.model.revisions.length - a - 1 : a
        },
        slide: function (a, b) {
            var c, d;
            if (this.model.get("compareTwoMode")) {
                if (b.values[1] === b.values[0])return !1;
                isRtl && b.values.reverse(), c = {
                    from: this.model.revisions.at(this.getPosition(b.values[0])),
                    to: this.model.revisions.at(this.getPosition(b.values[1]))
                }
            } else c = {to: this.model.revisions.at(this.getPosition(b.value))}, this.getPosition(b.value) > 0 ? c.from = this.model.revisions.at(this.getPosition(b.value) - 1) : c.from = void 0;
            d = this.model.revisions.at(this.getPosition(b.value)), this.model.get("scrubbing") && (c.hoveredRevision = d), this.model.set(c)
        },
        stop: function () {
            a(window).off("mousemove.wp.revisions"), this.model.updateSliderSettings(), this.model.set({scrubbing: !1})
        }
    }), b.view.Diff = wp.Backbone.View.extend({
        className: "revisions-diff",
        template: wp.template("revisions-diff"),
        prepare: function () {
            return _.extend({fields: this.model.fields.toJSON()}, this.options)
        }
    }), b.Router = Backbone.Router.extend({
        initialize: function (a) {
            this.model = a.model, this.listenTo(this.model, "update:diff", _.debounce(this.updateUrl, 250)), this.listenTo(this.model, "change:compareTwoMode", this.updateUrl)
        }, baseUrl: function (a) {
            return this.model.get("baseUrl") + a
        }, updateUrl: function () {
            var a = this.model.has("from") ? this.model.get("from").id : 0, b = this.model.get("to").id;
            this.model.get("compareTwoMode") ? this.navigate(this.baseUrl("?from=" + a + "&to=" + b), {replace: !0}) : this.navigate(this.baseUrl("?revision=" + b), {replace: !0})
        }, handleRoute: function (a, b) {
            var c = _.isUndefined(b);
            c || (b = this.model.revisions.get(a), a = this.model.revisions.prev(b), b = b ? b.id : 0, a = a ? a.id : 0)
        }
    }), b.init = function () {
        var a;
        window.adminpage && "revision-php" === window.adminpage && (a = new b.model.FrameState({
            initialDiffState: {
                to: parseInt(b.settings.to, 10),
                from: parseInt(b.settings.from, 10),
                compareTwoMode: "1" === b.settings.compareTwoMode
            }, diffData: b.settings.diffData, baseUrl: b.settings.baseUrl, postId: parseInt(b.settings.postId, 10)
        }, {revisions: new b.model.Revisions(b.settings.revisionData)}), b.view.frame = new b.view.Frame({model: a}).render())
    }, a(b.init)
}(jQuery);