This commit is contained in:
lxsang 2018-09-16 18:30:53 +00:00
commit c979f93b6d
15 changed files with 370 additions and 226 deletions

View File

@ -0,0 +1,14 @@
![](https://os.lxsang.me/repo/OpenPage/OpenPage.png)
# OpenPage: ODT (Open Document Text) editor alpha
**OpenPage** is an AntOS application developed in-browser using AntOSDK. It is a Pure Javascript based rich text editor compatible with Open Document Format.
**Feature:**
* Open, view and edit *.odt* documents
* Offer various formatting style to text
* Define and apply paragraph styles
* Insert link, image
* Embeded fonts
* Save documents as ODF format so that it can be compatible with desktop applications like Open Office
**Credit:**
OpenPage is heavily based on the WebODF javascript library: https://webodf.org

BIN
OpenPage/assets/blank.odt Normal file

Binary file not shown.

BIN
OpenPage/assets/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1,24 +0,0 @@
# OpenPage
This is an example project, generated by AntOS Development Kit
## Howto
1. Open the project.apj file with AntOSDK (simply double Click on it)
2. Modify the UI in *assets/scheme.html*
3. Modify application code in *coffees/main.coffee*
4. Modify CSS style in *css/main.css*
5. Other files need to be copied: put in to assets
## Set up build target
Click **Menu> Build > Build Option** or simply hit **ALT-Y**
In the build options dialog, add or remove files that need to be
included into the build
Click **Save**
## Build application
* To build: **Menu > Build > Build** or **ALT-C**
* To build and run: **Menu > Build > Build and Run** or **CTRL-R**
* To release: **Menu > Build > Build release** or **ALT-P**

View File

@ -1,77 +0,0 @@
afx-app-window[data-id="OpenPage"] div[data-id="container"]
{
overflow: auto;
margin:0px;
padding:0px;
padding-top: 10px;
padding-bottom: 10px;
text-align: center;
background-color: #f2f1f0;
}
afx-app-window[data-id="OpenPage"] div[data-id="odfcanvas"]
{
cursor: text;
margin:auto;
box-shadow: 1px 1px 3px 3px #9f9F9F;
}
afx-app-window[data-id="OpenPage"] afx-hbox[data-id="toolbox"]
{
background-color: #f5f5f5;
border: 1px solid #eaeaea;
box-shadow: 3px 3px 3px #9f9F9F;
}
afx-app-window[data-id="OpenPage"] afx-hbox[data-id="status-bar"]
{
background-color: #f5f5f5;
border: 1px solid #eaeaea;
box-shadow: -3px -3px 3px #9f9F9F;
}
afx-app-window[data-id="OpenPage"] afx-hbox[data-id="toolbox"] afx-button button, afx-app-window[data-id="OpenPage"] afx-button[data-id="btzoomfix"] button
{
border: 1px solid #f5f5f5;
background-color: transparent;
width:100%;
height: 100%;
}
afx-app-window[data-id="OpenPage"] afx-hbox[data-id="toolbox"] afx-button button:hover, afx-app-window[data-id="OpenPage"] afx-hbox[data-id="toolbox"] afx-button button.btactive, afx-app-window[data-id="OpenPage"] afx-button[data-id="btzoomfix"] button:hover
{
border: 1px solid #759DC0;
background-color: transparent;
border-radius:5px;
color:#759DC0;
}
afx-app-window[data-id="HyperLinkDialog"] afx-label.header span
{
font-weight: bold;
}
afx-app-window[data-id="FormatDialog"] afx-label.header
{
padding-left: 5px;
border-bottom: 1px solid #a6a6a6;
}
afx-app-window[data-id="FormatDialog"] afx-label.header span
{
font-weight: bold;
}
afx-app-window[data-id="FormatDialog"] afx-hbox[data-id="aligmentbox"] afx-label span,
afx-app-window[data-id="FormatDialog"] afx-hbox[data-id="spacingbox"] afx-label span,
afx-app-window[data-id="FormatDialog"] afx-hbox[data-id="stylebox"] afx-label span
{
display: block;
padding-top: 7px;
}
afx-app-window[data-id="FormatDialog"] div[data-id="preview"]
{
border: 1px solid #a6a6a6;
}
afx-app-window[data-id="FormatDialog"] div[data-id="txtcolor"],
afx-app-window[data-id="FormatDialog"] div[data-id="bgcolor"]
{
border:1px solid #a6a6a6;
display: block;
}

View File

@ -1,13 +0,0 @@
{
"app":"OpenPage",
"name":"OpenPage",
"description":"",
"info":{
"author": "",
"email": ""
},
"version":"0.0.1-a",
"category":"Other",
"iconclass":"fa fa-adn",
"mimes":["none"]
}

View File

@ -1,47 +0,0 @@
<afx-app-window apptitle="Open Page" width="650" height="500" data-id="OpenPage">
<afx-hbox >
<afx-vbox>
<afx-hbox data-id="toolbox" data-height="28">
<div data-width="5"></div>
<afx-button data-width = "25" data-id="btundo" iconclass = "fa fa-undo"></afx-button>
<afx-button data-width = "25" data-id="btredo" iconclass = "fa fa-rotate-right" ></afx-button>
<afx-button data-width = "25" data-id="btbold" iconclass = "fa fa-bold"></afx-button>
<afx-button data-width = "25" data-id="btitalic" iconclass = "fa fa-italic"></afx-button>
<afx-button data-width = "25" data-id="btunderline" iconclass = "fa fa-underline"></afx-button>
<afx-button data-width = "25" data-id="btstrike" iconclass = "fa fa-strikethrough"></afx-button>
<afx-button data-width = "25" data-id="btnote" iconclass = "fa fa-sticky-note"></afx-button>
<afx-button data-width = "25" data-id="btlink" iconclass = "fa fa-link"></afx-button>
<afx-button data-width = "25" data-id="btunlink" iconclass = "fa fa-unlink"></afx-button>
<afx-button data-width = "25" data-id="btimage" iconclass = "fa fa-image"></afx-button>
<afx-button data-width = "25" data-id="btac" iconclass = "fa fa-align-center"></afx-button>
<afx-button data-width = "25" data-id="btal" iconclass = "fa fa-align-left" ></afx-button>
<afx-button data-width = "25" data-id="btar" iconclass = "fa fa-align-right"></afx-button>
<afx-button data-width = "25" data-id="btaj" iconclass = "fa fa-align-justify"></afx-button>
<afx-button data-width = "25" data-id="btindent" iconclass = "fa fa-indent"></afx-button>
<afx-button data-width = "25" data-id="btoutdent" iconclass = "fa fa-outdent"></afx-button>
<afx-button data-width = "25" data-id="btformat" iconclass = "fa fa-paint-brush"></afx-button>
<afx-list-view dropdown = "true" data-width="100" data-id="format-list"></afx-list-view>
<div data-width="5"></div>
<afx-nspinner data-width = "50" data-id="font-size" ></afx-nspinner>
<div data-width="5"></div>
<afx-list-view dropdown = "true" data-width="150" data-id="font-list"></afx-list-view>
<div data-width="5"></div>
</afx-hbox>
<div data-height="5"></div>
<div data-id="container">
<div data-id="odfcanvas"></div>
</div>
<div data-height="5"></div>
<afx-hbox data-id="status-bar" data-height="28">
<div></div>
<afx-button data-width = "25" data-id="btzoomfix" iconclass = "fa fa-arrows-alt"></afx-button>
<div data-width="5"></div>
<afx-slider data-id="slzoom" data-width="150" max="400"></afx-slider>
<div data-width="5"></div>
<afx-label data-id = "lbzoom" data-width="40"></afx-label>
</afx-hbox>
</afx-vbox>
</afx-hbox>
</afx-app-window>

View File

@ -49,6 +49,12 @@ class FormatDialog extends this.OS.GUI.BaseDialog
right: @find("spnright"), right: @find("spnright"),
top: @find("spntop"), top: @find("spntop"),
bottom: @find("spnbottom"), bottom: @find("spnbottom"),
lineheight: @find("spnlheight")
padding:
left: @find("pspnleft"),
right: @find("pspnright"),
top: @find("pspntop"),
bottom: @find("pspnbottom"),
style: style:
bold: @find("swbold"), bold: @find("swbold"),
italic: @find("switalic"), italic: @find("switalic"),
@ -59,10 +65,25 @@ class FormatDialog extends this.OS.GUI.BaseDialog
family: @find("lstfont"), family: @find("lstfont"),
size: @find("spnfsize") size: @find("spnfsize")
formats: @find("lstformats") formats: @find("lstformats")
@initStyleObject()
@preview = ($(@find "preview").find "p")[0]
$(@preview)
.css "padding", "0"
.css "margin", "0"
@initUIEvent()
#@previewStyle()
initStyleObject: ()->
# init the format object # init the format object
@currentStyle = @currentStyle =
aligment: @_api.switcher("left", "right", "center", "justify"), aligment: @_api.switcher("left", "right", "center", "justify"),
spacing: spacing:
left:0
top:0,
right:0,
bottom:0,
lineheight: 0
padding:
left:0 left:0
top:0, top:0,
right:0, right:0,
@ -76,12 +97,6 @@ class FormatDialog extends this.OS.GUI.BaseDialog
font: font:
family: undefined, family: undefined,
size: 12 size: 12
@preview = ($(@find "preview").find "p")[0]
$(@preview)
.css "padding", "0"
.css "margin", "0"
@initUIEvent()
@previewStyle()
initUIEvent: () -> initUIEvent: () ->
me = @ me = @
@ -96,6 +111,8 @@ class FormatDialog extends this.OS.GUI.BaseDialog
set "onchange", "aligment", k, ((e) -> e.data) set "onchange", "aligment", k, ((e) -> e.data)
for k,v of @ui.spacing for k,v of @ui.spacing
set "onchange", "spacing", k set "onchange", "spacing", k
for k,v of @ui.padding
set "onchange", "padding", k
for k,v of @ui.style for k,v of @ui.style
set "onchange", "style", k, ((e) -> e.data) if k isnt "color" and k isnt "bgcolor" set "onchange", "style", k, ((e) -> e.data) if k isnt "color" and k isnt "bgcolor"
set "onchange", "font", "size" set "onchange", "font", "size"
@ -116,14 +133,88 @@ class FormatDialog extends this.OS.GUI.BaseDialog
@ui.formats.set "onlistselect", (e) -> @ui.formats.set "onlistselect", (e) ->
me.fromODFStyleFormat e.data me.fromODFStyleFormat e.data
@ui.formats.set "selected", 0 @ui.formats.set "selected", 0
#@currentStyle = (@find "btok").set "onbtclick", (e) ->
me.saveCurrentStyle()
(@find "btx").set "onbtclick", (e) ->
me.quit()
(@find "bt-clone").set "onbtclick", (e) ->
me.clone()
clone: ()->
me = @
selected = @ui.formats.get "selected"
return unless selected
@openDialog "PromptDialog", (d) ->
return me.notify __("Abort: no style name is specified") unless d and d.trim() isnt ""
newstyle = me.parent.editorSession.cloneParagraphStyle selected.name, d
me.ui.formats.push { text:d, name: newstyle }
me.ui.formats.set "selected", ((me.ui.formats.get 'count') - 1)
me.notify __("New style: {0} added", newstyle)
, __("Clone style: {0}", selected.text), { label: __("New style name:") }
saveCurrentStyle: () ->
selected = @ui.formats.get "selected"
return unless selected
odfs =
"style:paragraph-properties":
"fo:margin-top": @currentStyle.spacing.top + "mm"
"fo:margin-left": @currentStyle.spacing.left + "mm"
"fo:margin-bottom": @currentStyle.spacing.bottom + "mm"
"fo:margin-right": @currentStyle.spacing.right + "mm"
"fo:padding-top": @currentStyle.padding.top + "mm"
"fo:padding-left": @currentStyle.padding.left + "mm"
"fo:padding-bottom": @currentStyle.padding.bottom + "mm"
"fo:padding-right": @currentStyle.padding.right + "mm"
"fo:line-height": if @currentStyle.spacing.lineheight > 0 then @currentStyle.spacing.lineheight + "mm" else "normal"
"fo:text-align": @currentStyle.aligment.selected || "left"
"style:text-properties":
"fo:font-weight": if @currentStyle.style.bold then "bold" else "normal"
"fo:font-style": if @currentStyle.style.italic then "italic" else "normal"
"style:text-underline-style": if @currentStyle.style.underline then "solid" else "none"
"fo:font-size": @currentStyle.font.size + "pt"
"fo:font-name": @currentStyle.font.family.text
"fo:color": if @currentStyle.style.color then @currentStyle.style.color.hex else "#000000"
"fo:background-color": if @currentStyle.style.bgcolor then @currentStyle.style.bgcolor.hex else "transparent"
@parent.editorSession.updateParagraphStyle selected.name, odfs
@notify __("Paragraph format [{0}] is saved", selected.text)
fromODFStyleFormat: (odfs) -> fromODFStyleFormat: (odfs) ->
console.log "change style" me = @
console.log odfs @initStyleObject()
cssUnits = new core.CSSUnits()
findFont = (name) ->
items = me.ui.font.family.get "items"
item = v for v in items when v.text is name
return undefined unless item
return item
# spacing
style = @parent.editorSession.getParagraphStyleAttributes(odfs.name)['style:paragraph-properties']
if style
@currentStyle.spacing.top = cssUnits.convertMeasure(style['fo:margin-top'], 'mm') || 0
@currentStyle.spacing.left = cssUnits.convertMeasure(style['fo:margin-left'], 'mm') || 0
@currentStyle.spacing.right = cssUnits.convertMeasure(style['fo:margin-right'], 'mm') || 0
@currentStyle.spacing.bottom = cssUnits.convertMeasure(style['fo:margin-bottom'], 'mm') || 0
@currentStyle.padding.top = cssUnits.convertMeasure(style['fo:padding-top'], 'mm') || 0
@currentStyle.padding.left = cssUnits.convertMeasure(style['fo:padding-left'], 'mm') || 0
@currentStyle.padding.right = cssUnits.convertMeasure(style['fo:padding-right'], 'mm') || 0
@currentStyle.padding.bottom = cssUnits.convertMeasure(style['fo:padding-bottom'], 'mm') || 0
@currentStyle.spacing.lineheight = cssUnits.convertMeasure(style['fo:line-height'], 'mm') || 4.2 # 1em = 4,2175176mm
@currentStyle.aligment[style['fo:text-align']] = true if style['fo:text-align']
style = @parent.editorSession.getParagraphStyleAttributes(odfs.name)['style:text-properties']
if style
@currentStyle.style.bold = style['fo:font-weight'] is 'bold'
@currentStyle.style.italic = style['fo:font-style'] is 'italic'
@currentStyle.style.underline = true if style['style:text-underline-style'] and style['style:text-underline-style'] isnt 'none'
@currentStyle.font.size = parseFloat style['fo:font-size']
@currentStyle.font.family = findFont style['style:font-name']
@currentStyle.style.color = { hex: style['fo:color'] } if style['fo:color']
@currentStyle.style.bgcolor = { hex: style['fo:background-color'] } if style['fo:background-color']
@previewStyle()
previewStyle: () -> previewStyle: () ->
console.log "previewing" #console.log "previewing"
# reset ui # reset ui
@ui.aligment.left.set "swon", @currentStyle.aligment.left @ui.aligment.left.set "swon", @currentStyle.aligment.left
@ui.aligment.right.set "swon", @currentStyle.aligment.right @ui.aligment.right.set "swon", @currentStyle.aligment.right
@ -133,45 +224,62 @@ class FormatDialog extends this.OS.GUI.BaseDialog
@ui.spacing.right.set "value", @currentStyle.spacing.right @ui.spacing.right.set "value", @currentStyle.spacing.right
@ui.spacing.top.set "value", @currentStyle.spacing.top @ui.spacing.top.set "value", @currentStyle.spacing.top
@ui.spacing.bottom.set "value", @currentStyle.spacing.bottom @ui.spacing.bottom.set "value", @currentStyle.spacing.bottom
@ui.spacing.lineheight.set "value", @currentStyle.spacing.lineheight
@ui.padding.left.set "value", @currentStyle.padding.left
@ui.padding.right.set "value", @currentStyle.padding.right
@ui.padding.top.set "value", @currentStyle.padding.top
@ui.padding.bottom.set "value", @currentStyle.padding.bottom
@ui.style.bold.set "swon", @currentStyle.style.bold @ui.style.bold.set "swon", @currentStyle.style.bold
@ui.style.italic.set "swon", @currentStyle.style.italic @ui.style.italic.set "swon", @currentStyle.style.italic
@ui.style.underline.set "swon", @currentStyle.style.underline @ui.style.underline.set "swon", @currentStyle.style.underline
@ui.font.size.set "value", @currentStyle.font.size @ui.font.size.set "value", @currentStyle.font.size
#console.log @currentStyle
if @currentStyle.font.family
items = @ui.font.family.get "items" items = @ui.font.family.get "items"
item = i for v, i in items when v.name is name item = i for v, i in items when v.text is @currentStyle.font.family.text
@ui.font.family.set "selected", item if item >= 0 @ui.font.family.set "selected", item if item >= 0
$(@ui.style.color).css "background-color", @currentStyle.style.color.hex if @currentStyle.style.color $(@ui.style.color).css "background-color", if @currentStyle.style.color then @currentStyle.style.color.hex else "#000000"
$(@ui.style.bgcolor).css "background-color", @currentStyle.style.bgcolor.hex if @currentStyle.style.bgcolor $(@ui.style.bgcolor).css "background-color", if @currentStyle.style.bgcolor then @currentStyle.style.bgcolor.hex else "white"
# set the preview css # set the preview css
el = $ @preview el = $ @preview
el.css "text-align", @currentStyle.aligment.selected el.css "text-align", if @currentStyle.aligment.selected then @currentStyle.aligment.selected else "left"
el.css "padding-left", @currentStyle.spacing.left + "mm" el.css "margin-left", @currentStyle.spacing.left + "mm"
el.css "padding-right", @currentStyle.spacing.right + "mm" el.css "margin-right", @currentStyle.spacing.right + "mm"
el.css "padding-top", @currentStyle.spacing.top + "mm" el.css "margin-top", @currentStyle.spacing.top + "mm"
el.css "padding-bottom", @currentStyle.spacing.bottom + "mm" el.css "margin-bottom", @currentStyle.spacing.bottom + "mm"
el.css "padding-left", @currentStyle.padding.left + "mm"
el.css "padding-right", @currentStyle.padding.right + "mm"
el.css "padding-top", @currentStyle.padding.top + "mm"
el.css "padding-bottom", @currentStyle.padding.bottom + "mm"
el el
.css "font-weight", "normal" .css "font-weight", "normal"
.css "font-style", "normal" .css "font-style", "normal"
.css "text-decoration", "none" .css "text-decoration", "none"
.css "line-height", "normal"
el.css "font-weight", "bold" if @currentStyle.style.bold el.css "font-weight", "bold" if @currentStyle.style.bold
el.css "font-style", "italic" if @currentStyle.style.italic el.css "font-style", "italic" if @currentStyle.style.italic
el.css "text-decoration", "underline" if @currentStyle.style.underline el.css "text-decoration", "underline" if @currentStyle.style.underline
el.css "color", @currentStyle.style.color.hex if @currentStyle.style.color el.css "color", if @currentStyle.style.color then @currentStyle.style.color.hex else "#000000"
el.css "background-color", @currentStyle.style.bgcolor.hex if @currentStyle.style.bgcolor el.css "background-color", if @currentStyle.style.bgcolor then @currentStyle.style.bgcolor.hex else "transparent"
el.css "font-size", @currentStyle.font.size + "pt" el.css "font-size", @currentStyle.font.size + "pt"
el.css "font-family", @currentStyle.font.family.name if @currentStyle.font.family el.css "font-family", @currentStyle.font.family.name if @currentStyle.font.family
el.css "line-height", @currentStyle.spacing.lineheight + "mm" if @currentStyle.spacing.lineheight > 0
FormatDialog.scheme = """ FormatDialog.scheme = """
<afx-app-window apptitle="__(Format Dialog)" width="500" height="450" data-id="FormatDialog"> <afx-app-window apptitle="__(Format Dialog)" width="500" height="500" data-id="FormatDialog">
<afx-vbox> <afx-vbox>
<div data-height="5"></div> <div data-height="5"></div>
<afx-hbox data-height="30"> <afx-hbox data-height="30">
<div data-width="5"></div> <div data-width="5"></div>
<afx-list-view data-id="lstformats" dropdown = "true"></afx-list-view> <afx-list-view data-id="lstformats" dropdown = "true"></afx-list-view>
<div data-width="5" ></div> <div data-width="5" ></div>
<afx-button text="clone" data-id="bt-clone" iconclass = "fa fa-copy" data-width="60"></afx-button> <afx-button text="clone" data-id="bt-clone" iconclass = "fa fa-copy" data-width="65"></afx-button>
<div data-width="5"></div> <div data-width="5"></div>
</afx-hbox> </afx-hbox>
<afx-label text="__(Aligment)" class="header" data-height="20"></afx-label> <afx-label text="__(Aligment)" class="header" data-height="20"></afx-label>
@ -188,7 +296,7 @@ FormatDialog.scheme = """
<div data-width="20" ></div> <div data-width="20" ></div>
</afx-hbox> </afx-hbox>
<div data-height="5"></div> <div data-height="5"></div>
<afx-label text="__(Spacing)" class="header" data-height="20"></afx-label> <afx-label text="__(Margin)" class="header" data-height="20"></afx-label>
<div data-height="5"></div> <div data-height="5"></div>
<afx-hbox data-height="23" data-id="spacingbox"> <afx-hbox data-height="23" data-id="spacingbox">
<div ></div> <div ></div>
@ -205,6 +313,25 @@ FormatDialog.scheme = """
<afx-nspinner data-width="50" data-id="spnbottom" step="0.5"></afx-nspinner> <afx-nspinner data-width="50" data-id="spnbottom" step="0.5"></afx-nspinner>
<div ></div> <div ></div>
</afx-hbox> </afx-hbox>
<div data-height="5"></div>
<afx-label text="__(Padding)" class="header" data-height="20"></afx-label>
<div data-height="5"></div>
<afx-hbox data-height="23" data-id="spacingbox">
<div ></div>
<afx-label data-width="50" text="__(Left:)"></afx-label>
<afx-nspinner data-width="50" data-id="pspnleft" step="0.5"></afx-nspinner>
<div></div>
<afx-label data-width="50" text="__(Right:)"></afx-label>
<afx-nspinner data-width="50" data-id="pspnright" step="0.5"></afx-nspinner>
<div></div>
<afx-label data-width="50" text="__(Top:)"></afx-label>
<afx-nspinner data-width="50" data-id="pspntop" step="0.5"></afx-nspinner>
<div></div>
<afx-label data-width="50" text="__(Bottom:)"></afx-label>
<afx-nspinner data-width="50" data-id="pspnbottom" step="0.5"></afx-nspinner>
<div ></div>
</afx-hbox>
<div data-height="5"></div> <div data-height="5"></div>
<afx-label text="__(Style)" class="header" data-height="20"></afx-label> <afx-label text="__(Style)" class="header" data-height="20"></afx-label>
<div data-height="5"></div> <div data-height="5"></div>
@ -226,13 +353,16 @@ FormatDialog.scheme = """
<div data-height="5"></div> <div data-height="5"></div>
<afx-label text="__(Font)" class="header" data-height="20"></afx-label> <afx-label text="__(Font)" class="header" data-height="20"></afx-label>
<div data-height="5"></div> <div data-height="5"></div>
<afx-hbox data-height="30"> <afx-hbox data-height="30" data-id="font-box">
<div data-width="5"></div> <div data-width="5"></div>
<afx-list-view data-id="lstfont" dropdown = "true"></afx-list-view> <afx-list-view data-id="lstfont" dropdown = "true"></afx-list-view>
<div data-width="5" ></div> <div data-width="5" ></div>
<afx-label data-width="35" text="__(Size:)"></afx-label> <afx-label data-width="35" text="__(Size:)"></afx-label>
<afx-nspinner data-width="50" data-id="spnfsize"></afx-nspinner> <afx-nspinner data-width="50" data-id="spnfsize"></afx-nspinner>
<div data-width="5" ></div> <div data-width="5" ></div>
<afx-label data-width="80" text="__(Line Height:)"></afx-label>
<afx-nspinner data-width="50" data-id="spnlheight" value="4.2" step="0.2"></afx-nspinner>
<div data-width="5"></div>
</afx-hbox> </afx-hbox>
<div data-height="5"></div> <div data-height="5"></div>
<afx-label text="__(Preview)" class="header" data-height="20"></afx-label> <afx-label text="__(Preview)" class="header" data-height="20"></afx-label>
@ -248,7 +378,7 @@ FormatDialog.scheme = """
<div data-height="5"></div> <div data-height="5"></div>
<afx-hbox data-height="30"> <afx-hbox data-height="30">
<div></div> <div></div>
<afx-button text="__(Ok)" data-width="30" data-id="btok"></afx-button> <afx-button text="__(Save)" data-width="35" data-id="btok"></afx-button>
<div data-width="5"></div> <div data-width="5"></div>
<afx-button text="__(Cancel)" data-width="55" data-id="btx"></afx-button> <afx-button text="__(Cancel)" data-width="55" data-id="btx"></afx-button>
</afx-hbox> </afx-hbox>

View File

@ -4,18 +4,100 @@ class OpenPage extends this.OS.GUI.BaseApplication
main: () -> main: () ->
# load session class # load session class
if not OpenPage.EditorSession #if not OpenPage.EditorSession
require ["webodf/editor/EditorSession"], (ES) -> # require ["webodf/editor/EditorSession"], (ES) ->
OpenPage.EditorSession = ES # OpenPage.EditorSession = ES
@userid = @systemsetting.user.username me =@
@eventSubscriptions = new core.EventSubscriptions() @eventSubscriptions = new core.EventSubscriptions()
@initToolbox() @initToolbox()
@initCanvas() @userid = "#{@systemsetting.user.username}@#{@pid}"
@canvas.load "#{@_api.handler.get}/home://welcome.odt" #file = "home://welcome.odt"
#file = "#{@_api.handler.get}/home://welcome.odt"
#@canvas.load file
#odfContainer = new odf.OdfContainer file, (c) ->
# me.canvas.setOdfContainer c, false
@currentStyle = "" @currentStyle = ""
if @args and @args.length > 0 then @open @args[0] else @newdoc()
@resource = @resource =
fonts: [] fonts: []
formats: [] formats: []
@bindKey "ALT-N", () -> me.actionFile "#{me.name}-New"
@bindKey "ALT-O", () -> me.actionFile "#{me.name}-Open"
@bindKey "CTRL-S", () -> me.actionFile "#{me.name}-Save"
@bindKey "ALT-W", () -> me.actionFile "#{me.name}-Saveas"
menu: () ->
me = @
menu = [{
text: "__(File)",
child: [
{ 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" }
],
onmenuselect: (e) -> me.actionFile e.item.data.dataid
}]
menu
actionFile: (e) ->
me = @
saveas = () ->
me.openDialog "FileDiaLog", (d, n, p) ->
me.currfile.setPath "#{d}#{n}"
me.save()
, __("Save as"), { file: me.currfile }
switch e
when "#{@name}-Open"
@openDialog "FileDiaLog", ( d, f , p) ->
me.open p
, __("Open file"), { mimes: me.meta().mimes }
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) ->
me = @
@pathAsDataURL(p)
.then (r) ->
me.closeDocument() if me.editorSession
me.initCanvas()
OdfContainer = new odf.OdfContainer r.reader.result, (c) ->
me.canvas.setOdfContainer c, false
return me.currfile = "Untitled".asFileHandler() if b
me.currfile.setPath p
me.scheme.set "apptitle", me.currfile.basename
me.notify __("File {0} opened", p)
.catch (e) ->
me.error __("Problem read file {0}", e)
save: () ->
me = @
return unless @editorSession
container = @canvas.odfContainer()
return @error __("No document container found") unless container
container.createByteArray (ba) ->
# create blob
me.currfile.cache = new Blob [ba], { type: "application/vnd.oasis.opendocument.text" }
me.currfile.write "application/vnd.oasis.opendocument.text", (r) ->
return me.error __("Cannot save file: {0}", r.error) if r.error
me.notify __("File {0} saved", me.currfile.basename)
me.scheme.set "apptitle", me.currfile.basename
me.currfile.dirty = false
me.editorFocus()
, (err) ->
@error __("Cannot create byte array from container: {0}", err|| "")
initToolbox: () -> initToolbox: () ->
me = @ me = @
@ -69,8 +151,14 @@ class OpenPage extends this.OS.GUI.BaseApplication
el.classList.add "notranslate" el.classList.add "notranslate"
@canvas = new odf.OdfCanvas(el) @canvas = new odf.OdfCanvas(el)
@documentChanged = (e) -> @documentChanged = (e) ->
return if me.currfile.dirty
me.currfile.dirty = true
me.scheme.set "apptitle", me.currfile.basename + "*"
#console.log e #console.log e
@metaChanged = (e) -> @metaChanged = (e) ->
return if me.currfile.dirty
me.currfile.dirty = true
me.scheme.set "apptitle", me.currfile.basename + "*"
#console.log e #console.log e
@textStylingChanged = (e) -> @textStylingChanged = (e) ->
me.updateToolbar e me.updateToolbar e
@ -81,13 +169,23 @@ class OpenPage extends this.OS.GUI.BaseApplication
me.currentStyle = e.styleName me.currentStyle = e.styleName
me.basictool.styles.set "selected", item me.basictool.styles.set "selected", item
@styleAdded = (e) ->
return unless e.family is 'paragraph'
items = me.basictool.styles.get "items"
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 = me.editorSession.getParagraphStyleElement e.name
dtext = el.getAttributeNS stylens, 'display-name'
me.basictool.styles.push { text: dtext , name: e.name }, true
#me.resource.formats.push {text: dtext, name:e.name}
@updateSlider = (v) -> @updateSlider = (v) ->
value = Math.floor v*100 value = Math.floor v*100
me.basictool.zoom.set "value", value me.basictool.zoom.set "value", value
zlb = me.find "lbzoom" zlb = me.find "lbzoom"
zlb.set "text", value+"%" zlb.set "text", value+"%"
#me.canvas.enableAnnotations true, true
#@canvas.enableAnnotations(true, true)
@canvas.addListener "statereadychange", ()-> @canvas.addListener "statereadychange", ()->
me.session = new ops.Session(me.canvas) me.session = new ops.Session(me.canvas)
viewOptions = viewOptions =
@ -107,6 +205,10 @@ class OpenPage extends this.OS.GUI.BaseApplication
zoomingEnabled: true, zoomingEnabled: true,
reviewModeEnabled: false reviewModeEnabled: false
}) })
me.initFontList me.editorSession.getDeclaredFonts()
me.initStyles me.editorSession.getAvailableParagraphStyles()
#fix annotation problem on canvas
#console.log $("office:body").css "background-color", "red"
# basic format # basic format
me.directFormattingCtl = me.editorSession.sessionController.getDirectFormattingController() me.directFormattingCtl = me.editorSession.sessionController.getDirectFormattingController()
me.directFormattingCtl.subscribe gui.DirectFormattingController.textStylingChanged, me.textStylingChanged me.directFormattingCtl.subscribe gui.DirectFormattingController.textStylingChanged, me.textStylingChanged
@ -119,6 +221,8 @@ class OpenPage extends this.OS.GUI.BaseApplication
me.eventSubscriptions.addFrameSubscription me.editorSession, OpenPage.EditorSession.signalParagraphChanged, ()-> me.updateHyperlinkButtons() me.eventSubscriptions.addFrameSubscription me.editorSession, OpenPage.EditorSession.signalParagraphChanged, ()-> me.updateHyperlinkButtons()
me.eventSubscriptions.addFrameSubscription me.editorSession, OpenPage.EditorSession.signalParagraphStyleModified, ()-> me.updateHyperlinkButtons() me.eventSubscriptions.addFrameSubscription me.editorSession, OpenPage.EditorSession.signalParagraphStyleModified, ()-> me.updateHyperlinkButtons()
#annotation controller
me.annotationController = me.editorSession.sessionController.getAnnotationController()
#image controller #image controller
me.imageController = me.editorSession.sessionController.getImageController() me.imageController = me.editorSession.sessionController.getImageController()
@ -132,6 +236,9 @@ class OpenPage extends this.OS.GUI.BaseApplication
me.zoomHelper.subscribe gui.ZoomHelper.signalZoomChanged, me.updateSlider me.zoomHelper.subscribe gui.ZoomHelper.signalZoomChanged, me.updateSlider
me.updateSlider me.zoomHelper.getZoomLevel() me.updateSlider me.zoomHelper.getZoomLevel()
# format controller
me.editorSession.subscribe OpenPage.EditorSession.signalCommonStyleCreated, me.styleAdded
me.editorSession.sessionController.setUndoManager new gui.TrivialUndoManager() me.editorSession.sessionController.setUndoManager new gui.TrivialUndoManager()
me.editorSession.sessionController.getUndoManager().subscribe gui.UndoManager.signalDocumentModifiedChanged, me.documentChanged me.editorSession.sessionController.getUndoManager().subscribe gui.UndoManager.signalDocumentModifiedChanged, me.documentChanged
me.editorSession.sessionController.getMetadataController().subscribe gui.MetadataController.signalMetadataChanged, me.metaChanged me.editorSession.sessionController.getMetadataController().subscribe gui.MetadataController.signalMetadataChanged, me.metaChanged
@ -144,8 +251,6 @@ class OpenPage extends this.OS.GUI.BaseApplication
} }
} }
me.session.enqueue([op]) me.session.enqueue([op])
me.initFontList me.editorSession.getDeclaredFonts()
me.initStyles me.editorSession.getAvailableParagraphStyles()
me.editorSession.sessionController.insertLocalCursor() me.editorSession.sessionController.insertLocalCursor()
me.editorSession.sessionController.startEditing() me.editorSession.sessionController.startEditing()
#console.log me.editorSession.getDeclaredFonts() #console.log me.editorSession.getDeclaredFonts()
@ -157,8 +262,9 @@ class OpenPage extends this.OS.GUI.BaseApplication
@basictool.fonts.set "items", list @basictool.fonts.set "items", list
initStyles: (list) -> initStyles: (list) ->
list.unshift {name:"", displayName: 'Default style' }
v.text = v.displayName for v in list v.text = v.displayName for v in list
@resource.formats.push { text: v.text, name: v.name, el: @editorSession.getParagraphStyleElement(v.name) } for v in list @resource.formats.push { text: v.text, name: v.name } for v in list
@basictool.styles.set "items", list @basictool.styles.set "items", list
updateToolbar: (changes) -> updateToolbar: (changes) ->
@ -215,6 +321,9 @@ class OpenPage extends this.OS.GUI.BaseApplication
ac: (e) -> ac: (e) ->
@directFormattingCtl.alignParagraphCenter() @directFormattingCtl.alignParagraphCenter()
note: (e) ->
@annotationController.addAnnotation()
aj: (e) -> aj: (e) ->
@directFormattingCtl.alignParagraphJustified() @directFormattingCtl.alignParagraphJustified()
@ -274,30 +383,37 @@ class OpenPage extends this.OS.GUI.BaseApplication
redo: (e) -> redo: (e) ->
@editorSession.redo() @editorSession.redo()
image: (e) -> pathAsDataURL: (p) ->
me = @ return new Promise (resolve, error) ->
@openDialog "FileDiaLog", (d, n, p) ->
fp = p.asFileHandler() fp = p.asFileHandler()
fp.asFileHandler().read (data) -> fp.read (data) ->
blob = new Blob [data], { type: fp.info.mime } blob = new Blob [data], { type: fp.info.mime }
reader = new FileReader() reader = new FileReader()
reader.onloadend = () -> reader.onloadend = () ->
return me.error __("Couldnt load image {0}", p) if reader.readyState isnt 2 return error(p) if reader.readyState isnt 2
# insert the image to document resolve {reader: reader, fp: fp }
reader.readAsDataURL blob
, "binary"
image: (e) ->
me = @
@openDialog "FileDiaLog", (d, n, p) ->
me.pathAsDataURL(p)
.then (r) ->
hiddenImage = new Image() hiddenImage = new Image()
hiddenImage.style.position = "absolute" hiddenImage.style.position = "absolute"
hiddenImage.style.left = "-99999px" hiddenImage.style.left = "-99999px"
document.body.appendChild hiddenImage document.body.appendChild hiddenImage
hiddenImage.onload = () -> hiddenImage.onload = () ->
content = reader.result.substring(reader.result.indexOf(",") + 1) content = r.reader.result.substring(r.reader.result.indexOf(",") + 1)
#insert image #insert image
me.textController.removeCurrentSelection() me.textController.removeCurrentSelection()
me.imageController.insertImage fp.info.mime, content, hiddenImage.width, hiddenImage.height me.imageController.insertImage r.fp.info.mime, content, hiddenImage.width, hiddenImage.height
document.body.removeChild hiddenImage document.body.removeChild hiddenImage
hiddenImage.src = reader.result hiddenImage.src = r.reader.result
.catch () ->
reader.readAsDataURL blob me.error __("Couldnt load image {0}", p)
, "binary"
, __("Select image file"), { mimes: ["image/.*"] } , __("Select image file"), { mimes: ["image/.*"] }
styles: (e) -> styles: (e) ->
@ -306,14 +422,15 @@ class OpenPage extends this.OS.GUI.BaseApplication
zoom: (e) -> zoom: (e) ->
#console.log "zooming", e #console.log "zooming", e
return unless @zoomHelper
@zoomHelper.setZoomLevel e/100.0 @zoomHelper.setZoomLevel e/100.0
format: (e) -> format: (e) ->
@openDialog new FormatDialog(), (d) -> @openDialog new FormatDialog(), (d) ->
console.log d return
, __("Add/Modify paragraph format"), @resource , __("Add/Modify paragraph format"), @resource
closeDocument: () -> closeDocument: (f) ->
# finish editing # finish editing
return unless @editorSession and @session return unless @editorSession and @session
me = @ me = @
@ -335,6 +452,7 @@ class OpenPage extends this.OS.GUI.BaseApplication
me.directFormattingCtl.unsubscribe gui.DirectFormattingController.paragraphStylingChanged, me.textStylingChanged me.directFormattingCtl.unsubscribe gui.DirectFormattingController.paragraphStylingChanged, me.textStylingChanged
me.editorSession.unsubscribe OpenPage.EditorSession.signalParagraphChanged, me.paragrahStyleChanged me.editorSession.unsubscribe OpenPage.EditorSession.signalParagraphChanged, me.paragrahStyleChanged
me.zoomHelper.unsubscribe gui.ZoomHelper.signalZoomChanged, me.updateSlider me.zoomHelper.unsubscribe gui.ZoomHelper.signalZoomChanged, me.updateSlider
me.editorSession.unsubscribe OpenPage.EditorSession.signalCommonStyleCreated, me.styleAdded
# destry editorSession # destry editorSession
me.editorSession.destroy (e) -> me.editorSession.destroy (e) ->
return me.error __("Cannot destroy editor session {0}", e) if e return me.error __("Cannot destroy editor session {0}", e) if e
@ -345,7 +463,9 @@ class OpenPage extends this.OS.GUI.BaseApplication
core.Async.destroyAll [me.canvas.destroy], (e) -> core.Async.destroyAll [me.canvas.destroy], (e) ->
return me.error __("Cannot destroy canvas {0}", e) if e return me.error __("Cannot destroy canvas {0}", e) if e
me.notify "Document closed" me.notify "Document closed"
f() if f
me.session = undefined me.session = undefined
me.annotationController = undefined
me.directFormattingCtl = undefined me.directFormattingCtl = undefined
me.textController = undefined me.textController = undefined
me.imageController = undefined me.imageController = undefined
@ -355,10 +475,18 @@ class OpenPage extends this.OS.GUI.BaseApplication
me.textStylingChanged = undefined me.textStylingChanged = undefined
me.paragrahStyleChanged = undefined me.paragrahStyleChanged = undefined
me.updateSlider = undefined me.updateSlider = undefined
me.styleAdded = undefined
me.basictool.fonts.set "selected", -1
me.basictool.styles.set "selected", -1
# #
cleanup: (e) -> cleanup: (e) ->
@closeDocument() me = @
if @editorSession
e.preventDefault()
me.closeDocument ()->
me.quit()
this.OS.register "OpenPage", OpenPage this.OS.register "OpenPage", OpenPage

View File

@ -13,7 +13,8 @@ afx-app-window[data-id="FormatDialog"] afx-label.header span
} }
afx-app-window[data-id="FormatDialog"] afx-hbox[data-id="aligmentbox"] afx-label span, afx-app-window[data-id="FormatDialog"] afx-hbox[data-id="aligmentbox"] afx-label span,
afx-app-window[data-id="FormatDialog"] afx-hbox[data-id="spacingbox"] afx-label span, afx-app-window[data-id="FormatDialog"] afx-hbox[data-id="spacingbox"] afx-label span,
afx-app-window[data-id="FormatDialog"] afx-hbox[data-id="stylebox"] afx-label span afx-app-window[data-id="FormatDialog"] afx-hbox[data-id="stylebox"] afx-label span,
afx-app-window[data-id="FormatDialog"] afx-hbox[data-id="font-box"] > div > afx-label span
{ {
display: block; display: block;
padding-top: 7px; padding-top: 7px;

View File

@ -1,3 +1,4 @@
@namespace office url(urn:oasis:names:tc:opendocument:xmlns:office:1.0);
afx-app-window[data-id="OpenPage"] div[data-id="container"] afx-app-window[data-id="OpenPage"] div[data-id="container"]
{ {
overflow: auto; overflow: auto;
@ -7,13 +8,41 @@ afx-app-window[data-id="OpenPage"] div[data-id="container"]
padding-bottom: 10px; padding-bottom: 10px;
text-align: center; text-align: center;
background-color: #f2f1f0; background-color: #f2f1f0;
/*position: relative;*/
} }
/*
@media screen, print, handheld, projection
{
office|body{
display: inline !important;
}
}*/
/*
Fix annotation problem not showing
*/
/*
afx-app-window[data-id="OpenPage"] document, afx-app-window[data-id="OpenPage"] office:body{
display: inline !important;
}
afx-app-window[data-id="OpenPage"] .annotationsPane{
right: 0 !important;
top: 0 !important;
position: absolute !important;
}*/
afx-app-window[data-id="OpenPage"] div[data-id="odfcanvas"] afx-app-window[data-id="OpenPage"] div[data-id="odfcanvas"]
{ {
cursor: text; cursor: text;
margin:auto; margin:auto;
box-shadow: 1px 1px 3px 3px #9f9F9F; box-shadow: 1px 1px 3px 3px #9f9F9F;
/*added*/
transform-origin: top center;
-webkit-transform-origin: top center;
-moz-transform-origin: top center;
-o-transform-origin: top center;
overflow: hidden;
} }
afx-app-window[data-id="OpenPage"] afx-hbox[data-id="toolbox"] afx-app-window[data-id="OpenPage"] afx-hbox[data-id="toolbox"]
@ -43,3 +72,4 @@ afx-app-window[data-id="OpenPage"] afx-hbox[data-id="toolbox"] afx-button button
border-radius:5px; border-radius:5px;
color:#759DC0; color:#759DC0;
} }

