|
1243bf3…
|
stephan
|
1 |
# The fileedit Page |
|
1243bf3…
|
stephan
|
2 |
|
|
1243bf3…
|
stephan
|
3 |
This document describes the limitations of, caveats for, and |
|
1243bf3…
|
stephan
|
4 |
disclaimers for the [](/fileedit) page, which provides users with |
|
285430a…
|
drh
|
5 |
basic editing features for files via the web interface when they |
|
285430a…
|
drh
|
6 |
have [checkin privileges](./caps/index.md). |
|
1243bf3…
|
stephan
|
7 |
|
|
1243bf3…
|
stephan
|
8 |
# Important Caveats and Disclaimers |
|
1243bf3…
|
stephan
|
9 |
|
|
1243bf3…
|
stephan
|
10 |
Predictably, the ability to edit files in a repository from a web |
|
1243bf3…
|
stephan
|
11 |
browser halfway around the world comes with several obligatory caveats |
|
1243bf3…
|
stephan
|
12 |
and disclaimers... |
|
1243bf3…
|
stephan
|
13 |
|
|
66851cd…
|
wyoung
|
14 |
## <a id="cap"></a> `/fileedit` Does *Nothing* by Default. |
|
1243bf3…
|
stephan
|
15 |
|
|
1243bf3…
|
stephan
|
16 |
In order to "activate" it, a user with [the "setup" |
|
1243bf3…
|
stephan
|
17 |
permission](./caps/index.md) must set the |
|
c64f28d…
|
drh
|
18 |
[fileedit-glob](/help/fileedit-glob) repository setting to a |
|
1243bf3…
|
stephan
|
19 |
comma- or newline-delimited list of globs representing a whitelist of |
|
1243bf3…
|
stephan
|
20 |
files which may be edited online. Any user with commit access may then |
|
1243bf3…
|
stephan
|
21 |
edit files matching one of those globs. Certain pages within the UI |
|
1243bf3…
|
stephan
|
22 |
get an "edit" link added to them when the current user's permissions |
|
1243bf3…
|
stephan
|
23 |
and the whitelist both permit editing of that file. |
|
1243bf3…
|
stephan
|
24 |
|
|
66851cd…
|
wyoung
|
25 |
## <a id="csrf"></a> CSRF & HTTP Referrer Headers |
|
1243bf3…
|
stephan
|
26 |
|
|
1243bf3…
|
stephan
|
27 |
In order to protect against [Cross-site Request Forgery (CSRF)][csrf] |
|
1243bf3…
|
stephan
|
28 |
attacks, Fossil UI features which write to the database require that |
|
1243bf3…
|
stephan
|
29 |
the browser send the so-called [HTTP `Referer` header][referer] |
|
1243bf3…
|
stephan
|
30 |
(noting that the misspelling of "referrer" is a historical accident |
|
1243bf3…
|
stephan
|
31 |
which has long-since been standardized!). Modern browsers, by default, |
|
1243bf3…
|
stephan
|
32 |
include such information automatically for *interactive* actions which |
|
1243bf3…
|
stephan
|
33 |
lead to a request, e.g. clicking on a link back to the same |
|
1243bf3…
|
stephan
|
34 |
server. However, `/fileedit` uses asynchronous ["XHR"][xhr] |
|
1243bf3…
|
stephan
|
35 |
connections, which browsers *may* treat differently than strictly |
|
1243bf3…
|
stephan
|
36 |
interactive elements. |
|
1243bf3…
|
stephan
|
37 |
|
|
1243bf3…
|
stephan
|
38 |
- **Firefox**: configuration option `network.http.sendRefererHeader` |
|
1243bf3…
|
stephan
|
39 |
specifies whether the `Referer` header is sent. It must have a value |
|
1243bf3…
|
stephan
|
40 |
of 2 (which is the default) for XHR requests to get the `Referer` |
|
1243bf3…
|
stephan
|
41 |
header. Purely interactive Fossil features, in which users directly |
|
1243bf3…
|
stephan
|
42 |
activate links or forms, work with a level of 1 or higher. |
|
1243bf3…
|
stephan
|
43 |
- **Chrome**: apparently requires an add-on in order to change this |
|
1243bf3…
|
stephan
|
44 |
policy, so Chrome without such an add-on will not suppress this |
|
1243bf3…
|
stephan
|
45 |
header. |
|
1243bf3…
|
stephan
|
46 |
- **Safari**: ??? |
|
1243bf3…
|
stephan
|
47 |
- **Other browsers**: ??? |
|
1243bf3…
|
stephan
|
48 |
|
|
d400f40…
|
stephan
|
49 |
If `/fileedit` shows an error message saying "CSRF violation," the |
|
1243bf3…
|
stephan
|
50 |
problem is that the browser is not sending a `Referer` header to XHR |
|
1243bf3…
|
stephan
|
51 |
connections. Fossil does not offer a way to disable its CSRF |
|
1243bf3…
|
stephan
|
52 |
protections. |
|
1243bf3…
|
stephan
|
53 |
|
|
1243bf3…
|
stephan
|
54 |
[referer]: https://en.wikipedia.org/wiki/HTTP_referer |
|
1243bf3…
|
stephan
|
55 |
[csrf]: https://en.wikipedia.org/wiki/Cross-site_request_forgery |
|
1243bf3…
|
stephan
|
56 |
[xhr]: https://en.wikipedia.org/wiki/XMLHttpRequest |
|
1243bf3…
|
stephan
|
57 |
|
|
66851cd…
|
wyoung
|
58 |
## <a id="commit"></a> `/fileedit` **Works by Creating Commits** |
|
1243bf3…
|
stephan
|
59 |
|
|
1243bf3…
|
stephan
|
60 |
Thus any edits made via that page become a normal part of the |
|
1ddb400…
|
wyoung
|
61 |
repository. |
|
1243bf3…
|
stephan
|
62 |
|
|
66851cd…
|
wyoung
|
63 |
## <a id="intent"></a> `/fileedit` is *Intended* for use with Embedded Docs |
|
1243bf3…
|
stephan
|
64 |
|
|
1243bf3…
|
stephan
|
65 |
... and similar text files, and is most certainly |
|
1243bf3…
|
stephan
|
66 |
**not intended for editing code**. |
|
1243bf3…
|
stephan
|
67 |
|
|
1243bf3…
|
stephan
|
68 |
Editing files with unusual syntax requirements, e.g. hard tabs in |
|
1243bf3…
|
stephan
|
69 |
makefiles, may break them. *You Have Been Warned.* |
|
1243bf3…
|
stephan
|
70 |
|
|
1243bf3…
|
stephan
|
71 |
Similarly, though every effort is made to retain the end-of-line |
|
1243bf3…
|
stephan
|
72 |
style used by being-edited files, the round-trip through an HTML |
|
1243bf3…
|
stephan
|
73 |
textarea element may change the EOLs. The Commit section of the page |
|
1243bf3…
|
stephan
|
74 |
offers three different options for how to treat newlines when saving |
|
1243bf3…
|
stephan
|
75 |
changes. **Files with mixed EOL styles** *will be normalized to a single |
|
1243bf3…
|
stephan
|
76 |
EOL style* when modified using `/fileedit`. When "inheriting" the EOL |
|
1243bf3…
|
stephan
|
77 |
style from a previous version which has mixed styles, the first EOL |
|
1243bf3…
|
stephan
|
78 |
style detected in the previous version of the file is used. |
|
1243bf3…
|
stephan
|
79 |
|
|
66851cd…
|
wyoung
|
80 |
## <a id="checkout"></a> `/fileedit` **is Not a Replacement for a Checkout** |
|
1243bf3…
|
stephan
|
81 |
|
|
1243bf3…
|
stephan
|
82 |
A full-featured checkout allows far more possibilities than this basic |
|
1243bf3…
|
stephan
|
83 |
online editor permits, and the feature scope of `/fileedit` is |
|
1243bf3…
|
stephan
|
84 |
intentionally kept small, implementing only the bare necessities |
|
1243bf3…
|
stephan
|
85 |
needed for performing basic edits online. It *is not, and will never |
|
1243bf3…
|
stephan
|
86 |
be, a replacement for a checkout.* |
|
1243bf3…
|
stephan
|
87 |
|
|
1243bf3…
|
stephan
|
88 |
It is to be expected that users will want to do "more" with this |
|
1243bf3…
|
stephan
|
89 |
page, and we generally encourage feature requests, but be aware that |
|
1243bf3…
|
stephan
|
90 |
certain types of ostensibly sensible feature requests *will be |
|
1243bf3…
|
stephan
|
91 |
rejected* for `/fileedit`. These include, but are not limited to: |
|
1243bf3…
|
stephan
|
92 |
|
|
1243bf3…
|
stephan
|
93 |
- Features which are already provided by other pages, e.g. |
|
1243bf3…
|
stephan
|
94 |
the ability to create a new named branch or add tags. |
|
1243bf3…
|
stephan
|
95 |
- Features which would require re-implementing significant |
|
1243bf3…
|
stephan
|
96 |
capabilities provided only within a checkout (e.g. merging files). |
|
1243bf3…
|
stephan
|
97 |
- The ability to edit/manipulate files which are in a local |
|
1243bf3…
|
stephan
|
98 |
checkout. (If you have a checkout, use your local editor, not |
|
1243bf3…
|
stephan
|
99 |
`/fileedit`.) |
|
1243bf3…
|
stephan
|
100 |
- Editing of non-text files, e.g. images. Use a checkout and your |
|
1243bf3…
|
stephan
|
101 |
preferred graphics editor. |
|
1243bf3…
|
stephan
|
102 |
- Support for syncing/pulling/pushing of a repository before and/or |
|
1243bf3…
|
stephan
|
103 |
after edits. Those features cannot be *reliably* provided via a web |
|
1243bf3…
|
stephan
|
104 |
interface for several reasons. |
|
1243bf3…
|
stephan
|
105 |
|
|
1243bf3…
|
stephan
|
106 |
Similarly, some *potential* features have significant downsides, |
|
1243bf3…
|
stephan
|
107 |
abuses, and/or implementation hurdles which make the decision of |
|
1243bf3…
|
stephan
|
108 |
whether or not to implement them subject to notable contributor |
|
1243bf3…
|
stephan
|
109 |
debate. e.g. the ability to add new files or remove/rename older |
|
1243bf3…
|
stephan
|
110 |
files. |
|
1243bf3…
|
stephan
|
111 |
|
|
1243bf3…
|
stephan
|
112 |
|
|
66851cd…
|
wyoung
|
113 |
## <a id="storage"></a> `/fileedit` **Stores Only Limited Local Edits While Working** |
|
1243bf3…
|
stephan
|
114 |
|
|
1243bf3…
|
stephan
|
115 |
When changes are made to a given checkin/file combination, |
|
1243bf3…
|
stephan
|
116 |
`/fileedit` will, if possible, store them in [`window.localStorage` |
|
1243bf3…
|
stephan
|
117 |
or `window.sessionStorage`][html5storage], if available, but... |
|
1243bf3…
|
stephan
|
118 |
|
|
1243bf3…
|
stephan
|
119 |
- Which storage is used is unspecified and may differ across |
|
1243bf3…
|
stephan
|
120 |
environments. |
|
1243bf3…
|
stephan
|
121 |
- If neither of those is available, the storage is transient and |
|
1243bf3…
|
stephan
|
122 |
will not survive a page reload. In this case, the UI issues a clear |
|
1243bf3…
|
stephan
|
123 |
warning in the editor tab. |
|
1243bf3…
|
stephan
|
124 |
- It stores only the most recent checkin/file combinations which have |
|
1243bf3…
|
stephan
|
125 |
been modified (exactly how many may differ - the number will be |
|
1243bf3…
|
stephan
|
126 |
noted somewhere in the UI). Note that changing the "executable bit" |
|
1243bf3…
|
stephan
|
127 |
is counted as a modification, but the checkin *comment* is *not* |
|
1243bf3…
|
stephan
|
128 |
and is reset after a commit. |
|
1243bf3…
|
stephan
|
129 |
- If its internal limit on the number of modified files is exceeded, |
|
1243bf3…
|
stephan
|
130 |
it silently discards the oldest edits to keep the list at its limit. |
|
1243bf3…
|
stephan
|
131 |
|
|
1243bf3…
|
stephan
|
132 |
Edits are saved whenever the editor component fires its "change" |
|
1243bf3…
|
stephan
|
133 |
event, which essentially means as soon as it loses input focus. Thus |
|
1243bf3…
|
stephan
|
134 |
to force the browser to save any pending changes, simply click |
|
1243bf3…
|
stephan
|
135 |
somwhere on the page outside of the editor. |
|
1243bf3…
|
stephan
|
136 |
|
|
1243bf3…
|
stephan
|
137 |
Exactly how long `localStorage` will survive, and how much it or |
|
1243bf3…
|
stephan
|
138 |
`sessionStorage` can hold, is environment-dependent. `sessionStorage` |
|
1243bf3…
|
stephan
|
139 |
will survive until the current browser tab is closed, but it survives |
|
1243bf3…
|
stephan
|
140 |
across reloads of the same tab. |
|
1243bf3…
|
stephan
|
141 |
|
|
d400f40…
|
stephan
|
142 |
If `/fileedit` determines that no persistent storage is available a |
|
1243bf3…
|
stephan
|
143 |
warning is displayed on the editor page. |
|
1243bf3…
|
stephan
|
144 |
|
|
1243bf3…
|
stephan
|
145 |
[html5storage]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API |
|
1243bf3…
|
stephan
|
146 |
|
|
66851cd…
|
wyoung
|
147 |
## <a id="power"></a> The Power is Yours, but... |
|
1243bf3…
|
stephan
|
148 |
|
|
1243bf3…
|
stephan
|
149 |
> "With great power comes great responsibility." |
|
1243bf3…
|
stephan
|
150 |
|
|
1243bf3…
|
stephan
|
151 |
**Use this feature judiciously, *if at all*.** |
|
1243bf3…
|
stephan
|
152 |
|
|
1243bf3…
|
stephan
|
153 |
Now, with those warnings and caveats out of the way... |
|
1243bf3…
|
stephan
|
154 |
|
|
1243bf3…
|
stephan
|
155 |
----- |
|
1243bf3…
|
stephan
|
156 |
|
|
66851cd…
|
wyoung
|
157 |
# <a id="tips"></a> Tips and Tricks |
|
1243bf3…
|
stephan
|
158 |
|
|
66851cd…
|
wyoung
|
159 |
## <a id="global-js"></a> `fossil` Global-scope JS Object |
|
1243bf3…
|
stephan
|
160 |
|
|
1243bf3…
|
stephan
|
161 |
`/fileedit` is largely implemented in JavaScript, and makes heavy use |
|
1243bf3…
|
stephan
|
162 |
of the global-scope `fossil` object, which provides |
|
1243bf3…
|
stephan
|
163 |
infrastructure-level features intended for use by Fossil UI pages. |
|
1243bf3…
|
stephan
|
164 |
(That said, that infrastructure was introduced with `/fileedit`, and |
|
1243bf3…
|
stephan
|
165 |
most pages do not use it.) |
|
1243bf3…
|
stephan
|
166 |
|
|
1243bf3…
|
stephan
|
167 |
The `fossil.page` object represents the UI's current page (on pages |
|
1243bf3…
|
stephan
|
168 |
which make use of this API - most do not). That object supports |
|
1243bf3…
|
stephan
|
169 |
listening to page-specific events so that JS code installed via |
|
1243bf3…
|
stephan
|
170 |
[client-side edits to the site skin's footer](customskin.md) may react |
|
1243bf3…
|
stephan
|
171 |
to those changes somehow. The next section describes one such use for |
|
1243bf3…
|
stephan
|
172 |
such events... |
|
1243bf3…
|
stephan
|
173 |
|
|
66851cd…
|
wyoung
|
174 |
## <a id="syn-hl"></a> Integrating Syntax Highlighting |
|
1243bf3…
|
stephan
|
175 |
|
|
1243bf3…
|
stephan
|
176 |
Assuming a repository has integrated a 3rd-party syntax highlighting |
|
1243bf3…
|
stephan
|
177 |
solution, it can probably (depending on its API) be told how to |
|
1243bf3…
|
stephan
|
178 |
highlight `/fileedit`'s wiki/markdown-format previews. Here are |
|
1243bf3…
|
stephan
|
179 |
instructions for doing so with [highlightjs](https://highlightjs.org/): |
|
1243bf3…
|
stephan
|
180 |
|
|
1243bf3…
|
stephan
|
181 |
At the very bottom of the [site skin's footer](customskin.md), add a |
|
1243bf3…
|
stephan
|
182 |
script tag similar to the following: |
|
1243bf3…
|
stephan
|
183 |
|
|
1243bf3…
|
stephan
|
184 |
```javascript |
|
1243bf3…
|
stephan
|
185 |
<script nonce="$<nonce>"> |
|
1243bf3…
|
stephan
|
186 |
if(window.fossil && fossil.page && fossil.page.name==='fileedit'){ |
|
1243bf3…
|
stephan
|
187 |
fossil.page.addEventListener( |
|
1243bf3…
|
stephan
|
188 |
'fileedit-preview-updated', |
|
1243bf3…
|
stephan
|
189 |
(ev)=>{ |
|
1243bf3…
|
stephan
|
190 |
if(ev.detail.previewMode==='wiki'){ |
|
1243bf3…
|
stephan
|
191 |
ev.detail.element.querySelectorAll( |
|
1243bf3…
|
stephan
|
192 |
'code[class^=language-]' |
|
1243bf3…
|
stephan
|
193 |
).forEach((e)=>hljs.highlightBlock(e)); |
|
1243bf3…
|
stephan
|
194 |
} |
|
1243bf3…
|
stephan
|
195 |
} |
|
1243bf3…
|
stephan
|
196 |
); |
|
1243bf3…
|
stephan
|
197 |
} |
|
1243bf3…
|
stephan
|
198 |
</script> |
|
1243bf3…
|
stephan
|
199 |
``` |
|
1243bf3…
|
stephan
|
200 |
|
|
1243bf3…
|
stephan
|
201 |
Note that the `nonce="$<nonce>"` part is intended to be entered |
|
1243bf3…
|
stephan
|
202 |
literally as shown above. It will be expanded to contain the current |
|
1243bf3…
|
stephan
|
203 |
request's nonce value when the page is rendered. |
|
1243bf3…
|
stephan
|
204 |
|
|
1243bf3…
|
stephan
|
205 |
The first line of the script just ensures that the expected JS-level |
|
1243bf3…
|
stephan
|
206 |
infrastructure is loaded. It's only loaded in the `/fileedit` page and |
|
1243bf3…
|
stephan
|
207 |
possibly pages added or "upgraded" since `/fileedit`'s introduction. |
|
1243bf3…
|
stephan
|
208 |
|
|
d400f40…
|
stephan
|
209 |
The part in the `if` block adds an event listener to the `/fileedit` |
|
1243bf3…
|
stephan
|
210 |
app which gets called when the preview is refreshed. That event |
|
1243bf3…
|
stephan
|
211 |
contains 3 properties: |
|
1243bf3…
|
stephan
|
212 |
|
|
1243bf3…
|
stephan
|
213 |
- `previewMode`: a string describing the current preview mode: `wiki` |
|
1243bf3…
|
stephan
|
214 |
(which includes Fossil-native wiki and markdown), `text`, |
|
1243bf3…
|
stephan
|
215 |
`htmlInline`, `htmlIframe`. We should "probably" only highlight wiki |
|
1243bf3…
|
stephan
|
216 |
text, and thus the example above limits its work to that type of |
|
1243bf3…
|
stephan
|
217 |
preview. It won't work with `htmlIframe`, as that represents an |
|
1243bf3…
|
stephan
|
218 |
iframe element which contains a complete HTML document. |
|
1243bf3…
|
stephan
|
219 |
- `element`: the DOM element in which the preview is rendered. |
|
1243bf3…
|
stephan
|
220 |
- `mimetype`: the mimetype of the being-previewed content, as determined |
|
1243bf3…
|
stephan
|
221 |
by Fossil (by its file extension). |
|
1243bf3…
|
stephan
|
222 |
|
|
1243bf3…
|
stephan
|
223 |
The event listener callback shown above doesn't use the `mimetype`, |
|
285430a…
|
drh
|
224 |
but makes use of the other two. It fishes all `code` blocks out of |
|
1243bf3…
|
stephan
|
225 |
the preview which explicitly have a CSS class named |
|
1243bf3…
|
stephan
|
226 |
`language-`something, and then asks highlightjs to highlight them. |
|
1243bf3…
|
stephan
|
227 |
|
|
66851cd…
|
wyoung
|
228 |
## <a id="editor"></a> Integrating a Custom Editor Widget |
|
88703f0…
|
stephan
|
229 |
|
|
d400f40…
|
stephan
|
230 |
(These instructions also work for the `/wikiedit` page by replacing |
|
88703f0…
|
stephan
|
231 |
"fileedit" with "wikiedit" in any strings or symbol names!) |
|
1243bf3…
|
stephan
|
232 |
|
|
d400f40…
|
stephan
|
233 |
It is possible to replace `/fileedit`'s basic text-editing widget (a |
|
1243bf3…
|
stephan
|
234 |
`textarea` element) with a fancy 3rd-party editor widget by following |
|
1243bf3…
|
stephan
|
235 |
these instructions... |
|
1243bf3…
|
stephan
|
236 |
|
|
1243bf3…
|
stephan
|
237 |
All JavaScript code which follows is assumed to be in a script tag |
|
1243bf3…
|
stephan
|
238 |
similar to the one shown in the previous section: |
|
1243bf3…
|
stephan
|
239 |
|
|
1243bf3…
|
stephan
|
240 |
```javascript |
|
1243bf3…
|
stephan
|
241 |
<script nonce="$<nonce>"> |
|
1243bf3…
|
stephan
|
242 |
if(window.fossil && fossil.page && fossil.page.name==='fileedit'){ |
|
1243bf3…
|
stephan
|
243 |
// code specific to the fileedit page goes here |
|
1243bf3…
|
stephan
|
244 |
} |
|
1243bf3…
|
stephan
|
245 |
</script> |
|
1243bf3…
|
stephan
|
246 |
``` |
|
1243bf3…
|
stephan
|
247 |
|
|
1243bf3…
|
stephan
|
248 |
First, install proxy functions so that `fossil.page.fileContent()` |
|
1243bf3…
|
stephan
|
249 |
can get and set your content: |
|
1243bf3…
|
stephan
|
250 |
|
|
1243bf3…
|
stephan
|
251 |
``` |
|
bdfbc9f…
|
stephan
|
252 |
fossil.page.setContentMethods( |
|
1243bf3…
|
stephan
|
253 |
function(){ return text-form content of your widget }, |
|
1243bf3…
|
stephan
|
254 |
function(content){ set text-form content of your widget } |
|
1243bf3…
|
stephan
|
255 |
}; |
|
1243bf3…
|
stephan
|
256 |
``` |
|
1243bf3…
|
stephan
|
257 |
|
|
88703f0…
|
stephan
|
258 |
Secondly, we need to alert the editor app when there are changes so |
|
88703f0…
|
stephan
|
259 |
that it can do things like store edits locally so that they are not |
|
88703f0…
|
stephan
|
260 |
lost on a page reload. How that is done is completely dependent on the |
|
88703f0…
|
stephan
|
261 |
3rd-party editor widget, but it generically looks something like: |
|
88703f0…
|
stephan
|
262 |
|
|
88703f0…
|
stephan
|
263 |
``` |
|
88703f0…
|
stephan
|
264 |
myCustomWidget.on('eventName', ()=>fossil.page.notifyOfChange()); |
|
88703f0…
|
stephan
|
265 |
``` |
|
88703f0…
|
stephan
|
266 |
|
|
88703f0…
|
stephan
|
267 |
Lastly, if the 3rd-party editor does *not* hide or remove the native |
|
88703f0…
|
stephan
|
268 |
editor widget, and does not inject itself into the DOM on the caller's |
|
88703f0…
|
stephan
|
269 |
behalf, we can replace the native widget with the 3rd-party one with: |
|
1243bf3…
|
stephan
|
270 |
|
|
1243bf3…
|
stephan
|
271 |
```javascript |
|
1243bf3…
|
stephan
|
272 |
fossil.page.replaceEditorWidget(yourNewWidgetElement); |
|
1243bf3…
|
stephan
|
273 |
``` |
|
1243bf3…
|
stephan
|
274 |
|
|
1243bf3…
|
stephan
|
275 |
That method must be passed a DOM element and may only be called once: |
|
1243bf3…
|
stephan
|
276 |
it *removes itself* the first time it is called. |
|
1243bf3…
|
stephan
|
277 |
|
|
88703f0…
|
stephan
|
278 |
That should be all there is to it. When `fossil.page` needs to get the |
|
88703f0…
|
stephan
|
279 |
being-edited content, it will call the installed content-getter |
|
88703f0…
|
stephan
|
280 |
function with no arguments, and when it sets the content (immediately |
|
88703f0…
|
stephan
|
281 |
after (re)loading a file or grabbing local edits), it will pass that |
|
88703f0…
|
stephan
|
282 |
content to the installed content-setter method. Those, in turn will |
|
88703f0…
|
stephan
|
283 |
trigger the installed proxies and fire any relevant events. |
|
88703f0…
|
stephan
|
284 |
|
|
88703f0…
|
stephan
|
285 |
Below is an example of Fossil skin footer content which plugs in the |
|
88703f0…
|
stephan
|
286 |
TinyMCE HTML editor into the `/wikiedit` page, but the process is |
|
88703f0…
|
stephan
|
287 |
identical for `/fileedit` (noting that `/fileedit` may need to be able |
|
88703f0…
|
stephan
|
288 |
to edit multiple types of files for which a special-purpose editor |
|
88703f0…
|
stephan
|
289 |
like TinyMCE may not be suitable). Note that any paths to CSS and JS |
|
88703f0…
|
stephan
|
290 |
resources of course need to be modified to suit one's own |
|
88703f0…
|
stephan
|
291 |
installation. |
|
88703f0…
|
stephan
|
292 |
|
|
88703f0…
|
stephan
|
293 |
``` |
|
88703f0…
|
stephan
|
294 |
<!-- TinyMCE CSS and JS: --> |
|
88703f0…
|
stephan
|
295 |
<link href="$<home>/doc/ckout/skin.min.css" rel="stylesheet" type="text/css"> |
|
88703f0…
|
stephan
|
296 |
<link href="$<home>/doc/ckout/content.min.css" rel="stylesheet" type="text/css"> |
|
88703f0…
|
stephan
|
297 |
<script src='$<home>/doc/ckout/tinymce.min.js'></script> |
|
88703f0…
|
stephan
|
298 |
<script src='$<home>/doc/ckout/theme.min.js'></script> |
|
88703f0…
|
stephan
|
299 |
<script src='$<home>/doc/ckout/icons.min.js'></script> |
|
88703f0…
|
stephan
|
300 |
<!-- Integrate TinyMCE into /wikiedit: --> |
|
88703f0…
|
stephan
|
301 |
<script nonce="$<nonce>"> |
|
88703f0…
|
stephan
|
302 |
if(window.fossil && window.fossil.page.name==='wikiedit'){ |
|
88703f0…
|
stephan
|
303 |
window.fossil.onPageLoad( function(){ |
|
88703f0…
|
stephan
|
304 |
const elemId = 'wikiedit-content-editor'; |
|
88703f0…
|
stephan
|
305 |
tinymce.init({selector: 'textarea#'+elemId}); |
|
88703f0…
|
stephan
|
306 |
const widget = tinymce.get(elemId); |
|
88703f0…
|
stephan
|
307 |
fossil.page.setContentMethods( |
|
88703f0…
|
stephan
|
308 |
function(){return widget.getContent()}, |
|
88703f0…
|
stephan
|
309 |
function(content){widget.setContent(content)} |
|
88703f0…
|
stephan
|
310 |
); |
|
88703f0…
|
stephan
|
311 |
widget.on('change', function(){ |
|
88703f0…
|
stephan
|
312 |
if(widget.isDirty()) fossil.page.notifyOfChange(); |
|
88703f0…
|
stephan
|
313 |
}); |
|
88703f0…
|
stephan
|
314 |
}); |
|
88703f0…
|
stephan
|
315 |
} |
|
88703f0…
|
stephan
|
316 |
</script> |
|
88703f0…
|
stephan
|
317 |
``` |