mirror of
https://github.com/antos-rde/antosdk-apps.git
synced 2024-11-09 15:08:27 +01:00
518 lines
22 KiB
CoffeeScript
518 lines
22 KiB
CoffeeScript
class OpenPage extends this.OS.application.BaseApplication
|
|
constructor: ( args ) ->
|
|
super "OpenPage", args
|
|
|
|
main: () ->
|
|
# load session class
|
|
#if not OpenPage.EditorSession
|
|
# require ["webodf/editor/EditorSession"], (ES) ->
|
|
# OpenPage.EditorSession = ES
|
|
|
|
@eventSubscriptions = new core.EventSubscriptions()
|
|
@initToolbox()
|
|
@userid = "#{@systemsetting.user.username}@#{@pid}"
|
|
#file = "home://welco@odt"
|
|
#file = "#{@_api.handler.get}/home://welcome.odt"
|
|
#@canvas.load file
|
|
#odfContainer = new odf.OdfContainer file, (c) ->
|
|
# @canvas.setOdfContainer c, false
|
|
@currentStyle = ""
|
|
if @args and @args.length > 0 then @open @args[0].path else @newdoc()
|
|
@resource =
|
|
fonts: []
|
|
formats: []
|
|
@bindKey "ALT-N", () => @actionFile "#{@name}-New"
|
|
@bindKey "ALT-O", () => @actionFile "#{@name}-Open"
|
|
@bindKey "CTRL-S", () => @actionFile "#{@name}-Save"
|
|
@bindKey "ALT-W", () => @actionFile "#{@name}-Saveas"
|
|
|
|
|
|
menu: () ->
|
|
|
|
menu = [{
|
|
text: "__(File)",
|
|
nodes: [
|
|
{ text: "__(New)", dataid: "#{@name}-New", shortcut: "A-N" },
|
|
{ text: "__(Open)", dataid: "#{@name}-Open", shortcut: "A-O" },
|
|
{ text: "__(Save)", dataid: "#{@name}-Save", shortcut: "C-S" },
|
|
{ text: "__(Save as)", dataid: "#{@name}-Saveas", shortcut: "A-W" }
|
|
],
|
|
onchildselect: (e) => @actionFile e.data.item.data.dataid
|
|
}]
|
|
menu
|
|
|
|
actionFile: (e) ->
|
|
|
|
saveas = () =>
|
|
@openDialog "FileDialog", { title: __("Save as"), file: @currfile }
|
|
.then (f) =>
|
|
d = f.file.path.asFileHandle()
|
|
d = d.parent() if f.file.type is "file"
|
|
@currfile.setPath "#{d.path}/#{f.name}"
|
|
@save()
|
|
switch e
|
|
when "#{@name}-Open"
|
|
@openDialog "FileDialog", { title: __("Open file"), mimes: @meta().mimes }
|
|
.then (f) =>
|
|
@open f.file.path
|
|
|
|
when "#{@name}-Save"
|
|
#@currfile.cache = @editor.value()
|
|
return @save() if @currfile.basename
|
|
saveas()
|
|
when "#{@name}-Saveas"
|
|
saveas()
|
|
when "#{@name}-New"
|
|
@newdoc()
|
|
|
|
|
|
newdoc: () ->
|
|
blank = "#{@meta().path}/blank.odt"
|
|
@open blank, true
|
|
|
|
open: (p,b) ->
|
|
|
|
@pathAsDataURL(p)
|
|
.then (r) =>
|
|
@closeDocument() if @editorSession
|
|
@initCanvas()
|
|
OdfContainer = new odf.OdfContainer r.data, (c) =>
|
|
@canvas.setOdfContainer c, false
|
|
return @currfile = "Untitled".asFileHandle() if b
|
|
if @currfile then @currfile.setPath p else @currfile = p.asFileHandle()
|
|
@scheme.apptitle = @currfile.basename
|
|
@notify __("File {0} opened", p)
|
|
.catch (e) =>
|
|
@error __("Problem read file {0}", e.toString()), e
|
|
|
|
save: () ->
|
|
|
|
return unless @editorSession
|
|
container = @canvas.odfContainer()
|
|
return @error __("No document container found") unless container
|
|
container.createByteArray (ba) =>
|
|
# create blob
|
|
@currfile.cache = new Blob [ba], { type: "application/vnd.oasis.opendocument.text" }
|
|
@currfile.write "application/vnd.oasis.opendocument.text"
|
|
.then (r) =>
|
|
@notify __("File {0} saved", @currfile.basename)
|
|
@scheme.apptitle = @currfile.basename
|
|
@currfile.dirty = false
|
|
@editorFocus()
|
|
.catch (e) =>
|
|
@error __("Cannot save file: {0}", e.toString()), e
|
|
, (err) =>
|
|
@error __("Cannot create byte array from container: {0}", err.toString() || ""), err
|
|
|
|
initToolbox: () ->
|
|
|
|
@basictool =
|
|
undo: @find("btundo"),
|
|
redo: @find("btredo"),
|
|
bold: @find("btbold"),
|
|
italic:@find("btitalic"),
|
|
underline:@find("btunderline"),
|
|
strike: @find("btstrike"),
|
|
note: @find("btnote"),
|
|
link: @find("btlink"),
|
|
unlink: @find("btunlink"),
|
|
image:@find("btimage"),
|
|
ac: @find("btac"),
|
|
al: @find("btal"),
|
|
ar: @find("btar"),
|
|
aj: @find("btaj"),
|
|
indent: @find("btindent"),
|
|
outdent: @find("btoutdent"),
|
|
fonts: @find("font-list"),
|
|
fontsize: @find("font-size"),
|
|
styles: @find("format-list"),
|
|
zoom: @find("slzoom")
|
|
format: @find("btformat")
|
|
|
|
fn = (name, el) =>
|
|
if name is "fonts" or name is "styles"
|
|
act = "onlistselect"
|
|
else if name is "fontsize" or name is "zoom"
|
|
act = "onvaluechange"
|
|
else
|
|
act = "onbtclick"
|
|
el[act] = (e) =>
|
|
return unless @directFormattingCtl
|
|
return unless @[name]
|
|
@[name](e)
|
|
@editorFocus()
|
|
for name, el of @basictool
|
|
fn name, el
|
|
|
|
(@find "btzoomfix").onbtclick = (e) => @zoom { data: 100 }
|
|
@basictool.zoom.onvaluechanging = (e) =>
|
|
zlb = @find "lbzoom"
|
|
zlb.text = Math.floor(e.data) + "%"
|
|
|
|
initCanvas: () ->
|
|
el = @find "odfcanvas"
|
|
|
|
el.setAttribute "translate", "no"
|
|
el.classList.add "notranslate"
|
|
@canvas = new odf.OdfCanvas(el)
|
|
@documentChanged = (e) =>
|
|
return if @currfile.dirty
|
|
@currfile.dirty = true
|
|
@scheme.apptitle = @currfile.basename + "*"
|
|
#console.log e
|
|
@metaChanged = (e) =>
|
|
return if @currfile.dirty
|
|
@currfile.dirty = true
|
|
@scheme.apptitle = @currfile.basename + "*"
|
|
#console.log e
|
|
@textStylingChanged = (e) =>
|
|
@updateToolbar e
|
|
@paragrahStyleChanged = (e) =>
|
|
return unless e.type is "style"
|
|
items = @basictool.styles.data
|
|
item = i for v, i in items when v.name is e.styleName
|
|
return unless item isnt undefined
|
|
@currentStyle = e.styleName
|
|
@basictool.styles.selected = item
|
|
|
|
@styleAdded = (e) =>
|
|
return unless e.family is 'paragraph'
|
|
items = @basictool.styles.data
|
|
item = v for v in items when v.name is e.name
|
|
return if item
|
|
stylens = "urn:oasis:names:tc:opendocument:xmlns:style:1.0"
|
|
el = @editorSession.getParagraphStyleElement e.name
|
|
dtext = el.getAttributeNS stylens, 'display-name'
|
|
@basictool.styles.push { text: dtext , name: e.name }, true
|
|
#@resource.formats.push {text: dtext, name:e.name}
|
|
|
|
@updateSlider = (v) =>
|
|
value = Math.floor v*100
|
|
@basictool.zoom.value = value
|
|
zlb = @find "lbzoom"
|
|
zlb.text = value + "%"
|
|
@canvas.enableAnnotations true, true
|
|
@canvas.addListener "statereadychange", ()=>
|
|
@session = new ops.Session(@canvas)
|
|
viewOptions =
|
|
editInfoMarkersInitiallyVisible: false,
|
|
caretAvatarsInitiallyVisible: false,
|
|
caretBlinksOnRangeSelect: true
|
|
|
|
@editorSession = new OpenPage.EditorSession(@session,@userid, {
|
|
viewOptions: viewOptions,
|
|
directTextStylingEnabled: true,
|
|
directParagraphStylingEnabled: true,
|
|
paragraphStyleSelectingEnabled: true,
|
|
paragraphStyleEditingEnabled: true,
|
|
imageEditingEnabled: true,
|
|
hyperlinkEditingEnabled: true,
|
|
annotationsEnabled: true,
|
|
zoomingEnabled: true,
|
|
reviewModeEnabled: false
|
|
})
|
|
@initFontList @editorSession.getDeclaredFonts()
|
|
@initStyles @editorSession.getAvailableParagraphStyles()
|
|
#fix annotation problem on canvas
|
|
#console.log $("office:body").css "background-color", "red"
|
|
# basic format
|
|
@directFormattingCtl = @editorSession.sessionController.getDirectFormattingController()
|
|
@directFormattingCtl.subscribe gui.DirectFormattingController.textStylingChanged, @textStylingChanged
|
|
@directFormattingCtl.subscribe gui.DirectFormattingController.paragraphStylingChanged, @textStylingChanged
|
|
@editorSession.subscribe OpenPage.EditorSession.signalParagraphChanged, @paragrahStyleChanged
|
|
|
|
# hyper link controller
|
|
@hyperlinkController = @editorSession.sessionController.getHyperlinkController()
|
|
@eventSubscriptions.addFrameSubscription @editorSession, OpenPage.EditorSession.signalCursorMoved, ()=> @updateHyperlinkButtons()
|
|
@eventSubscriptions.addFrameSubscription @editorSession, OpenPage.EditorSession.signalParagraphChanged, ()=> @updateHyperlinkButtons()
|
|
@eventSubscriptions.addFrameSubscription @editorSession, OpenPage.EditorSession.signalParagraphStyleModified, ()=> @updateHyperlinkButtons()
|
|
|
|
#annotation controller
|
|
@annotationController = @editorSession.sessionController.getAnnotationController()
|
|
|
|
#image controller
|
|
@imageController = @editorSession.sessionController.getImageController()
|
|
#imageController.subscribe(gui.ImageController.enabledChanged, enableButtons)
|
|
|
|
#text controller
|
|
@textController = @editorSession.sessionController.getTextController()
|
|
|
|
# zoom controller
|
|
@zoomHelper = @editorSession.getOdfCanvas().getZoomHelper()
|
|
@zoomHelper.subscribe gui.ZoomHelper.signalZoomChanged, @updateSlider
|
|
@updateSlider @zoomHelper.getZoomLevel()
|
|
|
|
# format controller
|
|
@editorSession.subscribe OpenPage.EditorSession.signalCommonStyleCreated, @styleAdded
|
|
|
|
@editorSession.sessionController.setUndoManager new gui.TrivialUndoManager()
|
|
@editorSession.sessionController.getUndoManager().subscribe gui.UndoManager.signalDocumentModifiedChanged, @documentChanged
|
|
@editorSession.sessionController.getMetadataController().subscribe gui.MetadataController.signalMetadataChanged, @metaChanged
|
|
op = new ops.OpAddMember()
|
|
op.init {
|
|
memberid: @userid,
|
|
setProperties:{
|
|
"fullName": @userid,
|
|
"color": "blue"
|
|
}
|
|
}
|
|
@session.enqueue([op])
|
|
@editorSession.sessionController.insertLocalCursor()
|
|
@editorSession.sessionController.startEditing()
|
|
@fontsize {data: @basictool.fontsize.value}
|
|
#console.log @editorSession.getDeclaredFonts()
|
|
#
|
|
|
|
initFontList: (list) ->
|
|
v.text = v.name for v in list
|
|
@resource.fonts = []
|
|
@resource.fonts.push { text: v.text, name: v.family } for v in list
|
|
@basictool.fonts.data = list
|
|
|
|
initStyles: (list) ->
|
|
list.unshift {name:"", displayName: 'Default style' }
|
|
v.text = v.displayName for v in list
|
|
@resource.formats.push { text: v.text, name: v.name } for v in list
|
|
@basictool.styles.data = list
|
|
|
|
updateToolbar: (changes) ->
|
|
# basic style
|
|
(@basictool.bold.selected = changes.isBold) if changes.hasOwnProperty 'isBold'
|
|
(@basictool.italic.selected = changes.isItalic) if changes.hasOwnProperty 'isItalic'
|
|
(@basictool.underline.selected = changes.hasUnderline) if changes.hasOwnProperty 'hasUnderline'
|
|
(@basictool.strike.selected = changes.hasStrikeThrough) if changes.hasOwnProperty 'hasStrikeThrough'
|
|
if changes.hasOwnProperty "fontSize"
|
|
size = changes.fontSize
|
|
size = 12 if size is undefined
|
|
if @basictool.fontsize.value isnt size
|
|
@basictool.fontsize.value = size
|
|
|
|
@selectFont changes.fontName if changes.hasOwnProperty "fontName"
|
|
#pharagraph style
|
|
@basictool.al.selected = changes.isAlignedLeft if changes.hasOwnProperty "isAlignedLeft"
|
|
@basictool.ar.selected = changes.isAlignedRight if changes.hasOwnProperty "isAlignedRight"
|
|
@basictool.ac.selected = changes.isAlignedCenter if changes.hasOwnProperty "isAlignedCenter"
|
|
@basictool.aj.selected = changes.isAlignedJustified if changes.hasOwnProperty "isAlignedJustified"
|
|
|
|
updateHyperlinkButtons: (e) ->
|
|
selectedLinks = @editorSession.getSelectedHyperlinks()
|
|
@basictool.unlink.enable = selectedLinks.length > 0
|
|
|
|
selectFont: (name) ->
|
|
items = @basictool.fonts.data
|
|
item = i for v, i in items when v.name is name
|
|
return unless item isnt undefined
|
|
@basictool.fonts.selected = item
|
|
|
|
editorFocus: () ->
|
|
@editorSession.sessionController.getEventManager().focus()
|
|
|
|
bold: (e) ->
|
|
#console.log @, e
|
|
@directFormattingCtl.setBold (not @basictool.bold.selected)
|
|
|
|
italic: (e) ->
|
|
@directFormattingCtl.setItalic (not @basictool.italic.selected)
|
|
|
|
underline: (e) ->
|
|
@directFormattingCtl.setHasUnderline (not @basictool.underline.selected)
|
|
|
|
strike: (e) ->
|
|
@directFormattingCtl.setHasStrikethrough (not @basictool.strike.selected)
|
|
|
|
fonts: (e) ->
|
|
@directFormattingCtl.setFontName e.data.item.data.name
|
|
|
|
fontsize: (e) ->
|
|
# present the value change from enter infinity loop
|
|
@directFormattingCtl.setFontSize e.data
|
|
|
|
al: (e) ->
|
|
@directFormattingCtl.alignParagraphLeft()
|
|
|
|
ar: (e) ->
|
|
@directFormattingCtl.alignParagraphRight()
|
|
|
|
ac: (e) ->
|
|
@directFormattingCtl.alignParagraphCenter()
|
|
|
|
note: (e) ->
|
|
@annotationController.addAnnotation()
|
|
|
|
aj: (e) ->
|
|
@directFormattingCtl.alignParagraphJustified()
|
|
|
|
indent: (e) ->
|
|
@directFormattingCtl.indent()
|
|
|
|
outdent: (e) ->
|
|
@directFormattingCtl.outdent()
|
|
|
|
link: (e) ->
|
|
# get the link first
|
|
|
|
textSerializer = new odf.TextSerializer()
|
|
selection = @editorSession.getSelectedRange()
|
|
linksInSelection = @editorSession.getSelectedHyperlinks()
|
|
linkTarget = if linksInSelection[0] then odf.OdfUtils.getHyperlinkTarget(linksInSelection[0]) else "http://"
|
|
data =
|
|
link: linkTarget,
|
|
text: "",
|
|
readonly: true,
|
|
action: "new"
|
|
if selection and selection.collapsed and linksInSelection.length == 1
|
|
# selection is collapsed within a single link
|
|
# text in this case is read only
|
|
data.text = textSerializer.writeToString linksInSelection[0]
|
|
data.action = "edit"
|
|
else if selection and !selection.collapsed
|
|
# user select part of link or a block of text
|
|
# user convert a selection to a link
|
|
data.text = textSerializer.writeToString selection.cloneContents()
|
|
else
|
|
data.readonly = false
|
|
@openDialog new HyperLinkDialog(), {title: "__(Insert/edit link)", data: data}
|
|
.then (d) =>
|
|
selectionController = @editorSession.sessionController.getSelectionController()
|
|
if d.readonly
|
|
# edit the existing link
|
|
if d.action is "edit"
|
|
selectedLinkRange = selection.cloneRange()
|
|
selectedLinkRange.selectNode(linksInSelection[0])
|
|
selectionController.selectRange(selectedLinkRange, true)
|
|
@hyperlinkController.removeHyperlinks()
|
|
@hyperlinkController.addHyperlink d.link
|
|
else
|
|
@hyperlinkController.addHyperlink d.link, d.text
|
|
linksInSelection = @editorSession.getSelectedHyperlinks()
|
|
selectedLinkRange = selection.cloneRange()
|
|
selectedLinkRange.selectNode(linksInSelection[0])
|
|
selectionController.selectRange(selectedLinkRange, true)
|
|
|
|
unlink: (e) ->
|
|
@hyperlinkController.removeHyperlinks()
|
|
|
|
undo: (e) ->
|
|
@editorSession.undo()
|
|
|
|
redo: (e) ->
|
|
@editorSession.redo()
|
|
|
|
pathAsDataURL: (p) ->
|
|
return new Promise (resolve, error) =>
|
|
fp = p.asFileHandle()
|
|
fp.read("binary").then (data) =>
|
|
blob = new Blob [data], { type: fp.info.mime }
|
|
reader = new FileReader()
|
|
reader.onloadend = () =>
|
|
return error(@throwe __("Unable to load file {0}", p)) if reader.readyState isnt 2
|
|
resolve {data: reader.result, fp: fp }
|
|
reader.readAsDataURL blob
|
|
.catch (e) => error __e e
|
|
|
|
###
|
|
if not isText
|
|
|
|
else
|
|
fp.read (data) =>
|
|
# convert to base64
|
|
b64 = btoa data
|
|
dataurl = "data:#{fp.info.mime};base64," + b64
|
|
resolve { reader: {result: dataurl}, fp:fp }
|
|
###
|
|
|
|
image: (e) ->
|
|
|
|
@openDialog "FileDialog", { title: __("Select image file"), mimes: ["image/.*"] }
|
|
.then (f) =>
|
|
p = f.file.path
|
|
@pathAsDataURL(p)
|
|
.then (r) =>
|
|
hiddenImage = new Image()
|
|
hiddenImage.style.position = "absolute"
|
|
hiddenImage.style.left = "-99999px"
|
|
document.body.appendChild hiddenImage
|
|
hiddenImage.onload = () =>
|
|
content = r.data.substring(r.data.indexOf(",") + 1)
|
|
#insert image
|
|
@textController.removeCurrentSelection()
|
|
@imageController.insertImage r.fp.info.mime, content, hiddenImage.width, hiddenImage.height
|
|
document.body.removeChild hiddenImage
|
|
hiddenImage.src = r.data
|
|
.catch (e) =>
|
|
@error __("Couldnt load image {0}", p), e
|
|
|
|
styles: (e) ->
|
|
return if e.data.item.data.name is @currentStyle
|
|
@editorSession.setCurrentParagraphStyle e.data.item.data.name
|
|
|
|
zoom: (e) ->
|
|
#console.log "zooming", e
|
|
return unless @zoomHelper
|
|
@zoomHelper.setZoomLevel e.data/100.0
|
|
|
|
format: (e) ->
|
|
@openDialog new FormatDialog(), { title: __("Add/Modify paragraph format"), data: @resource }
|
|
.then (d) =>
|
|
return
|
|
|
|
closeDocument: (f) ->
|
|
# finish editing
|
|
return unless @editorSession and @session
|
|
|
|
@eventSubscriptions.unsubscribeAll()
|
|
@editorSession.sessionController.endEditing()
|
|
@editorSession.sessionController.removeLocalCursor()
|
|
# remove user
|
|
op = new ops.OpRemoveMember()
|
|
op.init {
|
|
memberid: @userid
|
|
}
|
|
@session.enqueue [op]
|
|
# close the session
|
|
@session.close (e) =>
|
|
return @error __("Cannot close session {0}", e.toString()), e if e
|
|
@editorSession.sessionController.getMetadataController().unsubscribe gui.MetadataController.signalMetadataChanged, @metaChanged
|
|
@editorSession.sessionController.getUndoManager().unsubscribe gui.UndoManager.signalDocumentModifiedChanged, @documentChanged
|
|
@directFormattingCtl.unsubscribe gui.DirectFormattingController.textStylingChanged, @textStylingChanged
|
|
@directFormattingCtl.unsubscribe gui.DirectFormattingController.paragraphStylingChanged, @textStylingChanged
|
|
@editorSession.unsubscribe OpenPage.EditorSession.signalParagraphChanged, @paragrahStyleChanged
|
|
@zoomHelper.unsubscribe gui.ZoomHelper.signalZoomChanged, @updateSlider
|
|
@editorSession.unsubscribe OpenPage.EditorSession.signalCommonStyleCreated, @styleAdded
|
|
# destry editorSession
|
|
@editorSession.destroy (e) =>
|
|
return @error __("Cannot destroy editor session {0}", e.toString()), e if e
|
|
@editorSession = undefined
|
|
# destroy session
|
|
@session.destroy (e) =>
|
|
return @error __("Cannot destroy document session {0}", e.toString()), e if e
|
|
core.Async.destroyAll [@canvas.destroy], (e) =>
|
|
return @error __("Cannot destroy canvas {0}", e.toString()), e if e
|
|
@notify "Document closed"
|
|
f() if f
|
|
@session = undefined
|
|
@annotationController = undefined
|
|
@directFormattingCtl = undefined
|
|
@textController = undefined
|
|
@imageController = undefined
|
|
@ZoomHelper = undefined
|
|
@metaChanged = undefined
|
|
@documentChanged = undefined
|
|
@textStylingChanged = undefined
|
|
@paragrahStyleChanged = undefined
|
|
@updateSlider = undefined
|
|
@styleAdded = undefined
|
|
@basictool.fonts.selected = -1
|
|
@basictool.styles.selected = -1
|
|
|
|
#
|
|
|
|
|
|
cleanup: (e) ->
|
|
|
|
if @editorSession
|
|
e.preventDefault()
|
|
@closeDocument ()=>
|
|
@quit()
|
|
|
|
this.OS.register "OpenPage", OpenPage |