View File

@ -24,9 +24,10 @@
/*global runtime, define, document, core, odf, gui, ops*/ /*global runtime, define, document, core, odf, gui, ops*/
define("webodf/editor/EditorSession", [ /*define("webodf/editor/EditorSession", [
"dojo/text!resources/fonts/fonts.css" "dojo/text!resources/fonts/fonts.css"
], function (fontsCSS) { // fontsCSS is retrieved as a string, using dojo's text retrieval AMD plugin ],*/
this.OS.APP.OpenPage.EditorSession = (function (fontsCSS) { // fontsCSS is retrieved as a string, using dojo's text retrieval AMD plugin
"use strict"; "use strict";
runtime.loadClass("core.Async"); runtime.loadClass("core.Async");
@ -656,5 +657,5 @@ define("webodf/editor/EditorSession", [
/**@const*/EditorSession.signalUndoStackChanged = "signalUndoStackChanged"; /**@const*/EditorSession.signalUndoStackChanged = "signalUndoStackChanged";
return EditorSession; return EditorSession;
}); })("");

View File

@ -1,13 +1,13 @@
{ {
"app":"OpenPage", "app":"OpenPage",
"name":"OpenPage", "name":"OpenPage",
"description":"", "description":"Open Document Format (ODF) text editor using WebODF",
"info":{ "info":{
"author": "", "author": "Xuan Sang LE",
"email": "" "email": "xsang.le@gmail.com"
}, },
"version":"0.0.1-a", "version":"0.0.1-a",
"category":"Other", "category":"Other",
"iconclass":"fa fa-adn", "icon":"icon.png",
"mimes":["none"] "mimes":["application/vnd.oasis.opendocument.text"]
} }

View File

@ -1 +1,2 @@
{"name":"OpenPage","root":"home://workspace/OpenPage","css":["css/main.css","css/dialog.css"],"javascripts":["javascripts/webodf.js","javascripts/EditorSession.js"],"coffees":["coffees/main.coffee","coffees/dialogs.coffee"],"copies":["assets/scheme.html","package.json","README.md"]} {"name":"OpenPage","root":"home://Documents/workspace/antosdk-apps/OpenPage","css":["css/main.css","css/dialog.css"],"javascripts":["javascripts/webodf.js","javascripts/EditorSession.js"],"coffees":["coffees/main.coffee","coffees/dialogs.coffee"],"copies":["assets/scheme.html","package.json","assets/OpenPage.md","assets/icon.png"]}
>>>>>>> 56d24a53d411c877d28ed671d0f49db49a9c41b9