mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge branch 'master' of github.com:sharelatex/web-sharelatex
This commit is contained in:
commit
af659e7690
8 changed files with 115 additions and 62 deletions
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
script(type="text/template")#tabTemplate
|
script(type="text/template")#tabTemplate
|
||||||
li(id="{{ id }}-tab-li")
|
li(id="{{ id }}-tab-li")
|
||||||
a(href="#", data-toggle="tab", data-target="\\#{{ id }}-tab", class="tab-link {{ id }}-tab")
|
a(href="#", data-toggle="tab", data-target="\\#{{ show }}-tab", class="tab-link {{ id }}-tab")
|
||||||
.content {{ name }}
|
.content {{ name }}
|
||||||
|
|
||||||
script(type="text/template")#tabContentTemplate
|
script(type="text/template")#tabContentTemplate
|
||||||
|
@ -436,6 +436,12 @@
|
||||||
.change-list-area
|
.change-list-area
|
||||||
.track-changes-diff
|
.track-changes-diff
|
||||||
|
|
||||||
|
script(type='text/template')#trackChangesDiffTemplate
|
||||||
|
.track-changes-diff-toolbar.btn-toolbar
|
||||||
|
.number-of-changes {{ changes }} in <strong>{{ name }}</strong>
|
||||||
|
a(href="#").restore.btn.btn-small.btn-danger Restore to before these changes
|
||||||
|
.track-changes-diff-editor
|
||||||
|
|
||||||
script(type='text/template')#changeListItemTemplate
|
script(type='text/template')#changeListItemTemplate
|
||||||
div(class='change-selectors')
|
div(class='change-selectors')
|
||||||
div.range
|
div.range
|
||||||
|
@ -447,9 +453,6 @@
|
||||||
div.change-date {{date}}
|
div.change-date {{date}}
|
||||||
div {{{users}}}
|
div {{{users}}}
|
||||||
|
|
||||||
div(class='restore')
|
|
||||||
a(href="#") Restore to here
|
|
||||||
|
|
||||||
script(type='text/template')#changeListItemUserTemplate
|
script(type='text/template')#changeListItemUserTemplate
|
||||||
div(class='change-name')
|
div(class='change-name')
|
||||||
div.color-square(style="background-color: hsl({{hue}}, 100%, 70%);")
|
div.color-square(style="background-color: hsl({{hue}}, 100%, 70%);")
|
||||||
|
|
|
@ -97,7 +97,7 @@ define [
|
||||||
@views[@selected_entity_id].deselect()
|
@views[@selected_entity_id].deselect()
|
||||||
@selected_entity_id = entity_id
|
@selected_entity_id = entity_id
|
||||||
@ide.sideBarView.deselectAll()
|
@ide.sideBarView.deselectAll()
|
||||||
@views[entity_id].select()
|
@views[entity_id]?.select()
|
||||||
|
|
||||||
getEntity: (entity_id) ->
|
getEntity: (entity_id) ->
|
||||||
@views[entity_id]?.model
|
@views[entity_id]?.model
|
||||||
|
|
|
@ -17,8 +17,9 @@ define [
|
||||||
addTab: (options) ->
|
addTab: (options) ->
|
||||||
@tabs.push options
|
@tabs.push options
|
||||||
|
|
||||||
|
options.show ||= options.id
|
||||||
tabEl = $(Mustache.to_html @templates.tab, options)
|
tabEl = $(Mustache.to_html @templates.tab, options)
|
||||||
tabEl.find("a").attr("href", "#" + options.id)
|
tabEl.find("a").attr("href", "#" + options.show)
|
||||||
|
|
||||||
if options.content?
|
if options.content?
|
||||||
contentEl = $(Mustache.to_html @templates.content, options)
|
contentEl = $(Mustache.to_html @templates.content, options)
|
||||||
|
@ -53,6 +54,8 @@ define [
|
||||||
if options.contract
|
if options.contract
|
||||||
@contract()
|
@contract()
|
||||||
|
|
||||||
|
show: (tab) ->
|
||||||
|
$("##{tab}-tab-li > a").tab("show")
|
||||||
|
|
||||||
lockOpen: () ->
|
lockOpen: () ->
|
||||||
@locked_open = true
|
@locked_open = true
|
||||||
|
|
|
@ -75,9 +75,6 @@ define [
|
||||||
delete @hoverFromIndex
|
delete @hoverFromIndex
|
||||||
@resetHoverStates()
|
@resetHoverStates()
|
||||||
|
|
||||||
view.on "click:restore", (e) =>
|
|
||||||
@trigger "restore", view.model
|
|
||||||
|
|
||||||
view.resetSelector(index, @selectedFromIndex, @selectedToIndex)
|
view.resetSelector(index, @selectedFromIndex, @selectedToIndex)
|
||||||
|
|
||||||
setSelectionRange: (fromIndex, toIndex) ->
|
setSelectionRange: (fromIndex, toIndex) ->
|
||||||
|
@ -173,8 +170,6 @@ define [
|
||||||
@trigger "mouseenter:from", args...
|
@trigger "mouseenter:from", args...
|
||||||
"mouseleave .change-selector-from": (args...) ->
|
"mouseleave .change-selector-from": (args...) ->
|
||||||
@trigger "mouseleave:from", args...
|
@trigger "mouseleave:from", args...
|
||||||
"click .restore a": "onRestoreClick"
|
|
||||||
|
|
||||||
|
|
||||||
templates:
|
templates:
|
||||||
item: $("#changeListItemTemplate").html()
|
item: $("#changeListItemTemplate").html()
|
||||||
|
@ -214,10 +209,6 @@ define [
|
||||||
onFromSelectorClick: (e) ->
|
onFromSelectorClick: (e) ->
|
||||||
@trigger "selected:from", e, @
|
@trigger "selected:from", e, @
|
||||||
|
|
||||||
onRestoreClick: (e) ->
|
|
||||||
e.preventDefault()
|
|
||||||
@trigger "click:restore", e, @
|
|
||||||
|
|
||||||
isSelectedFrom: () ->
|
isSelectedFrom: () ->
|
||||||
@$(".change-selector-from").is(":checked")
|
@$(".change-selector-from").is(":checked")
|
||||||
|
|
||||||
|
|
|
@ -4,15 +4,33 @@ define [
|
||||||
"ace/range"
|
"ace/range"
|
||||||
"moment"
|
"moment"
|
||||||
"libs/backbone"
|
"libs/backbone"
|
||||||
|
"libs/mustache"
|
||||||
], (Ace, LatexMode, Range, moment)->
|
], (Ace, LatexMode, Range, moment)->
|
||||||
DiffView = Backbone.View.extend
|
DiffView = Backbone.View.extend
|
||||||
|
template: $("#trackChangesDiffTemplate").html()
|
||||||
|
|
||||||
|
events:
|
||||||
|
"click .restore": () ->
|
||||||
|
console.log "click"
|
||||||
|
@trigger "restore"
|
||||||
|
|
||||||
initialize: () ->
|
initialize: () ->
|
||||||
@model.on "change:diff", () => @render()
|
@model.on "change:diff", () => @render()
|
||||||
@render()
|
|
||||||
|
|
||||||
render: ->
|
render: ->
|
||||||
diff = @model.get("diff")
|
diff = @model.get("diff")
|
||||||
return unless diff?
|
return unless diff?
|
||||||
|
|
||||||
|
changes = @getNumberOfChanges()
|
||||||
|
html = Mustache.to_html @template, {
|
||||||
|
changes: "#{changes} change#{if changes == 1 then "" else "s"}"
|
||||||
|
name: @model.get("doc")?.get("name")
|
||||||
|
}
|
||||||
|
@$el.html(html)
|
||||||
|
|
||||||
|
if !@model.get("from")? or !@model.get("to")? or changes == 0
|
||||||
|
@$(".restore").hide()
|
||||||
|
|
||||||
@createAceEditor()
|
@createAceEditor()
|
||||||
@aceEditor.setValue(@getPlainDiffContent())
|
@aceEditor.setValue(@getPlainDiffContent())
|
||||||
@aceEditor.clearSelection()
|
@aceEditor.clearSelection()
|
||||||
|
@ -24,12 +42,12 @@ define [
|
||||||
@scrollToFirstChange()
|
@scrollToFirstChange()
|
||||||
return @
|
return @
|
||||||
|
|
||||||
destroy: () ->
|
remove: () ->
|
||||||
@$editor?.remove()
|
@$editor?.remove()
|
||||||
|
@undelegateEvents()
|
||||||
|
|
||||||
createAceEditor: () ->
|
createAceEditor: () ->
|
||||||
@$el.empty()
|
@$editor = @$(".track-changes-diff-editor")
|
||||||
@$editor = $("<div/>")
|
|
||||||
@$el.append(@$editor)
|
@$el.append(@$editor)
|
||||||
@aceEditor = Ace.edit(@$editor[0])
|
@aceEditor = Ace.edit(@$editor[0])
|
||||||
@aceEditor.setTheme("ace/theme/#{window.userSettings.theme}")
|
@aceEditor.setTheme("ace/theme/#{window.userSettings.theme}")
|
||||||
|
@ -54,6 +72,12 @@ define [
|
||||||
content += entry.u or entry.i or entry.d or ""
|
content += entry.u or entry.i or entry.d or ""
|
||||||
return content
|
return content
|
||||||
|
|
||||||
|
getNumberOfChanges: () ->
|
||||||
|
changes = 0
|
||||||
|
for entry in @model.get("diff") or []
|
||||||
|
changes += 1 if entry.i? or entry.d?
|
||||||
|
return changes
|
||||||
|
|
||||||
insertMarkers: () ->
|
insertMarkers: () ->
|
||||||
row = 0
|
row = 0
|
||||||
column = 0
|
column = 0
|
||||||
|
|
|
@ -20,6 +20,7 @@ define [
|
||||||
@ide.tabManager.addTab
|
@ide.tabManager.addTab
|
||||||
id: "history"
|
id: "history"
|
||||||
name: "History"
|
name: "History"
|
||||||
|
show: "code"
|
||||||
after: "code"
|
after: "code"
|
||||||
contract: true
|
contract: true
|
||||||
onShown: () => @show()
|
onShown: () => @show()
|
||||||
|
@ -56,11 +57,8 @@ define [
|
||||||
@changeListView.on "change_diff", (fromIndex, toIndex) =>
|
@changeListView.on "change_diff", (fromIndex, toIndex) =>
|
||||||
@selectDocAndUpdateDiff(fromIndex, toIndex)
|
@selectDocAndUpdateDiff(fromIndex, toIndex)
|
||||||
|
|
||||||
@changeListView.on "restore", (change) =>
|
|
||||||
@restore(change)
|
|
||||||
|
|
||||||
if @diffView?
|
if @diffView?
|
||||||
@diffView.destroy()
|
@diffView.remove()
|
||||||
|
|
||||||
@ide.mainAreaManager.change "trackChanges"
|
@ide.mainAreaManager.change "trackChanges"
|
||||||
@ide.editor.disable()
|
@ide.editor.disable()
|
||||||
|
@ -72,7 +70,7 @@ define [
|
||||||
@ide.fileViewManager.enable()
|
@ide.fileViewManager.enable()
|
||||||
@disable()
|
@disable()
|
||||||
@ide.fileTreeManager.openDoc(@doc_id)
|
@ide.fileTreeManager.openDoc(@doc_id)
|
||||||
@ide.mainAreaManager.change "editor"
|
@ide.tabManager.show "code"
|
||||||
|
|
||||||
autoSelectDiff: () ->
|
autoSelectDiff: () ->
|
||||||
if @changes.models.length == 0
|
if @changes.models.length == 0
|
||||||
|
@ -113,33 +111,41 @@ define [
|
||||||
console.log "No selection - what should we do!?"
|
console.log "No selection - what should we do!?"
|
||||||
return
|
return
|
||||||
|
|
||||||
{from, to} = @_findDocVersionsRangeInSelection(@doc_id, fromIndex, toIndex)
|
{from, to, start_ts, end_ts} = @_findDocVersionsRangeInSelection(@doc_id, fromIndex, toIndex)
|
||||||
|
|
||||||
if !from? or !to?
|
|
||||||
console.log "No diff, should probably just show latest version"
|
|
||||||
return
|
|
||||||
|
|
||||||
@diff = new Diff({
|
@diff = new Diff({
|
||||||
project_id: @project_id
|
project_id: @project_id
|
||||||
doc_id: @doc_id
|
doc_id: @doc_id
|
||||||
from: from
|
from: from
|
||||||
to: to
|
to: to
|
||||||
|
start_ts: start_ts
|
||||||
|
end_ts: end_ts
|
||||||
|
}, {
|
||||||
|
ide: @ide
|
||||||
})
|
})
|
||||||
|
|
||||||
if @diffView?
|
if @diffView?
|
||||||
@diffView.destroy()
|
@diffView.remove()
|
||||||
|
|
||||||
|
if !@diff.get("doc")?
|
||||||
|
console.log "This document has been deleted. What should we do?"
|
||||||
|
return
|
||||||
|
|
||||||
@diffView = new DiffView(
|
@diffView = new DiffView(
|
||||||
model: @diff
|
model: @diff
|
||||||
el: @$el.find(".track-changes-diff")
|
el: @$el.find(".track-changes-diff")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@diffView.on "restore", () =>
|
||||||
|
@restoreDiff(@diff)
|
||||||
|
|
||||||
@diff.fetch()
|
@diff.fetch()
|
||||||
|
|
||||||
@ide.fileTreeManager.selectEntity(@doc_id)
|
@ide.fileTreeManager.selectEntity(@doc_id)
|
||||||
|
|
||||||
|
|
||||||
_findDocVersionsRangeInSelection: (doc_id, fromIndex, toIndex) ->
|
_findDocVersionsRangeInSelection: (doc_id, fromIndex, toIndex) ->
|
||||||
from = null
|
from = to = start_ts = end_ts = null
|
||||||
to = null
|
|
||||||
|
|
||||||
for change in @changes.models.slice(toIndex, fromIndex + 1)
|
for change in @changes.models.slice(toIndex, fromIndex + 1)
|
||||||
for doc in change.get("docs")
|
for doc in change.get("docs")
|
||||||
|
@ -147,16 +153,20 @@ define [
|
||||||
if from? and to?
|
if from? and to?
|
||||||
from = Math.min(from, doc.fromV)
|
from = Math.min(from, doc.fromV)
|
||||||
to = Math.max(to, doc.toV)
|
to = Math.max(to, doc.toV)
|
||||||
|
start_ts = Math.min(start_ts, change.get("start_ts"))
|
||||||
|
end_ts = Math.max(end_ts, change.get("end_ts"))
|
||||||
else
|
else
|
||||||
from = doc.fromV
|
from = doc.fromV
|
||||||
to = doc.toV
|
to = doc.toV
|
||||||
|
start_ts = change.get("start_ts")
|
||||||
|
end_ts = change.get("end_ts")
|
||||||
break
|
break
|
||||||
|
|
||||||
return {from, to}
|
return {from, to, start_ts, end_ts}
|
||||||
|
|
||||||
restore: (change) ->
|
restoreDiff: (diff) ->
|
||||||
name = @ide.fileTreeManager.getNameOfEntityId(@doc_id)
|
name = diff.get("doc")?.get("name")
|
||||||
date = moment(change.get("start_ts")).format("Do MMM YYYY, h:mm:ss a")
|
date = moment(diff.get("start_ts")).format("Do MMM YYYY, h:mm:ss a")
|
||||||
modal = new Modal({
|
modal = new Modal({
|
||||||
title: "Restore document"
|
title: "Restore document"
|
||||||
message: "Are you sure you want to restore <strong>#{name}</strong> to before the changes on #{date}?"
|
message: "Are you sure you want to restore <strong>#{name}</strong> to before the changes on #{date}?"
|
||||||
|
@ -169,24 +179,12 @@ define [
|
||||||
callback: ($button) =>
|
callback: ($button) =>
|
||||||
$button.text("Restoring...")
|
$button.text("Restoring...")
|
||||||
$button.prop("disabled", true)
|
$button.prop("disabled", true)
|
||||||
@doRestore change.get("version"), (error) =>
|
diff.restore (error) =>
|
||||||
modal.remove()
|
modal.remove()
|
||||||
@hide()
|
@hide()
|
||||||
}]
|
}]
|
||||||
})
|
})
|
||||||
|
|
||||||
doRestore: (version, callback = (error) ->) ->
|
|
||||||
$.ajax {
|
|
||||||
url: "/project/#{@project_id}/doc/#{@doc_id}/version/#{version}/restore"
|
|
||||||
type: "POST"
|
|
||||||
headers:
|
|
||||||
"X-CSRF-Token": window.csrfToken
|
|
||||||
success: () ->
|
|
||||||
callback()
|
|
||||||
error: (error) ->
|
|
||||||
callback(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
enable: () ->
|
enable: () ->
|
||||||
@enabled = true
|
@enabled = true
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,15 @@ define [
|
||||||
"libs/backbone"
|
"libs/backbone"
|
||||||
], (User) ->
|
], (User) ->
|
||||||
Diff = Backbone.Model.extend
|
Diff = Backbone.Model.extend
|
||||||
|
initialize: (attributes, options) ->
|
||||||
|
@ide = options.ide
|
||||||
|
@set "doc", @ide.fileTreeManager.getEntity(@get("doc_id"))
|
||||||
|
|
||||||
url: () ->
|
url: () ->
|
||||||
"/project/#{@get("project_id")}/doc/#{@get("doc_id")}/diff?from=#{@get("from")}&to=#{@get("to")}"
|
url = "/project/#{@get("project_id")}/doc/#{@get("doc_id")}/diff"
|
||||||
|
if @get("from")? and @get("to")?
|
||||||
|
url += "?from=#{@get("from")}&to=#{@get("to")}"
|
||||||
|
return url
|
||||||
|
|
||||||
parse: (diff) ->
|
parse: (diff) ->
|
||||||
for entry in diff.diff
|
for entry in diff.diff
|
||||||
|
@ -14,3 +21,15 @@ define [
|
||||||
else
|
else
|
||||||
entry.meta.user = User.getAnonymousUser()
|
entry.meta.user = User.getAnonymousUser()
|
||||||
return diff
|
return diff
|
||||||
|
|
||||||
|
restore: (callback = (error) ->) ->
|
||||||
|
$.ajax {
|
||||||
|
url: "/project/#{@get("project_id")}/doc/#{@get("doc_id")}/version/#{@get("from")}/restore"
|
||||||
|
type: "POST"
|
||||||
|
headers:
|
||||||
|
"X-CSRF-Token": window.csrfToken
|
||||||
|
success: () ->
|
||||||
|
callback()
|
||||||
|
error: (error) ->
|
||||||
|
callback(error)
|
||||||
|
}
|
||||||
|
|
|
@ -8,11 +8,10 @@
|
||||||
left: 0;
|
left: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
padding: 0px 12px;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
.ace_editor {
|
.ace_editor {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 30px;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
@ -20,6 +19,30 @@
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.track-changes-diff-toolbar {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: -1px;
|
||||||
|
height: 20px;
|
||||||
|
padding: 5px 5px 5px 5px;
|
||||||
|
margin: 0;
|
||||||
|
background-color: #282828;
|
||||||
|
color: white;
|
||||||
|
border-right: 1px solid white;
|
||||||
|
.number-of-changes, .restore {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
.number-of-changes {
|
||||||
|
left: 10px;
|
||||||
|
bottom: 7px;
|
||||||
|
}
|
||||||
|
.restore {
|
||||||
|
right: 10px;
|
||||||
|
bottom: 5px;
|
||||||
|
padding: 3px 9px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.track-changes-side-bar {
|
.track-changes-side-bar {
|
||||||
|
@ -181,11 +204,10 @@
|
||||||
li.selected-change-from {
|
li.selected-change-from {
|
||||||
.change-selectors {
|
.change-selectors {
|
||||||
.range {
|
.range {
|
||||||
bottom: 37px;
|
bottom: 10px;
|
||||||
}
|
}
|
||||||
.change-selector-from {
|
.change-selector-from {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
bottom: 32px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.restore {
|
.restore {
|
||||||
|
@ -230,12 +252,5 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
li.selected-change-from.hover-selected-from {
|
|
||||||
.change-selectors {
|
|
||||||
.range {
|
|
||||||
bottom: 37px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue