Compare commits

..

296 commits

Author SHA1 Message Date
af9f74594b
Merge pull request #227 from antville/dependabot/npm_and_yarn/lodash-4.17.19
build(deps): bump lodash from 4.17.15 to 4.17.19
2020-07-30 21:03:19 +02:00
f32621f991
Merge pull request #228 from antville/dependabot/npm_and_yarn/elliptic-6.5.3
build(deps): bump elliptic from 6.5.2 to 6.5.3
2020-07-30 21:02:39 +02:00
dependabot[bot]
630971076c
build(deps): bump elliptic from 6.5.2 to 6.5.3
Bumps [elliptic](https://github.com/indutny/elliptic) from 6.5.2 to 6.5.3.
- [Release notes](https://github.com/indutny/elliptic/releases)
- [Commits](https://github.com/indutny/elliptic/compare/v6.5.2...v6.5.3)

Signed-off-by: dependabot[bot] <support@github.com>
2020-07-30 15:44:19 +00:00
dependabot[bot]
c9cf3ce5cf
build(deps): bump lodash from 4.17.15 to 4.17.19
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.19.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.19)

Signed-off-by: dependabot[bot] <support@github.com>
2020-07-20 03:13:00 +00:00
b08268b311
chg: last paragraph
[shosho.co](https://shosho.co/About-Antville-2675) still complains about it but so far i could not find a better way
2020-06-16 21:13:07 +02:00
382449c574
chg: some more wording 2020-06-16 21:07:33 +02:00
32d0682163
chg: minor wording 2020-06-16 20:36:15 +02:00
3ba5d22723
chg: wording
according to suggestions from https://shosho.co
2020-06-16 20:24:34 +02:00
b0de833542 del: obsolete browserify config 2020-06-14 18:59:02 +02:00
83575dd27d fix: redirecting on cancelled delete dialog 2020-06-14 18:58:45 +02:00
05603b7dc8 add: tasks for running h2 console 2020-06-14 17:48:31 +02:00
4194c7849d add: yarn build and development tasks 2020-06-14 17:47:57 +02:00
2e368ce13f fix: semantic version string but keep it non-semantic in build 2020-06-14 17:16:50 +02:00
c92d6f93d6 chg: updated translations 2020-06-14 16:34:55 +02:00
9119dd7ea6 add: latest changelog entries 2020-06-14 16:28:51 +02:00
08b2d96eba chg: helma download url to recent release 2020-06-14 16:27:50 +02:00
1c5b661a3e add: ignore all build dirs 2020-06-14 16:27:04 +02:00
11639f9319 chg: reverted to more strict file name pattern 2020-05-31 22:21:07 +02:00
f64a1fa25d fix: redundant calls of decodeURIComponent 2020-05-31 14:40:15 +02:00
9fc91c221d chg: localize errors for accepting terms / gdpr 2020-05-24 22:28:04 +02:00
751d1d2523 fix: “null” string showing in alt/title attributes of images 2020-05-24 13:06:51 +02:00
6c407d72b3 fix: missing default properties in root site 2020-05-23 22:41:51 +02:00
820d11f35f fix: incorrect client-side hashing of password 2020-05-23 12:09:11 +02:00
ef5ac1c83c del: logging statement 2020-05-23 11:04:45 +02:00
707fd6391f fix: missing properties of default site created by db script 2020-05-23 10:34:00 +02:00
3e50f2a636 fix: missing upload input on layout import 2020-05-23 09:39:14 +02:00
cd6fd202c7 chg: replaced google’s captcha with h-captcha 2020-05-23 09:39:14 +02:00
51036916f8 chg: display markdown tables in uikit style 2020-05-23 09:39:14 +02:00
3fb8b91f89 chg: updated readme and changelog 2020-05-17 21:35:28 +02:00
9e9c929847 del: obsolete shell scripts 2020-05-17 21:26:42 +02:00
8e6e401cec fix: display of version and build date 2020-05-17 20:42:36 +02:00
207091aee8 chg: ironed out some details in build tasks 2020-05-17 20:19:29 +02:00
b1c60cbf00 add: properties for build version and date (placeholders)
both will be replaced with actual values on build
2020-05-17 17:14:34 +02:00
5d2ccc7c47 add: license report for additional jars 2020-05-17 15:41:35 +02:00
a83378d719 fix: missing output of generated license information 2020-05-17 15:10:36 +02:00
44b59e87fd fix: boolean check for alpine value
See https://github.com/alpinejs/alpine/pull/486
2020-05-17 15:07:55 +02:00
97f1bad6e0 fix: file permissions 2020-05-17 14:42:21 +02:00
8b5a26a4ac chg: documentation tasks 2020-05-17 14:14:02 +02:00
9d3fef0e4f fix: breaking change in alpinejs 2.3.4
See https://github.com/alpinejs/alpine/issues/499
2020-05-17 14:14:02 +02:00
764ac7eac0 del: obsolete file 2020-05-17 14:14:02 +02:00
c4ddaa2f60 chg: run yarn tasks silently 2020-05-17 11:31:56 +02:00
0f18744ee6 chg: improved build tasks 2020-05-17 11:31:56 +02:00
1c3889fae8 chg: replaced marked node module with commonmark java library 2020-05-17 11:31:56 +02:00
7ba2421018 chg: replaced string-strip-html node module with jsoup java library 2020-05-16 21:47:08 +02:00
8f377d0150 chg: rewrote most yarn tasks with gradle 2020-05-16 21:39:13 +02:00
22ccbedd47 add: routine for installing node modules if necessary 2020-05-16 13:44:32 +02:00
cfb9cdb590 chg: console methods (colors) to be consistent with helma log 2020-05-16 11:47:24 +02:00
2ecad42879 fix: rhino-incompatible versions of string-strip-html and punycode 2020-05-10 17:26:27 +02:00
319186547e fix: missing style for disabled submit buttons 2020-05-02 19:54:10 +02:00
eaa3ba2357 chg: rewrote most client-side code with alpine.js 2020-05-02 17:44:26 +02:00
21191ded75 chg: wrapped client-side code in iife 2020-05-02 17:35:38 +02:00
a7fe64b70e chg: surrounded client-side code with iife 2020-05-02 16:41:33 +02:00
a5fd70eba5 chg: load all necessary files from within editor skin 2020-05-02 16:27:21 +02:00
e214e9c80f del: work-around for https://github.com/uikit/uikit/issues/1149
was fixed alreday in 2015 with fe0b2e0010
2020-05-02 15:58:43 +02:00
95b4baf2cd fix: github security alert with jquery upgrade 2020-05-02 00:38:57 +02:00
1cad3ea794 fix: github security alert by running yarn upgrade 2020-05-02 00:17:53 +02:00
c74d616e77 add: alpine.js 2020-05-01 22:20:24 +02:00
49fad937e8 chg: move jquery collage plugin into extra file loaded in gallery only 2020-05-01 16:04:41 +02:00
a554aed6d0 fix: branch name 2020-05-01 15:50:44 +02:00
28988c34fb chg: replaced unmaintained minifyify with uglifyiy 2020-05-01 15:49:40 +02:00
da4ac4333c chg: return http status 400 if no url is provided 2020-04-24 22:41:03 +02:00
da17ed5855 add: readme 2020-04-24 22:29:15 +02:00
1041d5cc49 del: obsolete file and wiki reference 2020-04-24 22:29:04 +02:00
9e28a3af94 fix: jsonp response not containing json 2020-04-24 22:26:47 +02:00
93d2efed58 add: readme for connection claustra 2020-04-24 20:25:22 +02:00
501c060ed1 chg: updated codemirror, marked, string-strip-html, browserify and jsdoc deps 2020-04-24 19:08:11 +02:00
0cfd2abe5e del: console.log 2020-04-24 19:04:07 +02:00
b46838df69 add: construction claustra as integral part of antville 2020-04-13 20:17:50 +02:00
ef43475897 add: proxy claustra as integral part of antville 2020-04-13 20:17:50 +02:00
da1c419875 chg: rewrote most client-side code without using jquery 2020-04-13 13:40:06 +02:00
23d248bef2 fix: missing > at end of macro 2020-04-12 19:07:14 +02:00
1e83a393c3 fix: accidentally committed file paths with date string 2020-04-10 20:43:09 +02:00
1e8ac45da8 fix: client-side code requiring server-side rendering 2020-04-10 20:40:31 +02:00
302d2e3729 chg: refactored formica bookmarklet for using proxy claustra 2020-04-10 20:36:39 +02:00
307723572a add: some http headers for better changes to get a reasonable response 2020-04-10 20:34:37 +02:00
23e7af26a6 chg: moved client-side js code from .skin to main.js 2020-04-05 21:11:13 +02:00
0bdaa332e7 chg: refactored main js code without jquery 2020-04-05 21:11:08 +02:00
9260adc98d del: code in comments 2020-04-05 21:11:08 +02:00
38c203b89e chg: moved md5() method from jquery to global scope 2020-04-05 21:11:08 +02:00
b41116c3f5 chg: refactored initial js after page load without jquery 2020-04-05 21:11:08 +02:00
6cb6e4cd3e chg: refactored grouping timezones without jquery 2020-04-05 21:11:08 +02:00
1952ca19f6 chg: slightly modernized formica bookmarklet code 2020-04-05 21:11:08 +02:00
a90fff0c9f chg: rewrote formica bookmarklet without jquery 2020-04-05 14:14:21 +02:00
0c77ab756c fix: missing markdown rendering in multiple places 2020-04-04 11:14:24 +02:00
37817b382f chg: edited wording, revised or removed some outdated sections 2020-04-03 16:55:03 +02:00
6427aaf9ce chg: replaced ant task for creating claustra with yarn script 2020-04-03 16:36:50 +02:00
2d486f197b chg: replaced patch tasks in ant with yarn scripts 2020-04-03 16:07:11 +02:00
5f8482092a chg: replaced i18n tasks in ant with yarn scripts 2020-04-03 14:21:53 +02:00
0cdd3385cf fix: wrong site context for errors on sites which are not deleted 2020-04-03 11:48:05 +02:00
7ed88a16b4 del: support for instant articles 2020-04-03 11:31:11 +02:00
c588441add del: support for amplified mobile pages 2020-04-03 11:18:51 +02:00
72068d0d8c del: erroneously committed files 2020-03-29 21:46:08 +02:00
4ee6d89bf5 chg: moved parser files into tools dir 2020-03-29 21:36:52 +02:00
243e80d8ac chg: moved build scripts into their own dir 2020-03-29 21:13:12 +02:00
bf6aa7a90b chg: moved config files into tools/config dir 2020-03-29 21:04:50 +02:00
eff0f1f47c chg: moved updater into tools dir 2020-03-29 21:04:50 +02:00
d217d85e04 chg: moved client scripts into tools dir 2020-03-29 21:04:50 +02:00
d47cf60be5 chg: generate jsdoc files during build 2020-03-29 20:36:15 +02:00
f555a0e417 chg: replaced some ant tasks with yarn scripts 2020-03-29 20:33:29 +02:00
e86d3f0a9e chg: moved antville’s license to top-level directory 2020-03-28 23:05:23 +01:00
7cc3adedbf chg: replaced gradle build tasks with yarn scripts 2020-03-27 21:57:05 +01:00
af9b02de26 chg: bumped version of marked npm package 2020-03-27 21:26:58 +01:00
d29a2a1c3f chg: replaced sanitize-html npm package with string-strip-html 2020-03-27 21:21:59 +01:00
1205d82fda chg: bumped codemirror version 2020-03-22 15:23:49 +01:00
9ca613268f chg: reformatted long line 2020-03-22 15:21:59 +01:00
e1660721ef fix: story formatting issues due to mixing helma and markdown features 2020-03-22 15:21:31 +01:00
e3f3e29502 chg: bumped versions of browserify and less 2020-03-22 14:36:24 +01:00
9cf539c382 chg: moved client build from gradle to npm script 2020-03-22 14:35:50 +01:00
4d83a7e941 del: obsolete file 2020-03-07 19:43:48 +01:00
6986a8507e fix: missing digest / etag header for a site’s main action 2020-03-07 19:28:15 +01:00
8930a73b5a fix: markdown issues 2020-03-07 19:26:06 +01:00
175989447e add: editorconfig 2020-03-07 19:25:50 +01:00
4cce47686c Merge branch 'master' into develop 2020-03-07 19:12:48 +01:00
ff78289daa fix: base64 encoding w/ java > 8 2020-03-07 18:59:14 +01:00
95777db1fa fix: dangling pipe symbol if export action is disabled 2020-03-07 18:56:05 +01:00
74e76accb8 chg: ignore i18n files for now 2020-03-07 18:54:48 +01:00
5340dbfac5 fix: rss output missing digest / etag header 2020-03-07 18:43:31 +01:00
ac83a5e474 fix: less dividing values instead of correctly interpreting font-size syntax 2020-03-07 18:41:09 +01:00
c36302a83f chg: refactored deletion of accounts and sites 2018-05-21 15:00:57 +02:00
a978ad7c59 fix: typo in sql statement 2018-05-21 07:52:20 +02:00
5ed3ad138f fix: missing re-assignment of site creators and modifiers when deleting an account 2018-05-21 07:50:09 +02:00
12df0060f7 fix: error when trying to remove non-existing tag hub 2018-05-21 07:48:00 +02:00
09585e21df fix: misleading log message 2018-05-20 18:54:33 +02:00
a21c378b7a fix: exception when trying to delete image file 2018-05-20 18:50:59 +02:00
0ba3b4800c fix: premature assignment of image.parent.site 2018-05-20 17:59:21 +02:00
4e46065e87 fix: missing new creator for items in sites a deleted account might had been owner of before 2018-05-20 17:33:13 +02:00
4764649789 fix: undefined site 2018-05-20 16:53:15 +02:00
386690a818 fix: missing deletions / reassignments when deleting account 2018-05-20 16:48:18 +02:00
2b48d309f3 chg: refactored account deletion with sql 2018-05-20 15:02:32 +02:00
5683b35d12 chg: refactored site deletion with sql 2018-05-20 13:16:04 +02:00
70d8c67f07 fix: insufficient checks for displaying admin alert 2018-05-20 13:13:15 +02:00
4f0b0ab834 fix: obsolete calculation site’s deletion date 2018-05-20 10:28:03 +02:00
a4ff04909a chg: also schedule sites owned by an account for deletion 2018-05-20 10:16:33 +02:00
5f96e314db fix: timeout error when running nightly scheduler 2018-05-20 09:42:47 +02:00
e121967bbc fix: out of memory exception when deleting an account 2018-05-20 09:42:19 +02:00
0cb91214c7 fix: typo in translation 2018-05-20 09:39:21 +02:00
4c85e79dec chg: don’t save site export as antville file anymore 2018-05-20 08:52:07 +02:00
704f80de75 fix: out of memory error when exporting large sites 2018-05-19 12:38:20 +02:00
3f9d03a6f6 chg: moved recaptcha from claustra to core 2018-05-19 09:56:24 +02:00
62bd495564 fix: path of search provider being displayed in button 2018-05-18 21:09:08 +02:00
6dde17b8e8 chg: updated translated messages 2018-05-18 20:55:53 +02:00
b8b58a2ce7 chg: replaced google-search property with search.provider
enabled button for more results at other search providers
2018-05-18 20:46:14 +02:00
f65eff0015 fix: slow search 2018-05-18 20:44:43 +02:00
2120bc3ed8 fix: remaining persistent metadata preventing account deletion to complete 2018-05-13 00:08:11 +02:00
fc044132bb chg: sort jobs by date 2018-05-13 00:05:50 +02:00
2352a788e4 revert: extra deletion of child node 2018-05-12 22:34:49 +02:00
a1e8a00957 fix: transient metadata after deletion 2018-05-12 22:12:29 +02:00
cdefd37ee8 fix: wrong requirements preventing privileged users to delete accounts 2018-05-12 20:01:54 +02:00
0713ac5db7 fix: incomplete account deletion
also generally disable deletion of privileged accounts
2018-05-12 19:03:21 +02:00
94bd4c1f59 fix: missing translations 2018-05-12 17:51:13 +02:00
922f2ed732 add: support for account deletion 2018-05-12 17:39:34 +02:00
1defbc8240 fix: double encoding 2018-05-11 17:27:19 +02:00
24a41030e7 chg: get total count of items and then retrieve each page 2018-05-11 17:27:04 +02:00
b36609006e fix: sql syntax error in mysql 2018-05-11 17:01:51 +02:00
b61940c2e1 add: display of a user’s timeline 2018-05-11 16:53:20 +02:00
48c415cd2c add: tags to site export 2018-05-11 15:02:45 +02:00
bdf8d227b9 fix: issue with wrong membership name
exporting all site content now, anyway
2018-05-11 14:20:53 +02:00
c66b372748 add: site export in json format
contains vintage export.xml
2018-05-11 12:56:48 +02:00
72680a2659 fix: dysfunctional evaluation of response from stopforumspam.com
while adding a property for enabling the blacklist checks
2018-05-10 23:05:26 +02:00
aae43d3051 chg: column order and re-enabled size column 2018-05-06 22:01:20 +02:00
f35eaef6aa add: creator_name to every exported object 2018-05-05 19:24:30 +02:00
f6da6748cc fix: href of wrong object 2018-05-05 19:24:09 +02:00
2726768ddf add: story comments by other users to export 2018-05-05 18:55:37 +02:00
2e8fba1f31 add: job name to admin table 2018-05-05 17:53:30 +02:00
eed7d08028 fix: missing less compiler for creating static css 2018-05-05 16:57:24 +02:00
c3d64dc829 fix: unwanted code running after caught exception 2018-05-05 16:56:53 +02:00
ca2040d429 fix: undefined res.meta.values 2018-05-05 16:55:58 +02:00
3b4112fcfb add: check and removal of existing account data archive 2018-05-05 16:55:25 +02:00
b42772eef1 add: log output when exporting account data 2018-05-05 16:54:43 +02:00
6a62937005 fix: too complicated deletion of jobs 2018-05-05 16:46:30 +02:00
fb654a6c46 fix: incorrect method application 2018-05-05 16:45:47 +02:00
5a2af525e1 chg: run account export as job 2018-05-05 11:04:17 +02:00
c388e71203 add: archive export for account (json) 2018-05-04 17:02:00 +02:00
8b45d5acf7 fix: type in translation 2018-04-30 21:19:26 +02:00
3feee29c0f fix: missing translation 2018-04-30 13:51:42 +02:00
3a34a2fb0e fix: missing translations 2018-04-30 13:44:20 +02:00
8f83797e44 add: check and dialog for accepting updated terms and conditions 2018-04-30 13:37:21 +02:00
ef097ff020 add: class for rendering text from right to left 2018-04-30 12:04:00 +02:00
9f7d1a8529 fix: wrong namespace for sanitizeHtml method 2018-04-30 11:28:17 +02:00
97bfba00d0 chg: allow paths to other sites for terms / privacy stories 2018-04-30 11:26:12 +02:00
065679f7f0 chg: directly require() server-side node modules
needs `rhino.optlevel = -1` to prevent [“generated bytecode for method exceeds 64K limit” error](https://groups.google.com/forum/#!msg/mozilla-rhino/N_O4Got4ED8/gqMnItFFzL8J)
2018-04-29 23:55:57 +02:00
c2c3684ae0 chg: minor code improvement 2018-04-29 22:50:00 +02:00
8c86db2eb0 Merge branch 'develop' into feature/commonjs-support 2018-04-29 21:57:07 +02:00
10736fff35 fix: outdated rhino version 2018-04-29 21:51:32 +02:00
0f44650110 Merge branch 'develop' into feature/emulate-deleted-site 2018-04-29 20:46:26 +02:00
4d85afcf8a add: support for data privacy statement and terms & conditions 2018-04-29 20:42:42 +02:00
b31be0f3aa chg: prevent user from logging in and out again on insufficient login permission 2018-04-29 13:32:06 +02:00
9ec39eaf98 fix: user being logged in in spite of missing permission 2018-04-29 01:42:54 +02:00
fcc889a480 fix: unsecure url 2018-04-29 01:29:32 +02:00
6d85a22091 fix: display of null values for creation / modification dates on initial setup 2018-04-29 01:29:21 +02:00
1681ea1ec0 chg: use default public schema in postgres / h2 databases 2018-04-29 01:29:16 +02:00
6663e220d8 chg: upgraded h2 to version 1.4 2018-04-29 01:29:11 +02:00
d864e5e9d3 chg: refactored setup for login / registration permissions 2018-04-29 01:29:04 +02:00
4befcbac0d add: metadata for new root properties 2018-04-27 17:10:22 +02:00
66f0813c4d Revert "Merge branch 'hotfix/missing-metadata' into develop"
This reverts commit 81eade1e27.
2018-04-27 17:09:03 +02:00
4d18de1f59 Revert "Merge branch 'hotfix/missing-metadata' into develop"
This reverts commit c9527ef194.
2018-04-27 17:08:46 +02:00
45a47e47c1 Merge branch 'develop' 2018-04-27 17:02:30 +02:00
c9527ef194 Merge branch 'hotfix/missing-metadata' into develop 2018-04-27 16:59:12 +02:00
81eade1e27 Merge branch 'hotfix/missing-metadata' into develop 2018-04-27 16:58:17 +02:00
13b9782cf0 add: metadata for new root properties 2018-04-27 16:57:47 +02:00
d33f0eeaae Merge branch 'develop' into hotfix/missing-metadata 2018-04-27 16:54:33 +02:00
1b2bd820a0 fix: insufficient and invalidating amp output 2018-04-27 14:42:11 +02:00
4136683d2e Merge branch 'feature/disable-registration' into develop 2018-04-27 13:55:00 +02:00
b8d9958060 chg: translated new messages and rebuilt message files 2018-04-21 22:32:45 +02:00
f617e44d83 add: setup options for registration scope and login mode 2018-04-21 22:23:32 +02:00
7520783ff9 chg: simplified b/w compatibility for module optimizations 2018-04-18 22:43:20 +02:00
f283f83553 fix: too narrow page width for skin editor 2018-04-15 22:39:38 +02:00
9619351f9b chg: reverse application of new body css
ignore only if body has av-15 class
2018-04-15 20:13:43 +02:00
658a595dbd chg: refactored nav menu for smaller screens 2018-04-08 22:49:02 +02:00
79ceae33a4 del: unnecessary $Site#page skin 2018-04-08 22:48:09 +02:00
ac5d7dbe49 fix: dimensions of header image 2018-03-25 12:18:08 +02:00
19316ee98c fix: restrict max page width to most pages 2018-03-24 18:37:06 +01:00
df04fb91dc fix: image width in list view 2018-03-24 17:56:59 +01:00
b77469b33c chg: limit maximum page width 2018-03-24 17:56:28 +01:00
7cb6c70f60 fix: missing ant icon 2018-03-18 18:51:39 +01:00
c8f0c8ade9 Revert "fix: missing ant svg"
This reverts commit dcad7a4df4.
2018-03-18 18:51:19 +01:00
dcad7a4df4 fix: missing ant svg 2018-03-18 18:47:49 +01:00
4c0c009e05 fix: clashing class name av-ant 2018-03-18 18:45:55 +01:00
aca84e15f4 chg: hide floating navbar when area to left of it is touched 2018-03-18 18:29:41 +01:00
2274d2081a chg: display floating navigation with toggle button on small screens 2018-03-18 12:55:38 +01:00
6b30e1c71f Merge remote-tracking branch 'origin/develop' into develop 2018-03-17 20:35:30 +01:00
dba702341f Merge branch 'feature/update-depencendies' into develop 2018-03-17 20:35:19 +01:00
92be9c8079
Merge pull request #210 from antville/develop
Fix current dependency vulnerabilities
2018-03-17 20:33:03 +01:00
99f6d714bb
Merge pull request #208 from antville/feature/update-depencendies
Feature/update dependencies
2018-03-17 20:31:13 +01:00
503e2025ac
Merge pull request #209 from antville/develop
Release 1.6
2018-03-17 20:30:25 +01:00
86108f1bc8 chg: updated dependencies 2018-03-17 20:25:26 +01:00
3632095276 Merge pull request #203 from antville/feature/resolve-referrer-urls
Resolve Referrer URLs
2017-07-02 11:56:31 +02:00
b3a9a82382 chg: resolve referrer urls before writing to database 2017-07-02 11:54:16 +02:00
9ad4989583 add: Admin.resolveURl() method 2017-07-02 11:53:18 +02:00
55fb6d57e8 del: unnecessary prefix/suffix macro parameters
also unified meta tags wherever possible
2017-07-02 11:51:40 +02:00
e2d4447fbe fix: german t9n of “in {0} days” 2017-04-30 10:22:37 +02:00
5ab19df7d9 fix: too fuzzy results of text output in formatDate()
was always returning the integer part of the result – i.e. Math.floor()
2017-04-30 10:19:50 +02:00
88f65c007d fix: missing getDeletionDate() method 2017-04-30 10:08:50 +02:00
7393f28e66 chg: updated i18n files 2017-04-30 09:52:30 +02:00
c115f03867 chg: use “delete” instead of ”remove” in user messages 2017-04-30 09:50:52 +02:00
c2d8c557fc chg: simplified “deleted site” warning 2017-04-30 09:50:13 +02:00
ceeba55018 fix: display of 401 error message 2017-04-30 09:49:31 +02:00
49b1b357a0 fix: missing support for future dates in formatDate() method 2017-04-30 09:49:03 +02:00
f6b76518ac fix: return value of deleted_macro() if no formatting should be applied
in that case, the date value is returned allowing meaningful application of format filter
2017-04-30 09:47:15 +02:00
951f9a0983 fix: path to rhino jar 2017-04-30 09:45:11 +02:00
b7d55cbc88 chg: immediately show most users 404 page for a deleted site
owners can revert the deletion request until cronjob is created, privileged users until site is removed with nightly cronjo
2017-04-29 22:07:35 +02:00
df1a87eab4 chg: improved display of various console output levels 2017-04-17 20:03:16 +02:00
59bedf9e78 fix: display of modifier in list of story updates 2017-03-18 00:12:24 +01:00
37909691e5 chg: rebuilt server-side JS file 2017-03-18 00:11:32 +01:00
901cbc7aaf fix: missing build target for server-side JS files 2017-03-18 00:10:57 +01:00
76d98b32e1 fix: stickiness of version for marked
also fixed license to be spdx conform
2017-03-17 17:17:48 +01:00
f5cff5ba44 chg: bumped versions and rebuilt client files
note: marked is sticky @0.3.3 because of issue #872https://github.com/chjj/marked/issues/872
2017-03-17 16:53:55 +01:00
97d2813df2 add: helma version to health page 2016-12-17 18:16:20 +01:00
122818697b chg: incremented version string 2016-12-17 18:15:50 +01:00
472104fa75 chg: updated client files 2016-12-17 16:03:40 +01:00
52144cfa84 chg: line wrapping 2016-12-17 15:56:23 +01:00
e04e1daeaf fix: insufficient compression of main.css 2016-12-17 15:55:57 +01:00
d69cf54e43 add: ant target for updating java libraries
using helma’s new gradlew wrapper and an extra build.gradle file
2016-12-17 15:54:47 +01:00
0e3bb7216c fix: redundant call of lessParser.parse()
to improve performance again, compromised by slow java less parser
2016-12-17 14:36:53 +01:00
d28d18c0fe chg: experimental branch using rhino’s commonjs support
needs helma’s feature/commonjs-support branch

the less-rhino-1.7.5.js implementation uses its own require() implementation which breaks rhino’s one. thus, the official java impl is used instead – which is quite slow, unfortunately… needs to be resolved in a better way before this can be merged.

however, using marked with require() works like a charm :)
2016-12-17 14:36:52 +01:00
70e55bc853 fix: wording 2016-12-17 14:35:41 +01:00
6619322053 fix: indentation 2016-12-17 14:35:19 +01:00
59377e4676 fix: output of empty locale 2016-12-17 14:34:53 +01:00
b322ac79f6 fix: redundant call of lessParser.parse()
to improve performance again, compromised by slow java less parser
2016-12-17 14:11:09 +01:00
93194492ad chg: experimental branch using rhino’s commonjs support
needs helma’s feature/commonjs-support branch

the less-rhino-1.7.5.js implementation uses its own require() implementation which breaks rhino’s one. thus, the official java impl is used instead – which is quite slow, unfortunately… needs to be resolved in a better way before this can be merged.

however, using marked with require() works like a charm :)
2016-12-17 10:30:12 +01:00
cd5cd15018 del: definition of JSON object in external module
use Rhino’s implemented JSON support instead
2016-12-17 10:01:19 +01:00
d8fdba526a fix: href processing
missing else clause caused wrong hrefs for default domain
2016-12-09 15:01:17 +01:00
dd49a26a57 add: app property for overriding the scheme used in hrefs
e.g. hrefScheme = https generally renders urls starting with https://
2016-12-09 14:48:12 +01:00
9748633b78 add: current location as referrer
to make up for missing information in the user agent
2016-09-04 00:34:06 +02:00
7f6584dcbd fix: use simplified user agent
works better e.g. with nytimes.com because this site always redirects to its login form when a user agent starting with `Mozilla/5.0 (c` is detected:

```python
import os
import pprint

from google.appengine.api import memcache
from google.appengine.api import mail
from google.appengine.api import urlfetch
from google.appengine.ext import db

url = 'http://www.nytimes.com/2016/09/03/technology/nso-group-how-spy-tech-firms-let-governments-see-everything-on-a-smartphone.html?utm_source=pocket&utm_medium=email&utm_campaign=pockethits&_r=0'

response = urlfetch.fetch(url, headers={
  'User-Agent': 'Mozilla/5.0 (c u got me'
}, follow_redirects=True)

pprint.pprint(response.content)
```
2016-09-04 00:33:51 +02:00
02371689c8 chg: add log output 2016-07-10 18:24:11 +02:00
313833ecce fix: enable real utf-8 for mysql database
source: https://mathiasbynens.be/notes/mysql-utf8mb4
2016-07-10 18:23:27 +02:00
f27a4cf5ac fix: do not create or drop obsolete tables 2016-07-10 18:22:16 +02:00
c58bedeb0b chg: allow instant articles for all sites 2016-06-26 20:46:53 +02:00
3ead0b8019 add: basic support for Google’s accelerated mobile pages (AMP) 2016-06-26 20:36:28 +02:00
4be343d768 chg: sped up execution of sql deletion 2016-06-26 14:20:46 +02:00
1fc175018a fix: revert accidental commit of commented code 2016-06-26 14:13:45 +02:00
2d61c0dafa fix: ignore any origin without either http, https or ftp protocol 2016-06-26 14:12:53 +02:00
d75e3437a9 fix: respect default parameter in description macro 2016-06-26 13:40:29 +02:00
fdfee2e50d fix: display of file origin in File and Image prototypes
* ignore origins with c:\fakepath\ (i.e. uploaded from local file system)
 * use `description_macro()` for output of either this.description or this.origin (if available) or nothing, instead of macro default
 * prevent setting this.description in `update()` methods or from formica bookmarklet
2016-06-26 13:21:57 +02:00
2eeb4549ce fix: do not create a helma.Image instance if constraints are fulfilled
obviously, helma.Image already compresses image data and a recent change actually removed code preventing this for images fulfilling the max width and height constraints

see http://help.antville.org/stories/2239244/
2016-05-26 12:36:42 +02:00
79d6c265e2 new: skin for instant article 2016-05-25 17:21:29 +02:00
2d0b1d6790 change: added support for instant articles in rss feeds
currently only enabled for a few sites
2016-05-25 17:20:39 +02:00
a8b37e39ba fix: do not resize original image 2016-04-22 22:13:11 +02:00
ee28a1466a fix: don’t resize layout images (except their thumbnails) 2016-04-09 18:24:20 +02:00
4b451cd84c fix: automatically set og:image from formica 2016-03-28 18:29:53 +02:00
0fe4d4b160 fix: replaced getURL() with corresponding helma.Http methods for more configuration options and better results 2016-03-28 18:28:41 +02:00
b5851313b9 fix: reset the response before sending JSONP data 2016-03-28 18:27:47 +02:00
e9c9fb7ae5 fix: custom message for error when retrieving url 2016-03-25 20:06:55 +01:00
2e16d8b179 fix: disable debugging mode 2016-03-25 19:58:24 +01:00
780ad73c2a fix: catch various errors and give a litte bit of feedback in the gui 2016-03-25 19:57:19 +01:00
ac64092624 fix: replaced hard-coded site url with macro 2016-03-25 16:36:07 +01:00
a4b85d40e6 fix: disabled debugging code 2016-03-18 22:32:34 +01:00
8b3a41191e updated formica bookmarklet
fix: layout in uikit style
fix: gui for in/excluding image
add: support for open graph title and description
chg: emoji in bookmarklet code with support for custom cookie (useful e.g. for nyt)
2016-03-18 22:27:38 +01:00
4d2867d744 fix: added missing change in $Image#embed skin for improved formica image link 2016-01-16 23:43:11 +01:00
7644cc4ec0 chg: improved responsive formica image with custom link to source URL 2016-01-16 23:39:41 +01:00
95297f5f14 fix: styled image from formica bookmarklet as thumbnail to maintain responsive layout 2016-01-15 21:20:45 +01:00
6180ee475c fix: refactored for latest update in Helma’s format() method to prevent huge gaps in <pre> elements 2015-08-14 14:25:53 +02:00
aeb13485e9 fix: date formatting 2015-08-14 14:24:50 +02:00
342974fdc9 chg: added hints to Java and JavaScript to the first sentence about Helma 2015-08-14 14:24:33 +02:00
34af2b0bd9 fix: missing simple linebreaks in story 2015-08-14 11:29:47 +02:00
295 changed files with 11094 additions and 115499 deletions

17
.editorconfig Normal file
View file

@ -0,0 +1,17 @@
# editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
[*.{java}]
indent_size = 3

27
.gitignore vendored
View file

@ -1,13 +1,16 @@
.*
•*
*.eml
*.iml
build/work
build/dist
claustra/
code/domains.map
jobs/
local/
node_modules/
static/sites/*
static/scripts/*.map.json
build/
/claustra/
/docs/
/jobs/
/local/
/lib/
/node_modules/
/static/
!/static/img
!/static/formica.html
/code/domains.map
/i18n/*.js

33
CHANGES.md Normal file
View file

@ -0,0 +1,33 @@
# Change Log
## May 23, 2020
* Render tables with stripes and hover colors extrapolated from layout settings
* Replaced Googles ReCaptcha with [hCaptcha](https://hcaptcha.com)
## May 17, 2020
* Reverted Yarn scripts into Gradle tasks
* Implemented complete build system in Gradle
* Added color support for console messages
* Replaced Node module for rendering Markdown (marked) with Java implementation ([CommonMark](https://github.com/atlassian/commonmark-java))
* Replaced Node module for sanitizing HTML (string-strip-html) with Java implementation ([jsoup](https://jsoup.org))
## May 1, 2020
* Upgraded jQuery to version 3
* Refactored remaining cient-side jQuery code using [Alpine](https://github.com/alpinejs/alpine) (jQuery is still a dependency of UIkit, though)
* Moved code for jQuery [CollagePlus](https://github.com/antville/jquery-collagePlus) plugin into extra file
## April 13, 2020
* Rewrote most client-side code without using jQuery
* Refactored Formica bookmarklet
* Improved Proxy Claustra for use with Formica bookmarklet
* Fixed output missing Markdown filter in multiple places
* Replaced Gradle and Ant build tasks with Yarn scripts
* Removed support for Instant Articles
* Removed support for Accelerated Mobile Pages
* Replaced Rhino-incompatible sanitize-html NPM package with string-strip-html
* Upgraded NPM dependencies to latest compatible versions
* Incorporated some claustra as integral part of Antville

View file

@ -2,18 +2,19 @@
## Helma Object Publisher
Antville needs Helma Object Publisher to be installed on the desired machine. If not already done so please [download Helma](http://helma.org/download) and follow the [installation instructions](http://helma.org/download/installation).
Antville needs Helma Object Publisher to be installed on the desired machine. If not already done so please [download Helma](https://github.com/antville/helma/releases) and follow the [installation instructions](https://github.com/antville/helma/#how-to-helma).
## SQL Database
Furthermore, Antville needs an SQL database to be installed as well. Currently supported products are PostgreSQL and MySQL. If not already done so please install the desired database before you continue.
Furthermore, Antville needs an SQL database to be installed as well. Currently supported products are PostgreSQL and MySQL/MariaDB. Be sure to install the desired database before you continue.
For connecting Antville to the database the corresponding JDBC driver is also necessary. If not already done so please copy the driver to the directory `lib/ext` of Helmas installation directory.
Finally, you need the corresponding JDBC driver for connecting Antville to the database. Please copy the driver to the directory `lib/ext` of Helmas installation directory.
As of writing this installation guide the drivers could be downloaded via the following URLs:
As of writing this installation guide the drivers can be downloaded via the following URLs:
- [http://jdbc.postgresql.org/download.html]()
- [http://dev.mysql.com/downloads/connector/j/]()
- <http://jdbc.postgresql.org/download.html>
- <http://dev.mysql.com/downloads/connector/j/>
- <https://mariadb.com/kb/en/mariadb-connector-j/>
Of course you can also use a packet manager like aptitude or MacPorts if the JDBC driver is available from there. However, you then need to create a symbolic link to the driver from within Helmas `lib/ext` directory.
@ -21,9 +22,9 @@ Now unpack the Antville distribution package. Move the resulting directory `antv
Inside the directory `antville` you will find a directory called `db`. This directory contains all database-related files, ie. several SQL scripts for creating the database needed by the application. Change to that directory.
Antville currently comes with scripts for PostgreSQL (`postgre.sql`) and for MySQL databases (`my.sql`).
Antville currently comes with scripts for PostgreSQL (`postgre.sql`) and for MySQL/MariaDB databases (`my.sql`).
_Note:_ Antville is preconfigured for PostgreSQL out of the box but it is easy to modify the configuration to be compatible with MySQL.
_Note:_ Antville is preconfigured for PostgreSQL out of the box but it is easy to modify the configuration to be compatible with MySQL/MariaDB.
Each of these SQL scripts creates the tables, indexes and initial records and also the account used by the application to communicate with the database.
@ -31,7 +32,7 @@ Each of these SQL scripts creates the tables, indexes and initial records and al
The default password of this account is `antville`, so you should change it if you want to secure your installation. Open the desired SQL script and scroll down to the `create user` (for PostgreSQL) or `grant user` (for MySQL) statement. Search for `password` (PostgreSQL) or `identified by` (MySQL) and change the trailing value in quotes to the password of your choice.
Please refer to the documentation of your database on how to run the appropriate script. Afterwards you will have to tell Antville how it can access your database. This is done in a configuration file named `db.properties` which is located in the `code` directory, or if you are going for MySQL in the `db/my.compat` directory.
Please refer to the documentation of your database on how to run the appropriate script. Afterwards you will have to tell Antville how it can access your database. This is done in a configuration file named `db.properties` which is located in the `code` directory, or if you are going for MySQL/MariaDB in the `db/my.compat` directory.
Open the desired file and ensure that the line beginning with `antville.url` points to the server that runs the database. By default, this is the local machine aka localhost which will be just right in most cases.
@ -39,11 +40,11 @@ Check that the password is set accordingly to the one you entered in the SQL scr
## Enabling an Application
Finally, you need to tell Helma about the new application. This is done by adding the contents of the file `apps.properties` in the `extra` directory to the file `apps.properties` located in the top installation directory.
Finally, you need to tell Helma about the new application. This is done by adding the contents of the file `apps.properties` in the `tools/config` directory to the file `apps.properties` located in the top installation directory.
_Note:_ If you are using MySQL you need to edit and enable line 5 (the one defining `antville.repository.1`) of the file by removing the leading comment symbol `#`.
_Note:_ If you are using MySQL/MariaDB you need to edit and enable line 5 (the one defining `antville.repository.1`) of the file by removing the leading comment symbol `#`.
## Starting Up!
## Starting Up
Now start up Helma and point your browser to
@ -58,11 +59,11 @@ Have fun!
## TL;DR
1. Install Helma if not already done so
2. Install PostgreSQL or MySQL database if not already done so
3. Install corresponding JDBC driver in helma/lib/ext
2. Install PostgreSQL or MySQL/MariaDB database if not already done so
3. Install or symlink corresponding JDBC driver in helma/lib/ext
4. Unpack Antville distribution file
5. Move antville directory into helma/app directory
6. Run the desired script in antville/db for either PostgreSQL or MySQL
7. Copy contents of antville/extra/apps.properties to helma/apps.properties
8. If necessary, enable MySQL compatibility in apps.properties
9. Start up Helma and browse to [http://localhost:8080/antville]()
6. Run the desired SQL script in antville/db for either PostgreSQL or MySQL/MariaDB
7. Copy contents of antville/tools/config/apps.properties to helma/apps.properties
8. If necessary, enable MySQL/MariaDB compatibility in apps.properties
9. Start up Helma and browse to <http://localhost:8080/antville>

View file

@ -1,10 +1,12 @@
Copyright 2001-2014 by the Workers of Antville.
# License
Copyright 2001-2020 by the Workers of Antville.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
<http://www.apache.org/licenses/LICENSE-2.0>
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,

View file

@ -1,58 +1,54 @@
# About Antville
Antville is an open source project aimed at the development of a high performance, feature rich weblog hosting software. It can easily host up to several thousands of sites (the number of weblogs is rather limited by the installation owners choice and server power than by software limitations).
Antville is an open source project providing a high performance, feature-rich blog hosting software. Antville can host tens of thousands of blogs. Server power is the only limit. Installation and use is easy.
Antville is entirely written in JavaScript (ECMAScript, to be precise) and based on Helma Object Publisher, a powerful and fast scriptable open source web application server (which itself is written in Java). Antville works with a relational database in the backend.
Antville is written in server-side JavaScript and developed with Helma Object Publisher. Antville works with a relational database in the back-end.
[Check out the project site for more information.](http://project.antville.org)
[Look at the project site for more information.](https://project.antville.org)
## Status
Antville can be considered stable quality code. It is heavily used by several thousands of users at [Antville.org](http://antville.org) and [several other sites](http://code.google.com/p/antville/wiki/AntvilleSites). Nevertheless, there still could be bugs hidden somewhere in this application.
Antvilles codebase is of stable quality and ready for production deployment. Try out [Antville.org](https://antville.org) for a demonstration.
Antville can be used for production purposes, but please bear in mind that the creators of Antville do not take any warranty, whichever kind.
There still could be bugs hidden in Antvilles source code. If you find one please let us know. The creators of Antville do not take any responsibility for what the software might do.
## System Requirements
To run Antville you need [Helma Object Publisher](http://helma.org) and a relational database in the backend. Antville was thoroughly tested with [PostgreSQL](http://postgresql.org) and [MySQL](http://mysql.com).
To run Antville you need [Helma Object Publisher](https://github.com/antville/helma) and a relational database software. We tested Antville with [PostgreSQL](https://postgresql.org) and [MySQL](https://mysql.com) [MariaDB](https://mariadb.com) should work, too.
For setting up Helma Object Publisher and the database of your choice please refer to the corresponding installation instructions.
To enable Antville sending notification e-mails you need access to an SMTP server.
To enable Antville sending confirmation mails to users (e.g. after registration) you will also need access to an SMTP server.
Helma comes with an embedded webserver (Jetty) so you do not need to install one. Yet, you can also use the webserver of your choice.
Helma comes with its own embedded webserver (Jetty) so you do not need to install one, although you can easily use Apache httpd as front-end webserver, too.
For details please refer to the installation instructions of Helma Object Publisher and the corresponding software packages.
Please refer to the Install.md file for detailed information on how to install Antville.
The `INSTALL.md` file contains detailed instructions to install Antville.
## Documentation and Further Information
For documentation and further information regarding Antville you can refer to:
For documentation and further information about Antville you can refer to:
- [project.antville.org](https://project.antville.org)
- [about.antville.org](https://about.antville.org)
- [help.antville.org](https://help.antville.org)
- [project.antville.org](http://project.antville.org)
- [about.antville.org](http://about.antville.org)
- [help.antville.org](http://help.antville.org)
Feel free to ask any question about Antville at our [support site](https://help.antville.org).
Feel free to ask any question about Antville at our [support site](http://help.antville.org).
You should follow Antville on [Facebook](http://facebook.com/Antville) and [Twitter](http://twitter.com/antville_org)!
You should follow Antville on [Facebook](https://facebook.com/Antville) and [Twitter](https://twitter.com/antville_org)!
## Bug Reporting and Feature Requests
If you think you found a bug [please report it](http://project.antville.org).
If you think you found a bug [please let us know](https://project.antville.org).
A good place for your feature requests or proposals is the [project development site](http://project.antville.org).
A great place for your feature requests or proposals is the [project development site](https://project.antville.org).
Since Antville is open-source, you are definitely encouraged to modify the application, we would be happy to hear from your ideas, suggestions and changes drop us a message via <mail@antville.org> or use any of the aforementioned channels.
For those of you who demonstrated a commitment to collaborative open-source development through sustained participation and contributions within the development of Antville, there will also be other ways to participate.
Antville is open-source, and we want to encourage you to change its code according to your likeness. We are curious about your ideas and suggestions. Feel free to drop us a message to <mail@antville.org> or through any channels mentioned before.
## About Helma Object Publisher
[Helma Object Publisher](http://helma.org) is a web application server.
[Helma Object Publisher](https://github.com/antville/helma) is an open source project providing a powerful, fast and scriptable web application server written in Java.
With Helma Object Publisher (sometimes simply referred to as Helma or Hop) you can define Objects and map them to a relational database table. These so-called HopObjects can be created, modified and deleted using a comfortable object/container model. Hence, no manual fiddling around with database code is necessary.
Define HopObjects and map them to a relational database table. Create, change and delete HopObjects at your whim using a comfortable object-container model. Manual fiddling around with database code is not necessary.
HopObjects are extended JavaScript objects which can be scripted using server-side JavaScript. Beyond the common JavaScript features, Helma provides special “skin” and template functionalities which facilitate the rendering of objects via a web interface.
Thanks to Helmas relational database mapping technology, HopObjects create a hierarchical structure, the URL space of a Helma site. The parts between slashes in a Helma URL represent HopObjects (similar to the document tree in static sites). The Helma URL space can be thought of as an analogy to the Document Object Model (DOM) in client-side JavaScript.
HopObjects extend the native JavaScript object. They got all the common features you know and more. One highlight are the special templating features to ease the rendering of objects for the Web.
Combine HopObjects to create a hierarchical structure. A URL in Helma mirrors this structure. Each part of the URL path corresponds to a relational database mapping, similar to the document tree of static websites. Helmas URL space is an analogy to the Document Object Model implemented in client-side JavaScript.

287
build.gradle Normal file
View file

@ -0,0 +1,287 @@
plugins {
id 'base'
id 'java'
id 'com.github.node-gradle.node' version '2.2.3'
id 'org.ajoberstar.grgit' version '4.0.2' apply false
}
import org.ajoberstar.grgit.Grgit
tasks.build.dependsOn 'assemble'
node {
version = '12.16.3'
yarnVersion = '1.22.4'
download = true
}
allprojects {
apply plugin: 'java'
repositories {
mavenCentral()
jcenter()
}
project.ext.distVersion = { ->
def json = new groovy.json.JsonSlurper()
def packageData = json.parse(file("${rootProject.projectDir}/package.json"))
return packageData.version.substring(0, packageData.version.size() - 2)
}
project.ext.antvilleBuildDir = "${rootProject.buildDir}/tmp/antville"
project.ext.antvilleInstallDir = "${rootProject.buildDir}/install/antville"
project.ext.antvilleDistFiles = copySpec {
from fileTree(antvilleBuildDir).matching {
}
}
// Hide some purely Java-related tasks
project.tasks.buildDependents.group = null;
project.tasks.buildNeeded.group = null;
project.tasks.classes.group = null;
project.tasks.jar.group = null;
project.tasks.javadoc.group = null;
project.tasks.testClasses.group = null;
}
version = distVersion()
dependencies {
implementation 'com.atlassian.commonmark:commonmark:0.14.0'
implementation 'com.atlassian.commonmark:commonmark-ext-autolink:0.14.0'
implementation 'com.atlassian.commonmark:commonmark-ext-gfm-strikethrough:0.14.0'
implementation 'com.atlassian.commonmark:commonmark-ext-gfm-tables:0.14.0'
implementation 'org.jsoup:jsoup:1.13.1'
implementation 'rome:rome:1.0'
implementation('org.lesscss:lesscss:1.7.0.1.1') {
exclude group: 'org.mozilla', module: 'rhino'
exclude group: 'org.slf4j', module: 'slf4j-api'
exclude group: 'org.slf4j', module: 'slf4j-simple'
}
}
task assemble(type: Copy, overwrite: true) {
dependsOn 'installAntville'
dependsOn 'installJars'
dependsOn 'buildStaticFiles'
from fileTree(antvilleBuildDir).matching {
exclude 'node_modules'
exclude 'package.json'
exclude 'tests'
exclude 'tools/client'
exclude 'tools/antclick'
exclude 'yarn.lock'
} into antvilleInstallDir
}
task installAntville {
description 'Clone the Antville repository and remove all unnecessary files.'
group 'installation'
def tempDir = "$project.buildDir/tmp/repo"
outputs.dirs tempDir, antvilleBuildDir
doFirst {
Grgit.clone(dir: tempDir, uri: project.ext['antville.repo.url'])
}
doLast {
def git = Grgit.open(dir: tempDir)
def hash = git.head().abbreviatedId
def date = new Date().format('d MMM yyyy')
copy {
from "$tempDir/code/app.properties"
into "$antvilleBuildDir/code"
filter { line -> line.replaceAll('(version =) 0.0.0', "\$1 $version.$hash")
.replaceAll('(buildDate =) 18 Oct 1971', "\$1 $date")
}
}
copy {
from fileTree(tempDir).matching {
exclude 'code/app.properties'
exclude '*gradle*'
exclude '.*'
exclude 'i18n/*.po*'
} into antvilleBuildDir
}
}
}
task installJars(type: Copy) {
description 'Download required JAR libraries.'
group 'installation'
dependsOn 'installAntville'
def outputDir = "$antvilleBuildDir/lib"
outputs.dir outputDir
from configurations.runtimeClasspath
into outputDir
}
task installNodeModules(type: YarnTask) {
description 'Download required Node modules.'
group 'build'
dependsOn 'installAntville'
inputs.files "$antvilleBuildDir/package.json"
outputs.dir "$antvilleBuildDir/node_modules"
args = ['-s', 'install']
execOverrides {
it.workingDir = antvilleBuildDir
}
}
task buildStaticFiles(type: Copy) {
description 'Build fonts, client-side scripts and stylesheets.'
group 'build'
dependsOn 'installAntville'
dependsOn 'installNodeModules'
dependsOn 'buildMainScript'
dependsOn 'buildMainStyles'
dependsOn 'buildEditorScript'
dependsOn 'buildEditorStyles'
dependsOn 'buildGalleryScript'
dependsOn 'buildLicenses'
def inputDir = "$antvilleBuildDir/node_modules/uikit/dist/fonts"
def outputDir = "$antvilleBuildDir/static/fonts"
inputs.dir inputDir
outputs.dir outputDir
from inputDir
into outputDir
}
['main', 'editor', 'gallery'].each { name ->
task "build${name.capitalize()}Script" (type: YarnTask) {
description "Build the ${name} client-side scripts."
group 'build'
dependsOn 'installNodeModules'
def inputFile = "tools/client/${name}.js"
def outputFile = "static/scripts/${name}.min.js"
inputs.files "$antvilleBuildDir/$inputFile"
outputs.files "$antvilleBuildDir/$outputFile"
args = ['-s', 'browserify', inputFile, '-o', outputFile, '-g', 'uglifyify']
execOverrides {
it.workingDir = antvilleBuildDir
}
}
}
['main', 'editor'].each { name ->
task "build${name.capitalize()}Styles" (type: YarnTask) {
description "Build the ${name} stylesheet."
group 'build'
dependsOn 'installNodeModules'
def inputFile = "tools/client/${name}.less"
def outputFile = "static/styles/${name}.min.css"
inputs.files "$antvilleBuildDir/$inputFile"
outputs.files "$antvilleBuildDir/$outputFile"
args = ['-s', 'lessc', '--clean-css', inputFile, outputFile]
execOverrides {
it.workingDir = antvilleBuildDir
}
}
}
task buildLicenses(type: YarnTask) {
description 'Build licenses file from client-side dependecies.'
group 'build'
dependsOn 'installNodeModules'
def outputFile = "$antvilleBuildDir/static/licenses.txt"
inputs.file "$antvilleBuildDir/package.json"
outputs.file outputFile
args = ['-s', 'licenses', 'generate-disclaimer']
execOverrides {
it.workingDir = antvilleBuildDir
it.standardOutput = new FileOutputStream(outputFile)
}
}
task jsdoc(type: YarnTask) {
description 'Generates JavaScript API documentation for the main source code.'
group 'documentation'
dependsOn 'installNodeModules'
def inputDir = "$antvilleBuildDir/code"
def outputDir = "${project.buildDir}/docs/jsdoc"
inputs.dir inputDir
outputs.dir outputDir
args = ['-s', 'jsdoc', '-r', '-d', outputDir, inputDir]
execOverrides {
it.workingDir = antvilleBuildDir
}
}
task assembleDist {
description 'Creates the Antville download packages.'
group 'distribution'
dependsOn 'assemble'
dependsOn 'distZip'
dependsOn 'distTar'
}
task distZip(type: Zip) {
description 'Creates the Antville download package as Zip file.'
group 'distribution'
dependsOn 'assemble'
def version = project.distVersion()
def outputDir = "${project.buildDir}/distributions"
def outputFile = "antville-${version}.zip"
inputs.dir antvilleInstallDir
outputs.file "$outputDir/$outputFile"
from antvilleInstallDir
destinationDirectory = file(outputDir)
archiveFileName = outputFile
}
task distTar(type: Tar) {
description 'Creates the Antville download package as Bzip2 file.'
group 'distribution'
dependsOn 'assemble'
def version = project.distVersion()
def outputDir = "${project.buildDir}/distributions"
def outputFile = "antville-${version}.tbz"
inputs.dir antvilleInstallDir
outputs.file "$outputDir/$outputFile"
from antvilleInstallDir
compression = Compression.BZIP2
destinationDirectory = file(outputDir)
archiveFileName = outputFile
}

337
build.xml
View file

@ -1,337 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ The Antville Project
~ http://code.google.com/p/antville
~
~ Copyright 2001-2014 by the Workers of Antville.
~
~ Copyright 20012007 Robert Gaggl, Hannes Wallnöfer, Tobi Schäfer,
~ Matthias & Michael Platzer, Christoph Lincke.
~
~ Licensed under the Apache License, Version 2.0 (the ``License'');
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an ``AS IS'' BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project name="antville" default="dist" basedir=".">
<target name="help" depends="usage"/>
<target name="usage">
<echo message="Antville Build Instructions"/>
<echo message="==========================="/>
<echo message="Available targets are:"/>
<echo message=" clean Clean up build directory"/>
<echo message=" click Generate the AntClick packages"/>
<echo message=" client Build client-side scripts and styles"/>
<echo message=" dist Generate the Antville and AntClick packages (default)"/>
<echo message=" docs Generate the API documentation"/>
<echo message=" help Show these build instructions"/>
<echo message=" messages Generate JavaScript message files"/>
<echo message=" patch Apply patch file to Antville installation"/>
<echo message=" pot Extract gettext call strings into POT file"/>
<echo message=" ville Generate the Antville packages"/>
<echo message=" +claustra Scaffolds a new claustra, ready for implementation"/>
<echo message=" +patch Scaffolds a new patch, ready for implementation"/>
</target>
<target name="dist" depends="antville, antclick"/>
<target name="all" depends="dist"/>
<target name="build" depends="dist"/>
<target name="init">
<tstamp>
<format property="date" pattern="d MMM yyyy" locale="en"/>
</tstamp>
<tstamp>
<format property="file-date" pattern="yyyyMMdd" locale="en"/>
</tstamp>
<property name="name" value="antville"/>
<property name="year" value="2001-${year}"/>
<property name="version" value="1.5"/>
<property name="package.name" value="${name}-${version}"/>
<property name="antville.src" value="https://github.com/antville/antville.git"/>
<property name="helma.src" value="https://github.com/antville/helma.git"/>
<property name="jala.src" value="https://github.com/antville/helma-jala.git"/>
<property name="uikit.dir" location="./node_modules/uikit-bower"/>
<property name="build.dir" location="${basedir}/build"/>
<property file="${build.dir}/build.properties"/>
<property name="helma.dir" location="/opt/helma"/>
<property name="extra.dir" location="${build.dir}/extra"/>
<property name="dist.dir" location="${build.dir}/dist"/>
<property name="work.dir" location="${build.dir}/work"/>
<property name="source.dir" location="${work.dir}/src"/>
<property name="export.dir" location="${work.dir}/export"/>
<property name="modules.dir" location="${export.dir}/helma/modules"/>
<property name="antville.dir" location="${export.dir}/antville"/>
<property name="docs.title" value="Antville&amp;#32;${version}&amp;#32;API&amp;#32;Reference"/>
<property name="docs.infiles" location="${basedir}/code"/>
<property name="docs.outfiles" location="${basedir}/docs"/>
<property name="i18n.scan" value="claustra code compat extra"/>
<property name="i18n.destination" location="${basedir}/i18n"/>
<property name="i18n.poDirectory" location="${i18n.destination}"/>
<property name="i18n.template" location="${i18n.destination}/antville.pot"/>
<property name="i18n.namespace" value=""/>
</target>
<target name="export" depends="init">
<mkdir dir="${source.dir}"/>
<exec dir="${source.dir}" executable="git">
<arg line="clone ${antville.src}"/>
</exec>
<exec dir="${source.dir}/antville" executable="git">
<arg line="checkout-index -f -a --prefix=${antville.dir}/"/>
</exec>
<delete includeemptydirs="true">
<fileset dir="${antville.dir}" includes="build.xml build/** docs/** i18n/*.po*"/>
</delete>
<exec dir="${source.dir}/antville" executable="git" outputproperty="hash">
<arg line="rev-parse --short HEAD"/>
</exec>
<replace file="${antville.dir}/code/Root/Root.js" value="${version}">
<replacetoken><![CDATA[<v>0</v>]]></replacetoken>
</replace>
<replace file="${antville.dir}/code/Root/Root.js" value="${hash}">
<replacetoken><![CDATA[<h>0</h>]]></replacetoken>
</replace>
<replace file="${antville.dir}/code/Root/Root.js" value="${date}">
<replacetoken><![CDATA[<d/>]]></replacetoken>
</replace>
</target>
<target name="ville" depends="antville"/>
<target name="click" depends="antclick"/>
<target name="antville" depends="export">
<antcall target="make-tar">
<param name="filename" value="${package.name}"/>
<param name="path" value="${antville.dir}"/>
</antcall>
<antcall target="make-zip">
<param name="filename" value="${package.name}"/>
<param name="path" value="${antville.dir}"/>
</antcall>
</target>
<target name="antclick" depends="export">
<!-- Export the Helma and Jala repositories to a temporary directory -->
<exec dir="${source.dir}" executable="git">
<arg line="clone ${helma.src}"/>
</exec>
<exec dir="${source.dir}" executable="git">
<arg line="clone ${jala.src}"/>
</exec>
<!-- Checkout each repository index to the export directory -->
<mkdir dir="${export.dir}"/>
<exec dir="${source.dir}/helma" executable="git">
<arg line="checkout-index -f -a --prefix=${export.dir}/helma/"/>
</exec>
<exec dir="${source.dir}/helma-jala" executable="git">
<arg line="checkout-index -f -a --prefix=${export.dir}/helma/modules/jala/"/>
</exec>
<!-- Copy exported files to final destinations -->
<copy todir="${work.dir}">
<fileset dir="${export.dir}/helma" includes="lib/** licenses/**"/>
</copy>
<copy todir="${work.dir}/apps/antville">
<fileset dir="${antville.dir}"/>
</copy>
<copy todir="${work.dir}/modules">
<fileset dir="${modules.dir}" includes="core/** helma/** jala/**"/>
</copy>
<!-- Copy extra files to final destinations -->
<copy file="${export.dir}/helma/license.txt" tofile="${work.dir}/licenses/helma.txt"/>
<copy todir="${work.dir}">
<fileset dir="${extra.dir}" includes="start.bat apps.properties server.properties launcher.jar"/>
</copy>
<exec dir="${extra.dir}" executable="cp">
<arg line="-p start.sh ${work.dir}"/>
</exec>
<copy file="${extra.dir}/helma.jar" todir="${work.dir}/lib"/>
<copy file="${extra.dir}/h2-1.3.176.jar" todir="${work.dir}/lib/ext"/>
<copy file="${extra.dir}/h2.txt" todir="${work.dir}/licenses"/>
<copy todir="${build.dir}/work/db">
<fileset dir="${extra.dir}" includes="antville.h2.db"/>
</copy>
<copy todir="${work.dir}/licenses">
<fileset dir="${antville.dir}/legal" includes="**"/>
</copy>
<copy file="${modules.dir}/jala/licenses/jala.txt" todir="${work.dir}/licenses"/>
<!-- Delete unnecessary files -->
<delete>
<fileset dir="${work.dir}/modules/helma" includes="*.jar Search.js Ssh.js Chart.js"/>
</delete>
<delete includeemptydirs="true">
<fileset dir="${work.dir}/modules/jala" includes="build.properties docs/** lib/** licenses/** tests/** util/**"/>
</delete>
<delete dir="${work.dir}/apps/antville/legal"/>
<delete dir="${source.dir}"/>
<delete dir="${export.dir}"/>
<!-- Create the packages -->
<antcall target="make-zip">
<param name="filename" value="antclick-${version}"/>
<param name="path" value="${work.dir}"/>
</antcall>
<antcall target="make-tar">
<param name="filename" value="antclick-${version}"/>
<param name="path" value="${work.dir}"/>
</antcall>
</target>
<target name="client" depends="init">
<copy todir="static/fonts">
<fileset dir="${uikit.dir}/fonts" includes="**"/>
</copy>
<mkdir dir="static/scripts"/>
<exec executable="node_modules/.bin/browserify" output="static/scripts/main.min.js">
<arg line="build/client/main.js -d -p [minifyify --map /static/scripts/main.min.map.json --output static/scripts/main.min.map.json]"/>
</exec>
<exec executable="node_modules/.bin/browserify" output="static/scripts/editor.min.js">
<arg line="build/client/editor.js -d -p [minifyify --map /static/scripts/editor.min.map.json --output static/scripts/editor.min.map.json]"/>
</exec>
<mkdir dir="static/styles"/>
<exec executable="node_modules/.bin/lessc" output="static/styles/main.min.css">
<arg line="-x build/client/main.less"/>
</exec>
<exec executable="node_modules/.bin/lessc" output="static/styles/editor.min.css">
<arg line="--clean-css build/client/editor.less"/>
</exec>
</target>
<target name="server" depends="init">
<exec executable="node_modules/.bin/browserify" output="code/Global/0.node.js">
<arg line="build/server.js -d"/>
</exec>
<concat destfile="code/Global/0.node.js" append="true">
<fileset file="node_modules/less/dist/less-rhino-1.7.5.js"/>
<fileset file="node_modules/marked/lib/marked.js"/>
</concat>
</target>
<target name="docs" depends="init">
<exec dir="${build.dir}/jsdoc/toolkit" executable="${build.dir}/jsdoc/jsrunwrapper.sh">
<arg line='-D="title:${docs.title}" -q -r=2 -p -t=../templates/codeview
-d=${docs.outfiles} ${docs.infiles}'/>
</exec>
</target>
<target name="pot" depends="init">
<java dir="${helma.dir}" classpath="${helma.dir}/launcher.jar" classname="helma.main.launcher.Commandline"
fork="true">
<!-- Root.extractMessages is currently located in Global/i18n.js -->
<arg value="antville.extractMessages"/>
<arg value="${build.dir}/MessageParser.js"/>
<arg value="${i18n.scan}"/>
<arg value="${i18n.template}"/>
</java>
</target>
<target name="messages" depends="init">
<java dir="${helma.dir}" classpath="${helma.dir}/lib/rhino.jar"
classname="org.mozilla.javascript.tools.shell.Main">
<arg value="${build.dir}/PoParser.js"/>
<arg value="${i18n.poDirectory}"/>
<arg value="${i18n.destination}"/>
<arg value="${i18n.namespace}"/>
</java>
</target>
<target name="make-tar" depends="init">
<mkdir dir="${dist.dir}"/>
<fixcrlf srcdir="${path}" eol="lf" eof="remove" includes="**/*.txt,
**/*.properties, **/*.hac, **/*.js, **/*.skin, **/.xml, **/.sh"/>
<tar tarfile="${dist.dir}/${filename}.tar" basedir="${path}" excludes="**">
<tarfileset prefix="${filename}" dir="${path}" mode="755">
<include name="**/*.sh"/>
</tarfileset>
<tarfileset prefix="${filename}" dir="${path}">
<include name="**"/>
<exclude name="**/*.sh"/>
</tarfileset>
</tar>
<bzip2 zipfile="${dist.dir}/${filename}.tbz" src="${dist.dir}/${filename}.tar"/>
<delete file="${dist.dir}/${filename}.tar"/>
</target>
<target name="make-zip" depends="init">
<mkdir dir="${dist.dir}"/>
<fixcrlf srcdir="${path}" eol="crlf" includes="**/*.txt, **/*.properties, **/*.hac, **/*.js, **/*.skin, **/*.xml, **/.bat"/>
<zip zipfile="${dist.dir}/${filename}.zip">
<zipfileset dir="${path}" prefix="${filename}" includes="**"/>
</zip>
</target>
<target name="patch" depends="init">
<input message="Please enter the patch ID: " addproperty="patch.id"/>
<loadfile property="patch" srcFile="${basedir}/extra/updater/patch-${patch.id}.js"/>
<echo message="${patch}"/>
<input message="Apply the displayed patch? " validargs="y,n" addproperty="patch.confirm"/>
<condition property="patch.abort">
<equals arg1="${patch.confirm}" arg2="n" casesensitive="false" trim="true"/>
</condition>
<fail if="patch.abort">Build aborted by user.</fail>
<java dir="${helma.dir}" classpath="${helma.dir}/launcher.jar" classname="helma.main.launcher.Commandline" fork="true">
<arg value="antville.patch"/>
<arg value="${patch}"/>
</java>
</target>
<target name="+patch" depends="init">
<property name="patch.dir" value="extra/updater"/>
<echo file="${patch.dir}/patch-${file-date}.js">// Apply with enabled updater repository using `ant patch -Dpatch.id=${file-date}`${line.separator}<!--
-->var sql = new Sql();
</echo>
</target>
<target name="+claustra" depends="init">
<input message="Please enter the name of the new claustra: " addproperty="claustra.name"/>
<script language="javascript"><![CDATA[
name = project.getProperty('claustra.name');
firstLetter = name.substr(0, 1).toUpperCase();
title = firstLetter + name.substr(1);
project.setProperty('claustra.title', title);
]]></script>
<property name="claustra.dir" value="claustra/${claustra.name}/${claustra.title}"/>
<mkdir dir="${claustra.dir}"/>
<echo file="${claustra.dir}/${claustra.title}.properties" append="true">#sites = collection(Site)</echo>
<echo file="${claustra.dir}/${claustra.title}.js" append="true">${claustra.title}.prototype.main_action = function () {${line.separator}<!--
--> //res.debug(this.sites.count());${line.separator}<!--
-->};${line.separator}</echo>
<mkdir dir="${claustra.dir}/../Claustra"/>
<echo file="${claustra.dir}/../Claustra/Claustra.properties" append="true">${claustra.name} = mountpoint(${claustra.title})${line.separator}</echo>
</target>
<target name="clean" depends="init">
<delete dir="${work.dir}"/>
<delete dir="${dist.dir}"/>
</target>
<target name="file-exists" unless="file.exists">
<available property="file.exists" file="${file}"/>
</target>
<target name="debug" depends="init">
<!-- For debugging and testing purposes -->
</target>
</project>

View file

@ -1,481 +0,0 @@
// Jala Project [http://opensvn.csie.org/traccgi/jala]
//
// Copyright 2004 ORF Online und Teletext GmbH.
//
// Licensed under the Apache License, Version 2.0 (the ``License'');
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an ``AS IS'' BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview
* MessageParser script that extracts all gettext message macros
* out of skin files and all calls of gettext functions
* (that is "gettext", "ngettext" and "_") out of function
* files and directly generates a .pot file from it.
* If an argument "-o" is given and it is followed by
* a path to a file, the output is written to this file.
* Any other argument is interpreted as directory or file
* that should be parsed.
*/
/**
* @constructor
*/
var Message = function(id, pluralId) {
this.id = id && String(id);
this.pluralId = pluralId && String(pluralId);
this.locations = [];
return this;
};
/**
* Static method that constructs a message key by
* which a message can be identified in the messages map.
* @param {String} id The message Id
* @param {String} pluralId The plural message Id
* @returns The generated message key
* @type String
*/
Message.getKey = function(id, pluralId) {
if (id && pluralId) {
return id + pluralId;
} else {
return id;
}
};
/**
* Encloses the string passed as argument in quotes
* and wraps the string if it is longer than 80 characters.
* @param {String} str The string to format
* @param {Boolean} wrap If true the message string will be splitted in
* parts where each one is max. 80 characters long
* @returns The formatted string.
* @type String
*/
Message.formatId = function(str, wrap) {
var escapeQuotes = function(s) {
return s.replace(/(^|[^\\])"/g, '$1\\"');
};
var len = 80;
var buf = new java.lang.StringBuffer();
if (wrap == true && str.length > len) {
buf.append('""\n');
var offset = 0;
while (offset < str.length) {
buf.append('"');
buf.append(escapeQuotes(str.substring(offset, offset += len)));
buf.append('"');
buf.append("\n");
}
return buf.toString();
} else {
buf.append('"');
buf.append(escapeQuotes(str));
buf.append('"\n');
}
return buf.toString();
};
/**
* Adds a new location to this Message instance.
* @param {String} filePath The path to the file this message
* is located in.
* @param {Number} lineNum The line number at which this message
* was found at
*/
Message.prototype.addLocation = function(filePath, lineNum) {
this.locations.push(filePath + ":" + lineNum);
};
/**
* Writes this Message instance as .po compatible string to
* the StringBuffer passed as argument.
* @param {java.lang.StringBuffer} buf The StringBuffer instance
* to write into
*/
Message.prototype.write = function(buf) {
for (var i=0;i<this.locations.length;i++) {
buf.append("#: ");
buf.append(this.locations[i]);
buf.append("\n");
}
if (this.id.indexOf("{") > -1
|| (this.pluralId != null && this.pluralId.indexOf("{") > -1)) {
buf.append("#, java-format\n");
}
buf.append('msgid ');
buf.append(Message.formatId(this.id));
if (this.pluralId != null) {
buf.append('msgid_plural ');
buf.append(Message.formatId(this.pluralId));
buf.append('msgstr[0] ""\nmsgstr[1] ""\n')
} else {
buf.append('msgstr ""\n')
}
buf.append("\n");
return;
};
/**
* @constructor
*/
var MessageParser = function() {
this.messages = {};
return this;
};
/**
* Object containing the accepted function names, currently
* supported are "gettext", "ngettext" and "_". This is used
* as a lookup map during function file parsing.
* @type Object
*/
MessageParser.FUNCTION_NAMES = {
"_": true,
"gettext": true,
"ngettext": true,
"markgettext": true,
"cgettext": true
};
/**
* The name of the gettext macro
* @type String
*/
MessageParser.MACRO_NAME = "message";
/**
* The name of the macro attribute that will be interpreted
* as gettext attribute.
* @type String
*/
MessageParser.ATTRIBUTE_NAME = MessageParser.MACRO_NAME;
/**
* A regular expression for parsing macros in a skin. The result
* of this regular expression contains:
* result[1] = macro handler name (can be empty for global macros)
* result[2] = macro name
* result[3] = the macro's attributes
* @type RegExp
*/
MessageParser.REGEX_MACRO = /<%\s*(?:([\w]+)\.)?([\w]+)\s+([^%]+?)\s*%>/gm;
/**
* A regular expression for parsing the attributes of a macro. The result
* of this regular expression contains:
* result[1] = attribute name
* result[2] = attribute value
* @type RegExp
*/
MessageParser.REGEX_PARAM = /([\w]*)\s*=\s*["'](.*?)["']\s*(?=\w+=|$)/gm;
/**
* Calculates the line number in the string passed as argument
* at which the specified index position is located.
* @param {String} str The source string
* @param {Number} idx The index position to get the line number for.
* @returns The line number of the index position in the source string.
* @type Number
*/
MessageParser.getLineNum = function(str, idx) {
return str.substring(0, idx).split(/.*(?:\r\n|\n\r|\r|\n)/).length;
};
/**
* Parses the file passed as argument. If the file
* is a directory, this method recurses down the directory
* tree and parses all skin and function files.
* @param {java.io.File} file The file or directory to start at.
* @param {String} encoding The encoding to use
*/
MessageParser.prototype.parse = function(file, encoding) {
if (file.isDirectory()) {
var list = file.list();
for (var i=0;i<list.length;i++) {
this.parse(new java.io.File(file, list[i]), encoding);
}
} else {
var fName, dotIdx;
fName = file.getName();
if ((dotIdx = fName.lastIndexOf(".")) > -1) {
switch (String(fName.substring(dotIdx+1))) {
case "skin":
print("Parsing skin file " + file.getCanonicalPath() + "...");
this.parseSkinFile(file, encoding);
break;
case "hac":
case "js":
print("Parsing function file " + file.getCanonicalPath() + "...");
this.parseFunctionFile(file, encoding);
break;
default:
break;
}
}
}
return;
};
/** @ignore */
MessageParser.prototype.toString = function() {
return "[Jala Message Parser]";
};
/**
* Parses a .js file and creates Message instances for all
* calls of "gettext", "ngettext", "markgettext" and "_".
* @param {java.io.File} file The function file to parse
* @param {String} encoding The encoding to use
*/
MessageParser.prototype.parseFunctionFile = function(file, encoding) {
var fis = new java.io.FileInputStream(file);
var isr = new java.io.InputStreamReader(fis, encoding || "UTF-8");
var reader = new java.io.BufferedReader(isr);
var tokenizer = new java.io.StreamTokenizer(reader);
var messages = [], stack = [];
var c;
while ((c = tokenizer.nextToken()) != java.io.StreamTokenizer.TT_EOF) {
switch (c) {
case java.io.StreamTokenizer.TT_WORD:
if (MessageParser.FUNCTION_NAMES[tokenizer.sval] == true) {
stack.push({name: tokenizer.sval, lineNr: tokenizer.lineno()});
} else if (stack.length > 0) {
// it's something else than a string argument inside a gettext method call
// so finalize the argument parsing here as we aren't interested in that
messages.push(stack.pop());
}
break;
case java.io.StreamTokenizer.TT_NUMBER:
break;
default:
if (stack.length > 0) {
if ("\u0028".charCodeAt(0) == c) {
// start of arguments (an opening bracket)
stack[stack.length-1].args = [];
} else if ("\u0029".charCodeAt(0) == c) {
// end of arguments (a closing bracket)
messages.push(stack.pop());
} else if ("\u0022".charCodeAt(0) == c || "\u0027".charCodeAt(0) == c) {
// a quoted string argument
stack[stack.length-1].args.push(tokenizer.sval);
}
}
break;
}
}
if (messages.length > 0) {
var msgParam, key, msg;
for (var i=0;i<messages.length;i++) {
msgParam = messages[i];
if (msgParam.args && msgParam.args.length > 0) {
if (msgParam.name === "cgettext" || msgParam.name === "markgettext") {
msgParam.args[0] = cgettext.getKey(msgParam.args[0], msgParam.args[1]);
delete msgParam.args[1];
}
key = Message.getKey(msgParam.args[0]);
if (!(msg = this.messages[key])) {
this.messages[key] = msg = new Message(msgParam.args[0], msgParam.args[1]);
}
if (!msg.pluralId && msgParam.args.length > 1) {
msg.pluralId = msgParam.args[1];
}
msg.addLocation(file.getCanonicalPath(), msgParam.lineNr);
}
}
}
fis.close();
isr.close();
reader.close();
return;
};
/**
* =================================================
* FIXME: This is a patched version of the method in
* jala/util/HopKit/scripts/MessageParser.js
* It needs skin/macro introspection features enabled
* in Helma. See also the file Skin.java.patch.
* ==================================================
* Parses a skin file and creates Message instances for
* all macros which name is either "message" or
* that have attributes named "message" and optional
* "plural"
* @param {java.io.File} file The skin file to parse
* @param {String} encoding The encoding to use
*/
MessageParser.prototype.parseSkinFile = function(file, encoding) {
var self = this;
var source = readFile(file.getAbsolutePath(), encoding || "UTF-8");
var checkNestedMacros = function(iterator) {
var macros = [];
while (iterator.hasNext()) {
macro = iterator.next();
if (macro && macro.constructor !== String) {
macros.push(macro);
}
}
processMacros(macros);
}
var processMacros = function(macros) {
var re = gettext_macro.REGEX;
var id, pluralId, name, args, param, key, msg;
for each (var macro in macros) {
id = pluralId = null;
name = macro.getName();
param = macro.getNamedParams();
if (param) {
checkNestedMacros(param.values().iterator());
if (name === MessageParser.MACRO_NAME) {
id = param.get("text");
pluralId = param.get("plural");
} else if (param.containsKey("message") === MessageParser.ATTRIBUTE_NAME) {
id = param.get("message");
pluralId = param.get("plural");
}
}
args = macro.getPositionalParams();
if (args) {
checkNestedMacros(args.iterator());
if (name === "gettext" || name === "markgettext") {
id = cgettext.getKey(args.get(0), param && param.get("context"));
} else if (name === "ngettext") {
id = args.get(0);
pluralId = args.get(1);
}
}
if (id != null) {
if (id.constructor !== String) {
continue;
}
// create new Message instance or update the existing one
id = id.replace(re, String.SPACE);
pluralId && (pluralId = pluralId.replace(re, String.SPACE));
key = Message.getKey(id);
if (!(msg = self.messages[key])) {
self.messages[key] = msg = new Message(id, pluralId, file.getCanonicalPath());
}
msg.addLocation(file.getCanonicalPath(), MessageParser.getLineNum(source, macro.start));
}
}
}
var skin = createSkin(source);
if (skin.hasMainskin()) {
processMacros(skin.getMacros());
}
for each (var name in skin.getSubskinNames()) {
var subskin = skin.getSubskin(name);
processMacros(subskin.getMacros());
}
return;
}
/**
* FIXME: Patched with adequate header data
* Prints a standard Header of a .po file
* FIXME: why the hell is Plural-Forms ignored in poEdit?
* @see http://drupal.org/node/17564
*/
MessageParser.prototype.getPotString = function() {
var date = new Date;
var buf = new java.lang.StringBuffer();
buf.append('#\n');
buf.append('# The Antville Project\n');
buf.append('# http://code.google.com/p/antville\n');
buf.append('#\n');
buf.append('# Copyright 2001-' + date.getFullYear() + ' by the Workers of Antville.\n');
buf.append('#\n');
buf.append("# Licensed under the Apache License, Version 2.0 (the ``License''\n");
buf.append('# you may not use this file except in compliance with the License.\n');
buf.append('# You may obtain a copy of the License at\n');
buf.append('#\n');
buf.append('# http://www.apache.org/licenses/LICENSE-2.0\n');
buf.append('#\n');
buf.append('# Unless required by applicable law or agreed to in writing, software\n');
buf.append("# distributed under the License is distributed on an ``AS IS'' BASIS,\n");
buf.append('# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n');
buf.append('# See the License for the specific language governing permissions and\n');
buf.append('# limitations under the License.\n');
buf.append('#\n\n');
buf.append('#, fuzzy\n');
buf.append('msgid ""\n');
buf.append('msgstr ""\n');
buf.append('"Project-Id-Version: Antville-' + Root.VERSION + '\\n"\n');
buf.append('"Report-Msgid-Bugs-To: mail@antville.org\\n"\n');
var sdf = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mmZ");
buf.append('"POT-Creation-Date: ' + sdf.format(new java.util.Date()) + '\\n"\n');
buf.append('"PO-Revision-Date: ' + sdf.format(new java.util.Date()) + '\\n"\n');
//buf.append('"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n"\n');
buf.append('"Language-Team: The Antville People <mail@antville.org>\\n"\n');
buf.append('"MIME-Version: 1.0\\n"\n');
buf.append('"Content-Type: text/plain; charset=utf-8\\n"\n');
buf.append('"Content-Transfer-Encoding: 8bit\\n"\n');
buf.append('"Plural-Forms: nplurals=2; plural=(n != 1);\\n"\n');
buf.append('\n');
// sort all messages by their singular key
var keys = [];
for (var i in this.messages) {
keys[keys.length] = this.messages[i].id;
}
keys.sort();
// add all the messages
for (var i=0;i<keys.length;i++) {
this.messages[keys[i]].write(buf);
}
return new java.lang.String(buf);
};
/**
* Write the parsed contents into the file passed as argument.
* @param {java.io.File} file The file to write to
*/
MessageParser.prototype.writeToFile = function(file) {
var writer = new java.io.FileWriter(file);
writer.write(new java.lang.String(this.getPotString().getBytes("UTF-8")));
writer.close();
return;
};
/**
* Main script body
*/
var toParse = [];
var arg, outFile, file, fileEncoding;
for (var i=0;i<arguments.length;i++) {
arg = arguments[i];
if (arg.indexOf("-o") === 0 && i < arguments.length -1) {
outFile = new java.io.File(arguments[i += 1]);
} else if (arg.indexOf("-e") === 0 && i < arguments.length -1) {
fileEncoding = arguments[i += 1];
} else {
// add argument to list of files and directories to parse
toParse.push(new java.io.File(arg));
}
}
// start parsing
var parser = new MessageParser();
for (var i=0;i<toParse.length;i++) {
parser.parse(toParse[i], fileEncoding);
}
if (outFile != null) {
parser.writeToFile(outFile);
} else {
print(parser.getPotString());
}

View file

@ -1,328 +0,0 @@
// Jala Project [http://opensvn.csie.org/traccgi/jala]
//
// Copyright 2004 ORF Online und Teletext GmbH.
//
// Licensed under the Apache License, Version 2.0 (the ``License'');
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an ``AS IS'' BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview
* A parser script that converts GNU Gettext .po files into plain JavaScript objects
* for use with jala.I18n. To run it either start the build script of HopKit
* or call it directly using the JavaScript shell of Rhino:
* <code>java -cp rhino.jar org.mozilla.javascript.tools.shell.Main PoParser.js <input> <output> [namespace]</code>
*
* The accepted arguments are:
* <ul>
* <li><code>input</code>: Either a single .po file or a directory containing multiple files</li>
* <li><code>output</code>: The directory where to put the generated message files</li>
* <li><code>namespace</code>: An optional namespace in which the generated message object will reside
* (eg. if the namespace is called "jala", the messages will be stored in global.jala.messages)</li>
* </ul>
*/
/**
* Constructs a new PoParser instance.
* @class Instances of this class can generate JavaScript message files out
* of GNU Gettext .po files for use with jala.I18n (and possibly other internationalization
* environments too).
* @param {String} handler An optional namespace where the parsed messages should be stored
* @returns A newly created instance of PoParser
* @constructor
*/
var PoParser = function(namespace) {
/**
* An array containing the parsed messages
* @type Array
*/
this.messages = [];
/**
* The locale key string (eg. "de_AT") of the .po file
* @type String
*/
this.localeKey = null;
/**
* The namespace (optional) where to store the generated messages
* @type String
*/
this.namespace = namespace;
return this;
};
/**
* A regular expression for splitting the contents of a .po file into
* single lines
* @type RegExp
*/
PoParser.REGEX_LINES = /\r\n|\r|\n|\u0085|\u2028|\u2029/;
/**
* A regular expression for parsing singular message keys
* @type RegExp
*/
PoParser.REGEX_MSGID = /^\s*msgid(?!_plural)\s+\"(.*)\"\s*$/;
/**
* A regular expression for parsing plural message keys
* @type RegExp
*/
PoParser.REGEX_MSGID_PLURAL = /^\s*msgid_plural\s+\"(.*)\"\s*$/;
/**
* A regular expression for parsing message key continuations
* @type RegExp
*/
PoParser.REGEX_MSG_CONT = /^\s*\"(.*)\"\s*$/;
/**
* A regular expression for parsing a message translation
* @type RegExp
*/
PoParser.REGEX_MSGSTR = /^\s*msgstr(?:\[(\d)\])?\s+\"(.*)\"\s*$/;
/**
* A regular expression used to detect lines other than whitespace
* and comments
* @type RegExp
*/
PoParser.REGEX_DATA = /^\s*msg/;
PoParser.isData = function(str) {
return PoParser.REGEX_DATA.test(str);
};
/**
* Reads the file passed as argument, assuming that it is UTF-8 encoded
* @param {java.io.File} file The file to read
* @returns The contents of the file
* @type java.lang.String
*/
PoParser.readFile = function(file) {
var inStream = new java.io.InputStreamReader(new java.io.FileInputStream(file), "UTF-8");
var buffer = new java.lang.reflect.Array.newInstance(java.lang.Character.TYPE, 2048);
var read = 0;
var r = 0;
while ((r = inStream.read(buffer, read, buffer.length - read)) > -1) {
read += r;
if (read == buffer.length) {
// grow input buffer
var newBuffer = new java.lang.reflect.Array.newInstance(java.lang.Character.TYPE, buffer.length * 2);
java.lang.System.arraycopy(buffer, 0, newBuffer, 0, buffer.length);
buffer = newBuffer;
}
}
inStream.close();
return new java.lang.String(buffer, 0, read);
}
/**
* Parses the PO file passed as argument into the messages array
* of this PoParser instance.
* @param {java.io.File} file The .po file to parse
*/
PoParser.prototype.parse = function(file) {
// parse the locale key out of the file name
var fileName = file.getName();
if (!(this.localeKey = fileName.substring(0, fileName.indexOf(".")))) {
throw "Invalid PO file name: " + fileName;
}
// read the PO file content and parse it into messages
var content = PoParser.readFile(file);
var start = new Date();
var lines = content.split(PoParser.REGEX_LINES);
var idx = -1;
var line = null;
var m, value, nr;
var msg;
var hasMoreLines = function() {
return idx < lines.length - 1;
};
var nextLine = function() {
return (line = lines[idx += 1]) != null;
};
var getContinuation = function(str) {
var nLine;
while ((nLine = lines[idx + 1]) != null) {
if ((m = nLine.match(PoParser.REGEX_MSG_CONT)) != null) {
str += m[1];
nextLine();
} else {
break;
}
}
return str;
}
while (nextLine()) {
if ((m = line.match(PoParser.REGEX_MSGID)) != null) {
value = getContinuation(m[1]);
if (value) {
msg = this.messages[this.messages.length] = new Message(value);
}
} else if ((m = line.match(PoParser.REGEX_MSGID_PLURAL)) != null) {
value = getContinuation(m[1]);
if (value && msg != null) {
msg.pluralKey = value;
}
} else if ((m = line.match(PoParser.REGEX_MSGSTR)) != null) {
nr = m[1];
value = getContinuation(m[2]);
if (value && msg != null) {
nr = parseInt(nr, 10);
msg.translations[nr || 0] = value;
}
}
}
return;
};
/**
* Converts the array containing the parsed messages into a message
* catalog script file and saves it on disk.
* @param {java.io.File} outputDir The directory where the message
* file should be saved
*/
PoParser.prototype.writeToFile = function(output) {
var buf = new java.lang.StringBuffer();
// write header
buf.append('/**\n');
buf.append(' * Instantiate the messages namespace if it\'s not already existing\n');
buf.append(' */\n');
var objPath = "";
if (this.namespace) {
objPath += this.namespace;
buf.append('if (!global.' + objPath + ') {\n');
buf.append(' global.' + objPath + ' = {};\n');
buf.append('}\n');
objPath += ".";
}
objPath += "messages";
buf.append('if (!global.' + objPath + ') {\n');
buf.append(' global.' + objPath + ' = {};\n');
buf.append('}\n\n');
buf.append('/**\n');
buf.append(' * Messages for locale "' + this.localeKey + '"\n');
buf.append(' */\n');
var fname = objPath + "." + this.localeKey + ".js";
objPath += "['" + this.localeKey + "']";
buf.append('global.' + objPath + ' = {\n');
// write messages
for (var i=0;i<this.messages.length; i++) {
this.messages[i].write(buf);
}
// write footer
buf.append('};\n');
// write the message catalog into the outFile
var file = new java.io.File(output, fname);
var writer = new java.io.FileWriter(file);
writer.write(new java.lang.String(buf.toString().getBytes("UTF-8")));
writer.close();
print("generated messages file " + file.getAbsolutePath());
return;
};
/**
* Constructs a new message object containing the singular- and
* plural key plus their translations
* @param {String} singularKey The singular key of the message
* @returns A newly created Message instance
* @constructor
*/
var Message = function(singularKey) {
this.singularKey = singularKey;
this.pluralKey = null;
this.translations = [];
return this;
}
/**
* Dumps this message as JavaScript literal key-value pair(s)
* @param {java.lang.StringBuffer} buf The buffer to append the dumped
* string to
*/
Message.prototype.write = function(buf) {
var writeLine = function(key, value) {
buf.append(' "');
buf.append(key);
buf.append('": "');
if (value !== null && value !== undefined) {
buf.append(value);
}
buf.append('",\n');
};
if (this.singularKey != null) {
writeLine(this.singularKey, this.translations[0]);
if (this.pluralKey != null) {
writeLine(this.pluralKey, this.translations[1]);
}
}
return;
}
/**
* Main script body
*/
if (arguments.length < 2) {
print("Usage:");
print("PoParser.js <input> <output> [namespace]");
print("<input>: Either a single .po file or a directory containing .po files");
print("<output>: The directory where the generated messages files should be stored");
print("[namespace]: An optional global namespace where the messages should be");
print(" stored (eg. a namespace like 'jala' will lead to messages");
print(" stored in global.jala.messages by their locale.");
quit();
}
var input = new java.io.File(arguments[0]);
var output = new java.io.File(arguments[1]);
var namespace = arguments[2];
// check if the output destination is a directory
if (output.isFile()) {
print("Invalid arguments: the output destination must be a directory.");
quit();
}
if (namespace && namespace.indexOf(".") != -1) {
print("Invalid arguments: Please don't specify complex object paths, as this");
print("would corrupt the messages file.");
quit();
}
// parse the PO file(s) and create the message catalog files
var parser;
if (input.isDirectory()) {
var files = input.listFiles();
var file;
for (var i=0;i<files.length;i++) {
file = files[i];
if (file.getName().endsWith(".po")) {
parser = new PoParser(namespace);
parser.parse(file);
parser.writeToFile(output);
}
}
} else {
parser = new PoParser(namespace);
parser.parse(input);
parser.writeToFile(output);
}

View file

@ -1,2 +0,0 @@
@import (inline) 'node_modules/codemirror/lib/codemirror.css';
@import (inline) 'node_modules/uikit-bower/css/components/htmleditor.almost-flat.css';

View file

@ -1,172 +0,0 @@
window.$ = window.jQuery = require('jquery');
jQuery.md5 = require('js-md5/src/md5');
require('jquery-collagePlus/jquery.collagePlus');
require('jquery-collagePlus/extras/jquery.collageCaption');
require('jquery-collagePlus/extras/jquery.removeWhitespace');
require('uikit-bower/js/uikit');
require('uikit-bower/js/components/form-password');
require('uikit-bower/js/components/tooltip');
require('uikit-bower/js/components/upload');
$(function() {
// Extend jQuery with selectText() method.
$.fn.selectText = function() {
var element = this.get(0);
if (document.body.createTextRange) { // ms
var range = document.body.createTextRange();
range.moveToElementText(element);
range.select();
} else if (window.getSelection) { // moz, opera, webkit
var selection = window.getSelection();
var range = document.createRange();
range.selectNodeContents(element);
selection.removeAllRanges();
selection.addRange(range);
}
};
// Highlight the current navigation menu item
var counter = 0;
$('.uk-nav li').each(function (index, element) {
if (counter > 0) {
return;
}
var href = String($(element).find('a').attr('href')) + location.hash;
var index = location.href.lastIndexOf(href);
if (href && index > -1 && index + href.length === location.href.length) {
$(element).addClass('uk-active');
counter += 1;
}
});
// Prevent redundant submits of a form
$('form').one('submit', function (event) {
var submit = $(this).find('[type=submit]');
setTimeout(function () {
submit.attr('disabled', true);
}, 1);
});
// Show prompt to copy macro code
$('a.av-clipboard-copy').on('click', function (event) {
event.preventDefault();
prompt($(this).data('text'), $(this).data('value'));
});
// Select the macro code when clicking on elements with the macro-code class.
// FIXME: Obsolete (should move to compat layer)
$('.macro-code').click(function(event) {
$(this).selectText();
});
// Compatibility: Go back when cancel link is clicked
$('a.cancel').on('click', function (event) {
event.preventDefault();
history.back()
});
// Add the skin controls for the layout sandbox
/*$('body').prepend($('<div>').attr('class', 'layout-sandbox')
.append($('<div>')
.append($('<button>')
.html('Exit Sandbox')
.click(function() {
location.replace($('a[href$='sandbox']').attr('href'));
}))));*/
$('.av-skin').each(function() {
var skinButton = $('<span class="av-skin-control"><a class="av-skin-edit-link">');
skinButton.find('a').attr({
'data-uk-tooltip': true,
href: $(this).data('href'),
title: 'Click to edit ' + $(this).data('name') + ' skin'
}).mouseover(function() {
$(this).parents('.av-skin').eq(0).addClass('av-skin-active');
}).mouseout(function() {
$(this).parents('.av-skin').eq(0).removeClass('av-skin-active');
}).html('<i class="uk-icon-pencil"></i>');
$(this).prepend(skinButton);
});
});
Antville = {};
Antville.prefix = 'Antville_';
Antville.encode = function(str) {
var chars = ['&', '<', '>', '\''];
for (var i in chars) {
var c = chars[i];
var re = new RegExp(c, 'g');
str = str.replace(re, '&#' + c.charCodeAt() + ';');
}
return str;
};
Antville.decode = function(str) {
return str.replace(/&amp;/g, '&');
};
Antville.Referrer = function(url, text, count) {
this.url = url;
var re = new RegExp('https?://(?:www\.)?');
this.text = String(text).replace(re, '');
var pos = this.text.lastIndexOf('/');
if (pos === this.text.length - 1) {
this.text = this.text.substr(0, pos);
}
this.count = parseInt(count, 10);
this.compose = function(prefix, key) {
prefix || (prefix = '');
var query = new Antville.Query(this.url);
if (query[key]) {
return prefix + ' ' + Antville.encode(query[key]);
}
return this.text;
}
return this;
};
Antville.Query = function(str) {
if (str == undefined)
var str = location.search.substring(1);
else if (str.indexOf('?') > -1)
var str = str.split('?')[1];
if (str == '')
return this;
var parts = Antville.decode(decodeURIComponent(str)).split('&');
for (var i in parts) {
var pair = parts[i].split('=');
var key = pair[0];
if (key) {
key = key.replace(/\+/g, ' ');
var value = pair[1];
if (value)
value = value.replace(/\+/g, ' ');
this[key] = value;
}
}
return this;
};
Antville.Filter = function(def, key) {
this.key = key;
if (def == null)
this.items = [];
else if (def instanceof Array)
this.items = def;
else
this.items = def.replace(/\r/g, '\n').split('\n');
this.test = function(str) {
if (!str)
return false;
str = str.replace(/&amp;/g, '&');
for (var n in this.items) {
var re = new RegExp(this.items[n], 'i');
if (re.test(str))
return true;
}
return false;
}
return this;
};

View file

@ -1,5 +0,0 @@
@import (inline) 'node_modules/uikit-bower/css/uikit.almost-flat.css';
@import (inline) 'node_modules/uikit-bower/css/components/form-password.almost-flat.css';
@import (inline) 'node_modules/uikit-bower/css/components/tooltip.almost-flat.css';
@import './sprites';

Binary file not shown.

Binary file not shown.

View file

@ -1,12 +0,0 @@
H2 is dual licensed and available under a modified version of the MPL 1.1 (Mozilla Public License) or under the (unmodified) EPL 1.0 (Eclipse Public License). The changes to the MPL are underlined. There is a License FAQ for both the MPL and the EPL, most of that is applicable to the H2 License as well.
* You can use H2 for free. You can integrate it into your application (including commercial applications), and you can distribute it.
* Files containing only your code are not covered by this license (it is 'commercial friendly').
* Modifications to the H2 source code must be published.
* You don't need to provide the source code of H2 if you did not modify anything.
However, nobody is allowed to rename H2, modify it a little, and sell it as a database engine without telling the customers it is in fact H2. This happened to HSQLDB: a company called 'bungisoft' copied HSQLDB, renamed it to 'RedBase', and tried to sell it, hiding the fact that it was in fact just HSQLDB. It seems 'bungisoft' does not exist any more, but you can use the Wayback Machine and visit old web pages of http://www.bungisoft.com.
About porting the source code to another language (for example C# or C++): converted source code (even if done manually) stays under the same copyright and license as the original code. The copyright of the ported source code does not (automatically) go to the person who ported the code.
For the full license text see http://www.h2database.com/html/license.html.

Binary file not shown.

Binary file not shown.

View file

@ -1,23 +0,0 @@
# The Antville Project
# http://code.google.com/p/antville
#
# Copyright 20012014 by the Workers of Antville.
#
# Licensed under the Apache License, Version 2.0 (the ``License'');
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an ``AS IS'' BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
country = AT
language = en
smtp = localhost
# Login to manage console: admin/admin
adminAccess = 32ff9ee7e841b26a966870c144fdcaec
allowAdmin = 127.0.0.1, ::1

View file

@ -1,83 +0,0 @@
::
:: The Antville Project
:: http://code.google.com/p/antville
::
:: Copyright 20012014 by the Workers of Antville.
::
:: Licensed under the Apache License, Version 2.0 (the ``License'');
:: you may not use this file except in compliance with the License.
:: You may obtain a copy of the License at
::
:: http://www.apache.org/licenses/LICENSE-2.0
::
:: Unless required by applicable law or agreed to in writing, software
:: distributed under the License is distributed on an ``AS IS'' BASIS,
:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
:: See the License for the specific language governing permissions and
:: limitations under the License.
::
@echo off
set JAVA_HOME=
set HOP_HOME=
set HTTP_PORT=
set XMLRPC_PORT=
set AJP13_PORT=
set RMI_PORT=
set CONFIG_FILE=
set OPTIONS=
set HTTP_PORT=8080
rem set XMLRPC_PORT=8081
rem set AJP13_PORT=8009
rem set RMI_PORT=5050
rem set CONFIGFILE=./etc/jetty.xml
rem set HOP_HOME="c:\program files\helma"
rem set JAVA_HOME="c:\program files\java"
set JAVA_OPTIONS=-Djava.awt.headless=true -Dfile.encoding=utf-8
set INSTALL_DIR=%~d0%~p0
if "%JAVA_HOME%"=="" goto default
set JAVACMD=%JAVA_HOME%\bin\java
goto end
:default
set JAVACMD=java
:end
if "%HOP_HOME%"=="" (
set HOP_HOME=%INSTALL_DIR%
)
cd %HOP_HOME%
if not "%CONFIG_FILE%"=="" (
echo Using configuration file %CONFIG_FILE%
set OPTION=%OPTIONS% -c %CONFIG_FILE%
goto java
)
if not "%HTTP_PORT%"=="" (
echo Starting HTTP server on port %HTTP_PORT%
set OPTIONS=%OPTIONS% -w %HTTP_PORT%
)
if not "%XMLRPC_PORT%"=="" (
echo Starting XML-RPC server on port %XMLRPC_PORT%
set OPTIONS=%OPTIONS% -x %XMLRPC_PORT%
)
if not "%AJP13_PORT%"=="" (
echo Starting AJP13 listener on port %AJP13_PORT%
set OPTIONS=%OPTIONS% -jk %AJP13_PORT%
)
if not "%RMI_PORT%"=="" (
echo Starting RMI server on port %RMI_PORT%
set OPTIONS=%OPTIONS% -p %RMI_PORT%
)
if not "%HOP_HOME%"=="" (
echo Serving applications from %HOP_HOME%
set OPTIONS=%OPTIONS% -h "%HOP_HOME%
)
:java
%JAVACMD% %JAVA_OPTIONS% -jar "%INSTALL_DIR%\launcher.jar" %OPTIONS%

View file

@ -1,80 +0,0 @@
# The Antville Project
# http://code.google.com/p/antville
#
# Copyright 20012014 by the Workers of Antville.
#
# Licensed under the Apache License, Version 2.0 (the ``License'');
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an ``AS IS'' BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#!/bin/sh
HTTP_PORT=8080
#XMLRPC_PORT=8081
#AJP13_PORT=8009
#RMI_PORT=5050
#CONFIG_FILE=./etc/jetty.xml
#JAVA_HOME=/usr/lib/java
#HOP_HOME=/usr/local/helma
JAVA_OPTIONS="-Djava.awt.headless=true -Dfile.encoding=utf-8"
if [ "$JAVA_HOME" ]; then
JAVACMD="$JAVA_HOME/bin/java"
# Check if java command is executable
if [ ! -x $JAVACMD ]; then
echo "Warning: JAVA_HOME variable may be set incorrectly:"
echo " No executable found at $JAVACMD"
fi
else
JAVACMD=java
fi
INSTALL_DIR="${0%/*}"
cd $INSTALL_DIR
INSTALL_DIR=$PWD
if [ -z "$HOP_HOME" ]; then
HOP_HOME="${0%/*}"
cd $HOP_HOME
HOP_HOME=$PWD
else
cd $HOP_HOME
fi
echo "Starting Helma in directory $HOP_HOME"
if [ "$CONFIG_FILE" ]; then
SWITCHES="$SWITCHES -c $CONFIG_FILE"
echo Using configuration file $CONFIG_FILE
else
if [ "$HTTP_PORT" ]; then
SWITCHES="$SWITCHES -w $HTTP_PORT"
echo Starting HTTP server on port $HTTP_PORT
fi
if [ "$XMLRPC_PORT" ]; then
SWITCHES="$SWITCHES -x $XMLRPC_PORT"
echo Starting XML-RPC server on port $XMLRPC_PORT
fi
if [ "$AJP13_PORT" ]; then
SWITCHES="$SWITCHES -jk $AJP13_PORT"
echo Starting AJP13 listener on port $AJP13_PORT
fi
if [ "$RMI_PORT" ]; then
SWITCHES="$SWITCHES -p $RMI_PORT"
echo Starting RMI server on port $RMI_PORT
fi
if [ "$HOP_HOME" ]; then
SWITCHES="$SWITCHES -h $HOP_HOME"
fi
fi
$JAVACMD $JAVA_OPTIONS -jar "$INSTALL_DIR/launcher.jar" $SWITCHES

View file

@ -1,5 +0,0 @@
#!/bin/sh
# Simple wrapper for the JSDoc runner which is checked out
# from the JSDoc repository w/o executable permission.
. jsrun.sh

View file

@ -1,18 +0,0 @@
{! Link.base = ""; /* all generated links will be relative to this */ !}
{+subtemplate("subtemplates/head.tmpl", {subtitle: "Class Index"})+}
{+subtemplate("subtemplates/menu.tmpl")+}
<div class="content">
<div class="innerContent">
<h1 class="classTitle"><span>Class Index</span></h1>
<ul id="ClassList2">
<for each="thisClass" in="data">
<li>
<h2 class="classname">{+(new Link().toSymbol(thisClass.alias))+}</h2>
<p>{+resolveLinks(summarize(thisClass.classDesc))+}</p>
</li>
</for>
</ul>
</div>
</div>
{+subtemplate("subtemplates/foot.tmpl")+}

View file

@ -1,39 +0,0 @@
{! Link.base = ""; /* all generated links will be relative to this */ !}
{+subtemplate("subtemplates/head.tmpl", {subtitle: "File Index"})+}
{+subtemplate("subtemplates/menu.tmpl")+}
<div class="content">
<div class="innerContent">
<h1 class="classTitle"><span>File Index</span></h1>
<ul class="fileList" id="FileList">
<for each="item" in="data">
<li>
<h2 class="filename">{+new Link().toSrc(item.alias).withText(item.name)+}</h2>
<if test="item.desc">{+resolveLinks(item.desc)+}</if>
<dl class="detailList">
<if test="item.author">
<dt class="heading">Author:</dt>
<dd>{+item.author+}</dd>
</if>
<if test="item.version">
<dt class="heading">Version:</dt>
<dd>{+item.version+}</dd>
</if>
{! var locations = item.comment.getTag('location').map(function($){return $.toString().replace(/(^\$ ?| ?\$$)/g, '').replace(/^HeadURL: https:/g, 'http:');}) !}
<if test="locations.length">
<dt class="heading">Location:</dt>
<for each="location" in="locations">
<dd><a href="{+location+}">{+location+}</a></dd>
</for>
</if>
</dl>
</li>
</for>
</ul>
</div>
</div>
{+subtemplate("subtemplates/foot.tmpl")+}

View file

@ -1,679 +0,0 @@
{! Link.base = "../"; /* all generated links will be relative to this */ !}
{+subtemplate("subtemplates/head.tmpl", {subtitle: data.alias})+}
{+subtemplate("subtemplates/menu.tmpl")+}
<div class="content">
<div class="innerContent">
<h1 class="classTitle">
{!
var classType = "";
if (data.isBuiltin()) {
classType += "Built-In ";
}
if (data.isNamespace) {
if (data.is('FUNCTION')) {
classType += "Function ";
}
classType += "Namespace ";
} else {
classType += "Class ";
}
!}
{+classType+}<span>{+data.alias+}</span>
</h1>
<div class="intro">
<p class="description summary">
{+resolveLinks(data.classDesc)+}
</p>
<if test="data.version || !data.isBuiltin() || data.augments.length">
<ul class="summary">
<if test="data.version">
<li>Version {+ data.version +}</li>
</if>
<if test="!data.isBuiltin()">{# isn't defined in any file #}
<li>Defined in: {+new Link().toSrc(data.srcFile)+}</li>
</if>
<if test="data.augments.length"><li>Extends <span class="fixedFont">
{+
data.augments
.sort()
.map(
function($) { return new Link().toSymbol($); }
)
.join(", ")
+}</span></li>
</if>
</ul>
</if>
</div>
<if test="!data.isBuiltin() && (data.isNamespace || data.is('CONSTRUCTOR'))">
<div class="props">
<table class="summaryTable" cellspacing="0" summary="A summary of the constructor documented in the class {+data.alias+}.">
<caption class="sectionTitle">{+classType+}Summary</caption>
<thead>
<tr>
<th scope="col">Constructor Attributes</th>
<th scope="col">Constructor Name and Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="attributes">{!
if (data.isPrivate) output += "&lt;private&gt; ";
if (data.isInner) output += "&lt;inner&gt; ";
!}&nbsp;</td>
<td class="nameDescription" {!if (data.comment.getTag("hilited").length){output += 'style="color: red"'}!}>
<div class="fixedFont">
<b>{+ new Link().toSymbol(data.alias).inner('constructor')+}</b><if test="classType != 'Namespace '">{+ makeSignature(data.params) +}</if>
</div>
<div class="description">{+resolveLinks(summarize(data.desc))+}</div>
</td>
</tr>
</tbody>
</table>
</div>
</if>
<if test="data.properties.length">
{! var ownProperties = data.properties.filter(function($){return $.memberOf == data.alias && !$.isNamespace}).sort(makeSortby("name")); !}
<if test="ownProperties.length">
<div class="props">
<table class="summaryTable" cellspacing="0" summary="A summary of the fields documented in the class {+data.alias+}.">
<caption class="sectionTitle">Field Summary</caption>
<thead>
<tr>
<th scope="col">Field Attributes</th>
<th scope="col">Field Name and Description</th>
</tr>
</thead>
<tbody>
<for each="member" in="ownProperties">
<tr>
<td class="attributes">{!
if (member.isPrivate) output += "&lt;private&gt; ";
if (member.isInner) output += "&lt;inner&gt; ";
if (member.isStatic) output += "&lt;static&gt; ";
if (member.isConstant) output += "&lt;constant&gt; ";
!}&nbsp;</td>
<td class="nameDescription">
<div class="fixedFont">
<if test="member.isStatic && member.memberOf != '_global_'">{+member.memberOf+}.</if><b>{+new Link().toSymbol(member.alias).withText(member.name)+}</b>
</div>
<div class="description">{+resolveLinks(summarize(member.desc))+}</div>
</td>
</tr>
</for>
</tbody>
</table>
</div>
</if>
<if test="data.inheritsFrom.length">
<dl class="inheritsList">
{!
var borrowedMembers = data.properties.filter(function($) {return $.memberOf != data.alias});
var contributers = [];
borrowedMembers.map(function($) {if (contributers.indexOf($.memberOf) < 0) contributers.push($.memberOf)});
for (var i = 0, l = contributers.length; i < l; i++) {
output +=
"<dt>Fields borrowed from class "+new Link().toSymbol(contributers[i])+": </dt>"
+
"<dd>" +
borrowedMembers
.filter(
function($) { return $.memberOf == contributers[i] }
)
.sort(makeSortby("name"))
.map(
function($) { return new Link().toSymbol($.alias).withText($.name) }
)
.join(", ")
+
"</dd>";
}
!}
</dl>
</if>
</if>
<!--
#### METHODS SUMMARY
-->
<if test="data.methods.length">
{! var ownMethods = data.methods.filter(function($){return $.memberOf == data.alias && !$.isNamespace}).sort(makeSortby("name")); !}
<div class="props">
<h2 class="sectionTitle">Method Summary</h2>
<if test="ownMethods.length">
<table class="summaryTable" id="MethodsList" cellspacing="0" summary="A summary of the methods documented in the class {+data.alias+}.">
<thead>
<tr>
<th scope="col">Method Attributes</th>
<th scope="col">Method Name and Description</th>
</tr>
</thead>
<tbody>
{!
var methodSummaryCount = 0;
!}
<for each="member" in="ownMethods">
<tr
{!
output += " class='item"+ methodSummaryCount +"'";
methodSummaryCount++
!}
>
<td class="attributes">{!
if (member.isPrivate) output += "&lt;private&gt; ";
if (member.isInner) output += "&lt;inner&gt; ";
if (member.isStatic) output += "&lt;static&gt; ";
!}&nbsp;</td>
<td class="nameDescription">
<div class="fixedFont"><if test="member.isStatic && member.memberOf != '_global_'">{+member.memberOf+}.</if><b>{+new Link().toSymbol(member.alias).withText(member.name.replace(/\^\d+$/, ''))+}</b>{+makeSignature(member.params)+}
</div>
<div class="description">{+resolveLinks(summarize(member.desc))+}</div>
</td>
</tr>
</for>
</tbody>
</table>
</if>
<if test="data.inheritsFrom.length">
<dl class="inheritsList" id="MethodsListInherited">
{!
var borrowedMembers = data.methods.filter(function($) {return $.memberOf != data.alias});
var contributers = [];
borrowedMembers.map(function($) {if (contributers.indexOf($.memberOf) < 0) contributers.push($.memberOf)});
for (var i = 0, l = contributers.length; i < l; i++) {
output +=
"<dt>Methods borrowed from class <span class='fixedFont'>"+new Link().toSymbol(contributers[i])+"</span>: </dt>"
+
borrowedMembers
.filter(
function($) { return $.memberOf == contributers[i] }
)
.sort(makeSortby("name"))
.map(
function($) {
var link = "";
link += "<dd><span class='fixedFont'>";
link += new Link().toSymbol($.alias).withText($.name);
link += "</span></dd>";
return link;
}
)
.join(" ");
}
!}
</dl>
</if>
</div>
</if>
<!--
#### EVENTS SUMMARY
-->
<if test="data.events.length">
{! var ownEvents = data.events.filter(function($){return $.memberOf == data.alias && !$.isNamespace}).sort(makeSortby("name")); !}
<if test="ownEvents.length">
<div class="props">
<table class="summaryTable" cellspacing="0" summary="A summary of the events documented in the class {+data.alias+}.">
<caption class="sectionTitle">Event Summary</caption>
<thead>
<tr>
<th scope="col">Event Attributes</th>
<th scope="col">Event Name and Description</th>
</tr>
</thead>
<tbody>
<for each="member" in="ownEvents">
<tr>
<td class="attributes">{!
if (member.isPrivate) output += "&lt;private&gt; ";
if (member.isInner) output += "&lt;inner&gt; ";
if (member.isStatic) output += "&lt;static&gt; ";
!}&nbsp;</td>
<td class="nameDescription">
<div class="fixedFont"><if test="member.isStatic && member.memberOf != '_global_'">{+member.memberOf+}.</if><b>{+new Link().toSymbol(member.alias).withText(member.name)+}</b>{+makeSignature(member.params)+}
</div>
<div class="description">{+resolveLinks(summarize(member.desc))+}</div>
</td>
</tr>
</for>
</tbody>
</table>
</div>
</if>
<if test="data.inheritsFrom.length">
<dl class="inheritsList">
{!
var borrowedMembers = data.events.filter(function($) {return $.memberOf != data.alias});
var contributers = [];
borrowedMembers.map(function($) {if (contributers.indexOf($.memberOf) < 0) contributers.push($.memberOf)});
for (var i = 0, l = contributers.length; i < l; i++) {
output +=
"<dt>Events borrowed from class "+new Link().toSymbol(contributers[i])+": </dt>"
+
"<dd>" +
borrowedMembers
.filter(
function($) { return $.memberOf == contributers[i] }
)
.sort(makeSortby("name"))
.map(
function($) { return new Link().toSymbol($.alias).withText($.name) }
)
.join(", ")
+
"</dd>";
}
!}
</dl>
</if>
</if>
<!--
#### CONSTRUCTOR DETAILS
-->
<if test="!data.isBuiltin() && (data.isNamespace || data.is('CONSTRUCTOR'))">
<div class="details props">
<div class="innerProps">
<h2 class="sectionTitle" id="constructor">
{+classType+}Detail
</h2>
<div class="fixedFont">{!
if (data.isPrivate) output += "&lt;private&gt; ";
if (data.isInner) output += "&lt;inner&gt; ";
!}
<b>{+ data.alias +}</b><if test="classType != 'Namespace '">{+ makeSignature(data.params) +}</if>
</div>
<div class="description">
{+resolveLinks(data.desc)+}
<if test="data.author"><br /><i>Author: </i>{+data.author+}.</if>
</div>
<if test="data.example.length">
<for each="example" in="data.example">
<pre class="code">{+example+}</pre>
</for>
</if>
<if test="data.params.length">
<dl class="detailList params">
<dt class="heading">Parameters:</dt>
<for each="item" in="data.params">
<dt>
{+((item.type)?""+("<span class=\"light fixedFont\">{"+(new Link().toSymbol(item.type)+"}</span> ")) : "")+} <b>{+item.name+}</b>
<if test="item.isOptional"><i>Optional<if test="item.defaultValue">, Default: {+item.defaultValue+}</if></i></if>
</dt>
<dd>{+resolveLinks(item.desc)+}</dd>
</for>
</dl>
</if>
<if test="data.deprecated || data.since || data.exceptions.length || data.returns.length || data.requires.length || data.see.length">
<dl class="detailList nomargin">
<if test="data.deprecated">
<dt>
{+resolveLinks(data.deprecated)+}
</dt>
</if>
<if test="data.since">
<dt class="heading">Since:</dt>
<dd>{+ data.since +}</dd>
</if>
<if test="data.exceptions.length">
<dt class="heading">Throws:</dt>
<for each="item" in="data.exceptions">
<dt>
{+((item.type)?"<span class=\"light fixedFont\">{"+(new Link().toSymbol(item.type))+"}</span> " : "")+} <b>{+item.name+}</b>
</dt>
<dd>{+resolveLinks(item.desc)+}</dd>
</for>
</if>
<if test="data.returns.length">
<dt class="heading">Returns:</dt>
<for each="item" in="data.returns">
<dd>{+((item.type)?"<span class=\"light fixedFont\">{"+(new Link().toSymbol(item.type))+"}</span> " : "")+}{+resolveLinks(item.desc)+}</dd>
</for>
</if>
<if test="data.requires.length">
<dt class="heading">Requires:</dt>
<for each="item" in="data.requires">
<dd>{+ resolveLinks(item) +}</dd>
</for>
</if>
<if test="data.see.length">
<dt class="heading">See:</dt>
<for each="item" in="data.see">
<dd>{+ new Link().toSymbol(item) +}</dd>
</for>
</if>
</dl>
</if>
</div>
</div>
</if>
<!--
#### FIELD DETAILS
-->
<if test="defined(ownProperties) && ownProperties.length">
<div class="details props">
<div class="innerProps">
<h2 class="sectionTitle">
Field Detail
</h2>
<for each="member" in="ownProperties">
<div class="fixedFont heading" id="{+Link.symbolNameToLinkName(member)+}">
<span class='lighter'>
{!
if (member.isPrivate) output += "&lt;private&gt; ";
if (member.isInner) output += "&lt;inner&gt; ";
if (member.isStatic) output += "&lt;static&gt; ";
if (member.isConstant) output += "&lt;constant&gt; ";
!}
</span>
<if test="member.type"><span class="light">{{+new Link().toSymbol(member.type)+}}</span></if>
<if test="member.isStatic && member.memberOf != '_global_'"><span class="light">{+member.memberOf+}.</span></if><b>{+member.name+}</b>
</div>
<div class="description">
{+resolveLinks(member.desc)+}
<if test="member.srcFile != data.srcFile">
<br />
<i>Defined in: </i> {+new Link().toSrc(member.srcFile)+}.
</if>
<if test="member.author"><br /><i>Author: </i>{+member.author+}.</if>
</div>
<if test="member.example.length">
<for each="example" in="member.example">
<pre class="code">{+example+}</pre>
</for>
</if>
<if test="member.deprecated || member.since || member.see.length || member.defaultValue">
<dl class="detailList nomargin">
<if test="member.deprecated">
<dt class="heading">Deprecated:</dt>
<dt>
{+ resolveLinks(member.deprecated) +}
</dt>
</if>
<if test="member.since">
<dt class="heading">Since:</dt>
<dd>{+ member.since +}</dd>
</if>
<if test="member.see.length">
<dt class="heading">See:</dt>
<for each="item" in="member.see">
<dd>{+ new Link().toSymbol(item) +}</dd>
</for>
</if>
<if test="member.defaultValue">
<dt class="heading">Default Value:</dt>
<dd>
{+resolveLinks(member.defaultValue)+}
</dd>
</if>
</dl>
</if>
<if test="!$member_last"><div class="hr"></div></if>
</for>
</div>
</div>
</if>
<!--
#### METHOD DETAILS
-->
<if test="defined(ownMethods) && ownMethods.length">
<div class="details props">
<div class="innerProps">
<h2 class="sectionTitle">
Method Detail
</h2>
<ul class="methodDetail" id="MethodDetail">
{!
var methodDetailCount = 0;
!}
<for each="member" in="ownMethods">
<li
{!
output += " class='item"+ methodDetailCount +"'";
methodDetailCount++
!}
>
<div class="fixedFont heading" id="{+Link.symbolNameToLinkName(member)+}">
<span class='lighter'>
{!
if (member.isPrivate) output += "&lt;private&gt; ";
if (member.isInner) output += "&lt;inner&gt; ";
if (member.isStatic) output += "&lt;static&gt; ";
!}
</span>
<if test="member.type"><span class="light">{{+new Link().toSymbol(member.type)+}}</span></if>
<if test="member.isStatic && member.memberOf != '_global_'"><span class="light">{+member.memberOf+}.</span></if><b>{+member.name.replace(/\^\d+$/, '')+}</b>{+makeSignature(member.params)+}
</div>
<div class="description">
{+resolveLinks(member.desc)+}
<if test="member.srcFile != data.srcFile">
<br />
<i>Defined in: </i> {+new Link().toSrc(member.srcFile)+}.
</if>
<if test="member.author"><br /><i>Author: </i>{+member.author+}.</if>
</div>
<if test="member.example.length">
<for each="example" in="member.example">
<pre class="code">{+example+}</pre>
</for>
</if>
<if test="member.params.length">
<dl class="detailList params">
<dt class="heading">Parameters:</dt>
<for each="item" in="member.params">
<dt>
{+((item.type)?"<span class=\"light fixedFont\">{"+(new Link().toSymbol(item.type))+"}</span> " : "")+}<b>{+item.name+}</b>
<if test="item.isOptional"><i>Optional<if test="item.defaultValue">, Default: {+item.defaultValue+}</if></i></if>
</dt>
<dd>{+resolveLinks(item.desc)+}</dd>
</for>
</dl>
</if>
<if test="member.deprecated || member.since || member.exceptions.length || member.returns.length || member.requires.length || member.see.length">
<dl class="detailList nomargin">
<if test="member.deprecated">
<dt class="heading">Deprecated:</dt>
<dt>
{+ resolveLinks(member.deprecated) +}
</dt>
</if>
<if test="member.since">
<dt class="heading">Since:</dt>
<dd>{+ member.since +}</dd>
</if>
<if test="member.exceptions.length">
<dt class="heading">Throws:</dt>
<for each="item" in="member.exceptions">
<dt>
{+((item.type)?"<span class=\"light fixedFont\">{"+(new Link().toSymbol(item.type))+"}</span> " : "")+} <b>{+item.name+}</b>
</dt>
<dd>{+resolveLinks(item.desc)+}</dd>
</for>
</if>
<if test="member.returns.length">
<dt class="heading">Returns:</dt>
<for each="item" in="member.returns">
<dd>{+((item.type)?"<span class=\"light fixedFont\">{"+(new Link().toSymbol(item.type))+"}</span> " : "")+}{+resolveLinks(item.desc)+}</dd>
</for>
</if>
<if test="member.requires.length">
<dt class="heading">Requires:</dt>
<for each="item" in="member.requires">
<dd>{+ resolveLinks(item) +}</dd>
</for>
</if>
<if test="member.see.length">
<dt class="heading">See:</dt>
<for each="item" in="member.see">
<dd>{+ new Link().toSymbol(item) +}</dd>
</for>
</if>
</dl>
</if>
<if test="!$member_last"><div class="hr"></div></if>
</li>
</for>
</ul>
</div>
</div>
</if>
<!--
#### EVENT DETAILS
-->
<if test="defined(ownEvents) && ownEvents.length">
<div class="details props">
<div class="innerProps">
<h2 class="sectionTitle">
Event Detail
</h2>
<for each="member" in="ownEvents">
<div class="fixedFont heading" id="event:{+Link.symbolNameToLinkName(member)+}">
<span class='lighter'>
{!
if (member.isPrivate) output += "&lt;private&gt; ";
if (member.isInner) output += "&lt;inner&gt; ";
if (member.isStatic) output += "&lt;static&gt; ";
!}
</span>
<if test="member.type"><span class="light">{{+new Link().toSymbol(member.type)+}}</span></if>
<if test="member.isStatic && member.memberOf != '_global_'"><span class="light">{+member.memberOf+}.</span></if><b>{+member.name+}</b>{+makeSignature(member.params)+}
</div>
<div class="description">
{+resolveLinks(member.desc)+}
<if test="member.srcFile != data.srcFile">
<br />
<i>Defined in: </i> {+new Link().toSrc(member.srcFile)+}.
</if>
<if test="member.author"><br /><i>Author: </i>{+member.author+}.</if>
</div>
<if test="member.example.length">
<for each="example" in="member.example">
<pre class="code">{+example+}</pre>
</for>
</if>
<if test="member.params.length">
<dl class="detailList params">
<dt class="heading">Parameters:</dt>
<for each="item" in="member.params">
<dt>
{+((item.type)?"<span class=\"light fixedFont\">{"+(new Link().toSymbol(item.type))+"}</span> " : "")+}<b>{+item.name+}</b>
<if test="item.isOptional"><i>Optional<if test="item.defaultValue">, Default: {+item.defaultValue+}</if></i></if>
</dt>
<dd>{+ resolveLinks(item.desc) +}</dd>
</for>
</dl>
</if>
<if test="member.deprecated || member.since || member.exceptions.length || member.returns.length || member.see.length">
<dl class="detailList nomargin">
<if test="member.deprecated">
<dt class="heading">Deprecated:</dt>
<dt>{+ resolveLinks(member.deprecated) +}</dt>
</if>
<if test="member.since">
<dt class="heading">Since:</dt>
<dd>{+ member.since +}</dd>
</if>
<if test="member.exceptions.length">
<dt class="heading">Throws:</dt>
<for each="item" in="member.exceptions">
<dt>
{+((item.type)?"<span class=\"light fixedFont\">{"+(new Link().toSymbol(item.type))+"}</span> " : "")+} <b>{+item.name+}</b>
</dt>
<dd>{+ resolveLinks(item.desc) +}</dd>
</for>
</if>
<if test="member.returns.length">
<dt class="heading">Returns:</dt>
<for each="item" in="member.returns">
<dd>{+((item.type)?"<span class=\"light fixedFont\">{"+(new Link().toSymbol(item.type))+"}</span> " : "")+}{+resolveLinks(item.desc)+}</dd>
</for>
</if>
<if test="member.requires.length">
<dt class="heading">Requires:</dt>
<for each="item" in="member.requires">
<dd>{+ resolveLinks(item) +}</dd>
</for>
</if>
<if test="member.see.length">
<dt class="heading">See:</dt>
<for each="item" in="member.see">
<dd>{+ new Link().toSymbol(item) +}</dd>
</for>
</if>
</dl>
</if>
<if test="!$member_last"><div class="hr"></div></if>
</for>
</div>
</div>
</if>
</div>
</div>
{+subtemplate("subtemplates/foot.tmpl")+}

View file

@ -1,358 +0,0 @@
/* TABLE OF CONTENTS:
* - Browser reset
* - HTML elements
* - JsDoc styling
*/
/*
* BEGIN BROWSER RESET
*/
body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,p,pre,form,fieldset,input,textarea,p,blockquote,th,td {
margin:0;
padding:0
}
html {
height:100%;
overflow:-moz-scrollbars-vertical;
overflow-x:auto
}
table {
border:0;
border-collapse:collapse;
border-spacing:0
}
fieldset,img {
border:0
}
address,caption,cite,code,dfn,em,strong,th,var {
font-style:normal;
font-weight:normal
}
em,cite {
font-style:italic
}
strong {
font-weight:bold
}
ol,ul {
list-style:none
}
caption,th {
text-align:left
}
h1,h2,h3,h4,h5,h6 {
font-size:100%;
font-weight:normal;
margin:0;
padding:0
}
q:before,q:after {
content:''
}
abbr,acronym {
border:0
}
section,article,header,footer,nav,aside,hgroup {
display:block
}
/*
* END BROWSER RESET
*/
/*
* HTML ELEMENTS
*/
@font-face {
font-family: 'M1m';
src: url('fonts/mplus-1m-regular-webfont.eot');
src: local('☺'), url('fonts/mplus-1m-regular-webfont.woff') format('woff'), url('fonts/mplus-1m-regular-webfont.ttf') format('truetype'), url('fonts/mplus-1m-regular-webfont.svg#webfontVd14f4NN') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'M1m';
src: url('fonts/mplus-1m-bold-webfont.eot');
src: local('☺'), url('fonts/mplus-1m-bold-webfont.woff') format('woff'), url('fonts/mplus-1m-bold-webfont.ttf') format('truetype'), url('fonts/mplus-1m-bold-webfont.svg#webfontIjI5mZqE') format('svg');
font-weight: bold;
font-style: normal;
}
* {
line-height: 1.4em;
}
html {
font-size: 100%;
}
body {
font-size: 0.75em;
padding: 15px 0;
background: #eee;
background-image: -moz-linear-gradient(left, #dddddd, #f9f9f9) fixed;
background-image: -webkit-gradient(linear,left bottom,right bottom,color-stop(0, #dddddd),color-stop(1, #f9f9f9)) fixed;
}
body,
input,
select,
textarea {
color: #000;
font-family: Arial, Geneva, sans-serif;
}
a:link,
a:hover,
a:active,
a:visited {
color: #19199e;
}
a:hover,
a:focus {
color: #00f;
text-decoration: none;
}
p {
margin: 0 0 1.5em 0;
}
/*
* END HTML ELEMENTS
*/
/*
* BEGIN HACK
*/
div.containerMain:after,
div.safeBox:after {
content:"";
display:block;
height:0;
clear:both;
}
/*
* END HACK
*/
/*
* BEGIN JSDOC
*/
/* Start menu */
div.index *.heading1 {
margin-bottom: 0.5em;
border-bottom: 1px solid #999999;
font-family: M1m, Arial, sans-serif;
font-size: 1.6em;
letter-spacing: 1px;
line-height: 1.3em;
}
div.index div.menu {
background-color: #FFFFFF;
}
*+html div.index div.menu {
background-color: #FFFFFF;
}
* html div.index div.menu {
background-color: #FFFFFF;
}
div.index div.menu div {
text-align: left;
}
div.index div.menu a {
text-decoration: none;
}
div.index div.menu a:hover {
text-decoration: underline;
}
div.index ul.classList {
padding-left: 0;
}
div.index ul.classList a {
display: block;
margin: 1px 0;
padding: 4px 0 2px 10px;
text-indent: -10px;
}
div.index div.fineprint {
color: #777;
font-size: 0.9em;
}
div.index div.fineprint a {
color: #777;
}
/* End menu */
/* Start content */
div.content ul {
padding-left: 0;
}
div.content *.classTitle {
font-size: 1.2em;
font-weight: bold;
line-height: 1em;
}
div.content *.classTitle span {
display: block;
font-size: 2em;
letter-spacing: 2px;
line-height: 1em;
padding-top: 5px;
text-shadow: 1px 1px 1px #999999;
word-wrap: break-word;
}
div.content p.summary {
font-size: 1.25em;
}
div.content ul *.classname a,
div.content ul *.filename a {
font-family: Consolas, "Courier New", Courier, monospace;
text-decoration: none;
font-weight: bold;
}
div.content ul *.classname a:hover,
div.content ul *.filename a:hover {
text-decoration: underline;
}
div.content div.props {
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
background: #fff;
background: -moz-linear-gradient(top, rgba(255, 255, 255, 0.7), rgba(255, 255, 255, 0.2)); /* FF3.6 */
background: -webkit-gradient(linear,left top,left bottom,color-stop(0, rgba(255, 255, 255, 0.7)),color-stop(1, rgba(255, 255, 255, 0.2)));
-moz-box-shadow: 0px 0px 10px #ccc;
-webkit-box-shadow: 0px 0px 5px #bbb;
box-shadow: 0px 0px 5px #bbb;
}
*.sectionTitle {
font-family: M1m, sans-serif;
font-size: 1.6em;
letter-spacing: 1px;
}
table.summaryTable td,
table.summaryTable th {
vertical-align: top;
}
table.summaryTable tr:last-child td {
padding-bottom: 0;
}
table.summaryTable th {
font-weight: bold;
}
table.summaryTable td.attributes {
font-family: Consolas, "Courier New", Courier, monospace;
color: #666;
}
table.summaryTable td.nameDescription div.fixedFont {
font-weight: bold;
}
table.summaryTable div.description {
color: #333;
}
dl.detailList dt {
font-weight: bold;
}
dl.inheritsList dd + dt {
margin-top: 10px;
}
dl.inheritsList dd {
display: inline;
}
.fixedFont {
font-family: Consolas, "Courier New", Courier, monospace;
}
.fixedFont.heading {
font-size: 1.25em;
line-height: 1.1em
}
.fixedFont.heading + .description {
font-size: 1.2em;
}
.fixedFont.heading .light,
.fixedFont.heading .lighter {
font-weight: bold;
}
pre.code {
overflow: auto;
font-family: Consolas, "Courier New", Courier, monospace;
background: #eee;
}
/* Start content */
/* Start general styles */
.light {
color: #666;
}
.lighter {
color: #999;
}
span.break {
font-size: 1px;
line-height: 1px;
}
/* End general styles */
/*
* END JSDOC
*/

View file

@ -1,134 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>
This is a custom SVG webfont generated by Font Squirrel.
Foundry URL : http://mplus-fonts.sourceforge.jp
</metadata>
<defs>
<font id="webfontIjI5mZqE" horiz-adv-x="500" >
<font-face units-per-em="1000" ascent="860" descent="-140" />
<missing-glyph horiz-adv-x="500" />
<glyph unicode=" " />
<glyph unicode="!" d="M165 730h170l-20 -495h-130zM170 0v150h160v-150h-160z" />
<glyph unicode="&#x22;" d="M270 780h160l-30 -320h-100zM70 780h160l-30 -320h-100z" />
<glyph unicode="#" d="M20 165v120h62l24 185h-51v120h67l18 140h135l-18 -140h45l18 140h135l-18 -140h43v-120h-59l-24 -185h48v-120h-64l-21 -165h-135l21 165h-45l-21 -165h-135l21 165h-46zM217 285h45l24 185h-45z" />
<glyph unicode="$" d="M357 397q55 -32 76.5 -74t21.5 -108q0 -190 -192 -199v-101h-110v112q-51 16 -88 43v140q38 -35 88 -55v191q-53 33 -75.5 75.5t-22.5 103.5q0 89 50 138.5t142 51.5v100h110v-112q42 -12 78 -33v-135q-32 25 -78 42v-180zM247 445v149q-54 -9 -54 -69q0 -55 54 -80z M263 295v-157q52 13 52 77q0 55 -52 80z" />
<glyph unicode="%" d="M40 310l420 220v-110l-420 -220v110zM160 740q70 0 110 -41t40 -119t-40 -119t-110 -41t-110 41t-40 119t40 119t110 41zM340 310q70 0 110 -41t40 -119t-40 -119t-110 -41t-110 41t-40 119t40 119t110 41zM160 518q38 0 38 62t-38 62t-38 -62t38 -62zM340 88q38 0 38 62 t-38 62t-38 -62t38 -62z" />
<glyph unicode="&#x26;" d="M235 615q-23 0 -36.5 -14.5t-13.5 -40.5q0 -18 7.5 -37.5t33.5 -65.5q35 30 47 52.5t12 50.5q0 26 -13.5 40.5t-36.5 14.5zM118 368q-47 77 -62.5 116t-15.5 76q0 80 51.5 130t138.5 50t141 -50.5t54 -129.5q0 -114 -130 -220l55 -94v2v132h125v-225q-16 -25 -41 -52 l61 -103h-150l-15 24q-66 -34 -130 -34q-88 0 -136.5 45.5t-48.5 134.5q0 99 103 198zM269 124l-77 125q-27 -37 -27 -74q0 -60 65 -60q20 0 39 9z" />
<glyph unicode="'" d="M160 780h180l-35 -320h-110z" />
<glyph unicode="(" d="M100 300q0 136 50 256.5t144 213.5h126q-196 -194 -196 -470t196 -470h-126q-94 93 -144 213.5t-50 256.5z" />
<glyph unicode=")" d="M400 300q0 -136 -50 -256.5t-144 -213.5h-126q196 194 196 470t-196 470h126q94 -93 144 -213.5t50 -256.5z" />
<glyph unicode="*" d="M193 750h114l-4 -144l136 48l35 -109l-138 -40l88 -115l-93 -67l-81 119l-81 -119l-93 67l88 115l-138 40l35 109l136 -48z" />
<glyph unicode="+" d="M315 545v-195h135v-110h-135v-195h-130v195h-135v110h135v195h130z" />
<glyph unicode="," d="M180 190h190l-130 -320h-120z" />
<glyph unicode="-" d="M90 240v110h320v-110h-320z" />
<glyph unicode="." d="M155 0v190h190v-190h-190z" />
<glyph unicode="/" d="M465 730l-310 -770h-120l310 770h120z" />
<glyph unicode="0" d="M250 740q73 0 117.5 -32.5t68.5 -116t24 -226.5t-24 -226.5t-68.5 -116t-117.5 -32.5t-117.5 32.5t-68.5 116t-24 226.5t24 226.5t68.5 116t117.5 32.5zM171 317l142 248q-9 34 -24.5 47t-38.5 13q-28 0 -44.5 -19.5t-26 -77.5t-9.5 -163q0 -33 1 -48zM183 179 q9 -41 25.5 -57.5t41.5 -16.5q28 0 44.5 19.5t26 77.5t9.5 163q0 47 -1 67z" />
<glyph unicode="1" d="M240 592l-2 1l-173 -91v128l175 100h140v-730h-140v592z" />
<glyph unicode="2" d="M220 122v-2h220v-120h-380v120q127 141 181 237t54 173q0 43 -21 66.5t-59 23.5q-31 0 -74 -22t-81 -58v130q78 70 185 70q90 0 140 -51t50 -149q0 -180 -215 -418z" />
<glyph unicode="3" d="M290 608v2h-230v120h385v-120l-170 -178v-2h10q79 0 122 -51.5t43 -153.5q0 -121 -54 -178t-166 -57q-51 0 -81.5 6.5t-78.5 28.5v130q80 -45 150 -45q46 0 68 27t22 88q0 58 -26 76.5t-114 18.5h-40v120z" />
<glyph unicode="4" d="M400 150v-150h-135v150h-245v120l230 460h150v-460h80v-120h-80zM265 270v255h-2l-127 -253v-2h129z" />
<glyph unicode="5" d="M202 455q36 19 82 19q161 0 161 -239q0 -245 -230 -245q-76 0 -150 35v130q80 -45 140 -45q51 0 75.5 29t24.5 96t-14.5 93t-46.5 26q-34 0 -64 -34h-110l10 410h345v-120h-220l-5 -155h2z" />
<glyph unicode="6" d="M295 625q-54 0 -76.5 -34.5t-28.5 -135.5h2q45 35 98 35q92 0 133.5 -54.5t41.5 -185.5q0 -141 -51 -200.5t-159 -59.5q-75 0 -119 28.5t-67.5 101t-23.5 200.5q0 162 25 254t75 129t135 37q66 0 135 -20v-125q-57 30 -120 30zM255 107q39 0 55.5 29.5t16.5 113.5 q0 79 -14 104.5t-53 25.5q-38 0 -56.5 -29.5t-18.5 -100.5q0 -81 17 -112t53 -31z" />
<glyph unicode="7" d="M55 730h390v-120q-113 -273 -200 -610h-146q92 325 216 608v2h-260v120z" />
<glyph unicode="8" d="M258 625q-41 0 -59.5 -20.5t-18.5 -64.5q0 -74 75 -105q33 16 51.5 43.5t18.5 61.5q0 40 -18 62.5t-49 22.5zM250 -10q-105 0 -162.5 52t-57.5 148q0 116 105 179v2q-42 31 -66 80t-24 104q0 87 53.5 136t151.5 49t151.5 -48.5t53.5 -136.5q0 -98 -100 -164v-2 q115 -62 115 -199q0 -96 -58 -148t-162 -52zM242 105q93 0 93 100q0 75 -103 115q-33 -17 -52.5 -48.5t-19.5 -66.5q0 -48 22.5 -74t59.5 -26z" />
<glyph unicode="9" d="M205 110q55 0 77 32.5t28 132.5h-2q-45 -35 -98 -35q-89 0 -132 57.5t-43 192.5q0 131 51 190.5t159 59.5q79 0 123 -27.5t65.5 -99.5t21.5 -203q0 -162 -25 -254t-75 -129t-135 -37q-66 0 -135 20v130q57 -30 120 -30zM245 623q-39 0 -55.5 -28t-16.5 -105 q0 -83 15.5 -111.5t51.5 -28.5q75 0 75 140q0 73 -17 103t-53 30z" />
<glyph unicode=":" d="M160 390v190h180v-190h-180zM160 0v190h180v-190h-180z" />
<glyph unicode=";" d="M170 190h190l-130 -320h-120zM170 390v190h180v-190h-180z" />
<glyph unicode="&#x3c;" d="M445 470l-320 -174v-2l320 -174v-120l-400 225v140l400 225v-120z" />
<glyph unicode="=" d="M50 125v110h400v-110h-400zM50 362v103h400v-103h-400z" />
<glyph unicode="&#x3e;" d="M55 470v120l400 -225v-140l-400 -225v120l320 174v2z" />
<glyph unicode="?" d="M460 575q0 -36 -12.5 -69t-25 -51t-38.5 -49q-25 -30 -38 -48.5t-27.5 -52.5t-18.5 -70h-130q0 49 17 94.5t32 66.5t44 57q21 25 30.5 38t19 33.5t9.5 40.5q0 58 -82 58t-180 -53v130q95 40 200 40q95 0 147.5 -44t52.5 -121zM155 0v150h160v-150h-160z" />
<glyph unicode="@" d="M285 635q-72 0 -108.5 -62.5t-36.5 -207.5q0 -265 160 -265q58 0 125 30v-115q-70 -25 -150 -25q-260 0 -260 375q0 194 64 284.5t191 90.5q99 0 152 -51.5t53 -148.5v-325q-28 -28 -76 -46.5t-94 -18.5q-69 0 -102 49t-33 166q0 114 31.5 164.5t93.5 50.5q36 0 68 -25h2 v15q0 26 -23.5 45.5t-56.5 19.5zM290 365q0 -72 8 -93.5t29 -21.5q20 0 28 18v147q0 41 -6 53t-25 12t-26.5 -22t-7.5 -93z" />
<glyph unicode="A" d="M249 620h-2l-55 -335h112zM323 170h-150l-28 -170h-140l165 730h160l165 -730h-144z" />
<glyph unicode="B" d="M190 445h15q59 0 85 20.5t26 64.5q0 49 -23 71t-73 22q-17 0 -30 -5v-173zM190 330v-218q20 -5 45 -5q51 0 75 27.5t24 90.5q0 57 -25.5 81t-88.5 24h-30zM470 210q0 -220 -240 -220q-93 0 -180 15v720q92 15 190 15q210 0 210 -185q0 -62 -32 -105t-83 -54v-2 q57 -10 96 -61.5t39 -122.5z" />
<glyph unicode="C" d="M30 365q0 195 64.5 285t190.5 90q80 0 150 -25v-115q-70 25 -125 25q-74 0 -109.5 -58.5t-35.5 -201.5q0 -260 150 -260q57 0 125 30v-120q-70 -25 -150 -25q-260 0 -260 375z" />
<glyph unicode="D" d="M344 365q0 142 -30 198.5t-94 56.5q-23 0 -40 -5v-500q17 -5 40 -5q63 0 93.5 55.5t30.5 199.5zM480 365q0 -144 -28.5 -226.5t-83.5 -115.5t-148 -33q-92 0 -180 15v720q88 15 180 15q141 0 200.5 -82t59.5 -293z" />
<glyph unicode="E" d="M210 610v-165h220v-115h-220v-210h230v-120h-370v730h370v-120h-230z" />
<glyph unicode="F" d="M220 330v-330h-140v730h360v-120h-220v-165h210v-115h-210z" />
<glyph unicode="G" d="M310 625q-82 0 -116 -55t-34 -205q0 -143 32 -201.5t93 -58.5q27 0 48 10v215h-98v115h230v-415q-83 -40 -180 -40q-260 0 -260 375q0 196 69.5 285.5t215.5 89.5q70 0 130 -25v-115q-72 25 -130 25z" />
<glyph unicode="H" d="M318 330h-140v-330h-138v730h138v-280h140v280h142v-730h-142v330z" />
<glyph unicode="I" d="M430 0h-360v115h108v500h-108v115h360v-115h-108v-500h108v-115z" />
<glyph unicode="J" d="M410 730v-515q0 -126 -48.5 -175.5t-166.5 -49.5q-86 0 -155 30v130q29 -18 68 -30t67 -12q50 0 71 26.5t21 95.5v385h-147v115h290z" />
<glyph unicode="K" d="M192 330h-2v-330h-140v730h140v-300h2l135 300h148l-160 -345l165 -385h-150z" />
<glyph unicode="L" d="M230 730v-610h210v-120h-350v730h140z" />
<glyph unicode="M" d="M338 500h-2l-38 -300h-100l-38 300h-2v-500h-133v730h167l59 -400h2l59 400h163v-730h-137v500z" />
<glyph unicode="N" d="M187 460h-2v-460h-140v730h147l125 -460h2v460h136v-730h-143z" />
<glyph unicode="O" d="M250 740q121 0 175.5 -84t54.5 -291t-54.5 -291t-175.5 -84t-175.5 84t-54.5 291t54.5 291t175.5 84zM250 108q52 0 75 53.5t23 203.5t-23 203.5t-75 53.5t-75 -53.5t-23 -203.5t23 -203.5t75 -53.5z" />
<glyph unicode="P" d="M334 503q0 120 -104 120q-23 0 -40 -5v-235q18 -5 40 -5q53 0 78.5 28t25.5 97zM470 503q0 -127 -57 -184.5t-173 -57.5q-26 0 -50 5v-266h-140v725q90 15 185 15q122 0 178.5 -56t56.5 -181z" />
<glyph unicode="Q" d="M250 740q121 0 175.5 -84t54.5 -291q0 -257 -92 -333v-2q39 -22 68.5 -74t33.5 -106h-145q-15 81 -36.5 110.5t-58.5 29.5q-121 0 -175.5 84t-54.5 291t54.5 291t175.5 84zM250 108q52 0 75 53.5t23 203.5t-23 203.5t-75 53.5t-75 -53.5t-23 -203.5t23 -203.5t75 -53.5z " />
<glyph unicode="R" d="M465 513q0 -151 -98 -199l-1 -2q27 -19 58 -118l61 -194h-145l-57 204q-12 43 -25.5 57.5t-42.5 14.5h-30v-276h-140v725q90 15 185 15q124 0 179.5 -53.5t55.5 -173.5zM185 393h30q64 0 89 24.5t25 95.5q0 58 -25.5 84t-78.5 26q-23 0 -40 -5v-225z" />
<glyph unicode="S" d="M440 575q-84 48 -165 48q-41 0 -65 -21t-24 -57q0 -71 69 -100q116 -48 160.5 -103t44.5 -142q0 -210 -225 -210q-100 0 -180 50v135q83 -68 173 -68q94 0 94 88q0 76 -77 110q-108 46 -151.5 99.5t-43.5 135.5q0 90 57 145t153 55q102 0 180 -35v-130z" />
<glyph unicode="T" d="M320 615v-615h-140v615h-145v115h430v-115h-145z" />
<glyph unicode="U" d="M250 -10q-112 0 -161 54t-49 186v500h142v-460q0 -101 14.5 -131.5t55.5 -30.5t55.5 30.5t14.5 131.5v460h138v-500q0 -132 -49 -186t-161 -54z" />
<glyph unicode="V" d="M253 110l92 620h140l-155 -730h-160l-155 730h144l92 -620h2z" />
<glyph unicode="W" d="M164 190h2l38 440h100l38 -440h2l15 540h126l-45 -730h-157l-34 420h-2l-34 -420h-153l-45 730h134z" />
<glyph unicode="X" d="M251 470h2l74 260h145l-132 -360l135 -370h-152l-74 270h-2l-74 -270h-148l135 370l-132 360h149z" />
<glyph unicode="Y" d="M251 415h2l84 315h148l-165 -455v-275h-140v275l-165 455h152z" />
<glyph unicode="Z" d="M290 613v2h-235v115h390v-115l-235 -498v-2h235v-115h-390v115z" />
<glyph unicode="[" d="M410 675h-170v-750h170v-95h-290v940h290v-95z" />
<glyph unicode="\" d="M35 730h120l310 -770h-120z" />
<glyph unicode="]" d="M90 675v95h290v-940h-290v95h170v750h-170z" />
<glyph unicode="^" d="M251 655h-2l-111 -375h-123l145 450h180l145 -450h-123z" />
<glyph unicode="_" d="M40 -170v88h420v-88h-420z" />
<glyph unicode="`" d="M90 810h190l100 -320h-120z" />
<glyph unicode="a" d="M65 495q39 14 95 24.5t90 10.5q111 0 155.5 -45t44.5 -160v-325h-127l-2 65h-2q-49 -75 -134 -75q-68 0 -106.5 42t-38.5 118q0 88 63.5 136.5t186.5 48.5h25v10q0 40 -16 56.5t-54 16.5q-32 0 -86.5 -11.5t-93.5 -26.5v115zM315 245h-25q-59 0 -89.5 -23t-30.5 -62 q0 -31 15 -48t40 -17q90 0 90 130v20z" />
<glyph unicode="b" d="M45 730h137v-275h2q49 75 116 75q83 0 129 -66.5t46 -203.5q0 -133 -47.5 -201.5t-127.5 -68.5q-35 0 -62.5 17.5t-56.5 62.5h-2l-2 -70h-132v730zM338 260q0 150 -78 150q-80 0 -80 -145v-10q0 -145 80 -145q35 0 56.5 36.5t21.5 113.5z" />
<glyph unicode="c" d="M305 420q-115 0 -115 -160q0 -163 120 -163q60 0 120 28v-110q-68 -25 -140 -25q-116 0 -178 67.5t-62 202.5t60 202.5t175 67.5q67 0 135 -25v-110q-61 25 -115 25z" />
<glyph unicode="d" d="M455 0h-132l-2 70h-2q-29 -45 -56.5 -62.5t-62.5 -17.5q-80 0 -127.5 68.5t-47.5 201.5q0 137 46 203.5t129 66.5q67 0 116 -75h2v275h137v-730zM162 260q0 -77 21.5 -113.5t56.5 -36.5q80 0 80 145v10q0 145 -80 145q-78 0 -78 -150z" />
<glyph unicode="e" d="M182 206q7 -62 33 -85.5t80 -23.5q52 0 135 28v-110q-84 -25 -155 -25q-112 0 -173.5 68t-61.5 202q0 270 220 270q200 0 200 -270q0 -31 -2 -54h-276zM181 310h142q-1 63 -15.5 88t-47.5 25q-41 0 -58 -23t-21 -90z" />
<glyph unicode="f" d="M60 391v109h100v45q0 104 40.5 149.5t129.5 45.5q56 0 110 -15v-110q-36 16 -80 16q-37 0 -50 -20.5t-13 -85.5v-25h143v-109h-143v-391h-137v391h-100z" />
<glyph unicode="g" d="M323 75h-2q-45 -75 -116 -75q-78 0 -126.5 66.5t-48.5 193.5q0 137 46 203.5t129 66.5q35 0 62.5 -17.5t56.5 -62.5h2l2 70h132v-505q0 -245 -240 -245q-81 0 -150 25v115q76 -33 145 -33q55 0 81.5 34t26.5 114v50zM167 260q0 -70 22 -105t56 -35q80 0 80 135v10 q0 145 -80 145q-78 0 -78 -150z" />
<glyph unicode="h" d="M50 730h137v-275h2q47 75 126 75t112 -47.5t33 -172.5v-310h-135v290q0 74 -12.5 98t-47.5 24t-56.5 -43.5t-21.5 -131.5v-237h-137v730z" />
<glyph unicode="i" d="M110 520h240v-413h100v-107h-370v107h130v306h-100v107zM190 630v130h160v-130h-160z" />
<glyph unicode="j" d="M225 -20v433h-110v107h250v-540q0 -68 -10.5 -106t-44 -63t-87.5 -33t-148 -8v109q39 0 60.5 0.5t41 5t27 9.5t13.5 18t7 27.5t1 40.5zM205 630v130h160v-130h-160z" />
<glyph unicode="k" d="M480 520l-185 -250l185 -270h-162l-131 224v-224h-137v730h137v-418l133 208h160z" />
<glyph unicode="l" d="M310 190q0 -68 9 -80.5t56 -12.5q31 0 75 6v-108q-44 -5 -100 -5q-111 0 -145.5 32.5t-34.5 137.5v463h-120v107h260v-540z" />
<glyph unicode="m" d="M360 0v340q0 40 -21 40q-8 0 -12.5 -5t-7 -22.5t-2.5 -52.5v-300h-130v340q0 40 -21 40q-8 0 -12.5 -5t-7 -22.5t-2.5 -52.5v-300h-134v520h120l2 -65h2q15 34 39.5 54.5t48.5 20.5q28 0 45 -16t32 -59h2q42 75 99 75q48 0 69 -36t21 -134v-360h-130z" />
<glyph unicode="n" d="M50 520h132l2 -70h2q49 80 129 80q79 0 112 -47.5t33 -172.5v-310h-135v290q0 74 -12.5 98t-47.5 24t-56.5 -43.5t-21.5 -131.5v-237h-137v520z" />
<glyph unicode="o" d="M250 530q220 0 220 -270t-220 -270t-220 270t220 270zM250 97q44 0 62 33.5t18 129.5t-18 129.5t-62 33.5t-62 -33.5t-18 -129.5t18 -129.5t62 -33.5z" />
<glyph unicode="p" d="M179 70h-2v-290h-137v740h132l2 -70h2q29 45 56.5 62.5t62.5 17.5q83 0 129 -66.5t46 -203.5q0 -133 -47.5 -201.5t-127.5 -68.5q-71 0 -116 80zM333 260q0 150 -78 150q-80 0 -80 -145v-10q0 -145 80 -145q35 0 56.5 36.5t21.5 113.5z" />
<glyph unicode="q" d="M321 70q-45 -80 -116 -80q-80 0 -127.5 68.5t-47.5 201.5q0 137 46 203.5t129 66.5q35 0 62.5 -17.5t56.5 -62.5h2l2 70h132v-740h-137v290h-2zM167 260q0 -77 21.5 -113.5t56.5 -36.5q80 0 80 145v10q0 145 -80 145q-78 0 -78 -150z" />
<glyph unicode="r" d="M375 416q-69 0 -111 -52t-42 -144v-220h-137v520h135v-85h2q36 53 70.5 74t82.5 21q36 0 70 -10v-115q-36 11 -70 11z" />
<glyph unicode="s" d="M265 418q-73 0 -73 -43q0 -22 14.5 -35t48.5 -20q109 -21 149.5 -60t40.5 -115q0 -74 -50.5 -114.5t-144.5 -40.5q-107 0 -190 35v120q87 -43 165 -43q45 0 64 11.5t19 36.5q0 22 -14 34t-54 21q-99 21 -142 62.5t-43 112.5t49 110.5t146 39.5q99 0 180 -30v-115 q-87 33 -165 33z" />
<glyph unicode="t" d="M445 500v-109h-158v-201q0 -61 10.5 -74.5t57.5 -13.5q43 0 80 17v-114q-50 -15 -110 -15q-98 0 -136.5 36.5t-38.5 133.5v231h-105v109h105v190h137v-190h158z" />
<glyph unicode="u" d="M445 0h-132l-2 70h-2q-50 -80 -124 -80q-77 0 -108.5 44.5t-31.5 165.5v320h135v-300q0 -70 11 -91t44 -21q73 0 73 175v237h137v-520z" />
<glyph unicode="v" d="M251 90h2l79 430h138l-130 -520h-180l-130 520h142z" />
<glyph unicode="w" d="M343 120h2l29 400h116l-70 -520h-137l-37 358h-2l-31 -358h-133l-70 520h124l29 -400h2l39 400h100z" />
<glyph unicode="x" d="M251 335h2l69 185h143l-125 -260l125 -260h-152l-64 180h-2l-64 -180h-148l125 260l-125 260h147z" />
<glyph unicode="y" d="M254 170h2l87 350h142l-237 -740h-138l85 230l-170 510h142z" />
<glyph unicode="z" d="M275 411h-210v109h370v-109l-210 -300v-2h210v-109h-370v109l210 300v2z" />
<glyph unicode="{" d="M187 301v-2q58 -24 85.5 -62t27.5 -100v-112q0 -73 12 -86.5t75 -13.5h53v-95h-107q-80 0 -116.5 37t-36.5 123v147q0 61 -22 88t-68 27h-40v96h40q46 0 68 27t22 88v147q0 86 36.5 123t116.5 37h107v-95h-53q-63 0 -75 -13.5t-12 -86.5v-112q0 -62 -27.5 -100t-85.5 -62 z" />
<glyph unicode="|" d="M188 -220v1030h124v-1030h-124z" />
<glyph unicode="}" d="M313 301q-58 24 -85.5 62t-27.5 100v112q0 73 -12 86.5t-75 13.5h-53v95h107q80 0 116.5 -37t36.5 -123v-147q0 -61 22 -88t68 -27h40v-96h-40q-46 0 -68 -27t-22 -88v-147q0 -86 -36.5 -123t-116.5 -37h-107v95h53q63 0 75 13.5t12 86.5v112q0 62 27.5 100t85.5 62v2z " />
<glyph unicode="~" d="M40 568v107q45 35 100 35q63 0 131 -50q49 -37 84 -37q49 0 105 51v-107q-45 -35 -100 -35q-63 0 -131 50q-49 37 -84 37q-49 0 -105 -51z" />
<glyph unicode="&#xa0;" />
<glyph unicode="&#xa5;" d="M251 415h2l84 315h148l-132 -365h97v-95h-130v-65h130v-95h-130v-110h-140v110h-130v95h130v65h-130v95h97l-132 365h152z" />
<glyph unicode="&#xad;" d="M90 240v110h320v-110h-320z" />
<glyph unicode="&#x2000;" horiz-adv-x="407" />
<glyph unicode="&#x2001;" horiz-adv-x="815" />
<glyph unicode="&#x2002;" horiz-adv-x="407" />
<glyph unicode="&#x2003;" horiz-adv-x="815" />
<glyph unicode="&#x2004;" horiz-adv-x="271" />
<glyph unicode="&#x2005;" horiz-adv-x="203" />
<glyph unicode="&#x2006;" horiz-adv-x="135" />
<glyph unicode="&#x2007;" horiz-adv-x="135" />
<glyph unicode="&#x2008;" horiz-adv-x="101" />
<glyph unicode="&#x2009;" horiz-adv-x="163" />
<glyph unicode="&#x200a;" horiz-adv-x="45" />
<glyph unicode="&#x2010;" d="M90 240v110h320v-110h-320z" />
<glyph unicode="&#x2011;" d="M90 240v110h320v-110h-320z" />
<glyph unicode="&#x2013;" d="M50 240v110h400v-110h-400z" />
<glyph unicode="&#x2014;" d="M10 240v110h480v-110h-480z" />
<glyph unicode="&#x2018;" d="M305 460h-190l130 320h120z" />
<glyph unicode="&#x2019;" d="M190 780h190l-130 -320h-120z" />
<glyph unicode="&#x201c;" d="M405 460h-170l130 320h100zM195 460h-170l130 320h100z" />
<glyph unicode="&#x201d;" d="M300 780h170l-130 -320h-100zM90 780h170l-130 -320h-100z" />
<glyph unicode="&#x2026;" horiz-adv-x="1000" d="M72 270v190h190v-190h-190zM405 270v190h190v-190h-190zM738 270v190h190v-190h-190z" />
<glyph unicode="&#x202f;" horiz-adv-x="163" />
<glyph unicode="&#x205f;" horiz-adv-x="203" />
<glyph unicode="&#x2122;" horiz-adv-x="1000" d="M838 500h-2l-38 -300h-100l-38 300h-2v-500h-133v730h167l59 -400h2l59 400h163v-730h-137v500zM320 615v-615h-140v615h-145v115h430v-115h-145z" />
</font>
</defs></svg>

Before

Width:  |  Height:  |  Size: 17 KiB

View file

@ -1,134 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>
This is a custom SVG webfont generated by Font Squirrel.
Foundry URL : http://mplus-fonts.sourceforge.jp
</metadata>
<defs>
<font id="webfontVd14f4NN" horiz-adv-x="500" >
<font-face units-per-em="1000" ascent="860" descent="-140" />
<missing-glyph horiz-adv-x="500" />
<glyph unicode=" " />
<glyph unicode="!" d="M200 730h100l-10 -515h-80zM195 0v130h110v-130h-110z" />
<glyph unicode="&#x22;" d="M275 780h100l-20 -280h-60zM125 780h100l-20 -280h-60z" />
<glyph unicode="#" d="M40 188v72h77l29 228h-71v72h80l21 170h82l-21 -170h76l21 170h82l-21 -170h65v-72h-74l-29 -228h68v-72h-77l-23 -188h-82l23 188h-76l-23 -188h-82l23 188h-68zM199 260h76l29 228h-76z" />
<glyph unicode="$" d="M293 311v-214q58 21 58 108q0 71 -58 106zM293 19v-104h-76v101q-70 6 -137 49v95q65 -57 137 -69v251q-77 31 -109.5 75.5t-32.5 117.5q0 76 37 122.5t105 55.5v102h76v-102q69 -8 127 -38v-90q-52 38 -127 52v-237q77 -31 109.5 -76.5t32.5 -118.5q0 -163 -142 -186z M217 429v207q-58 -18 -58 -101q0 -73 58 -106z" />
<glyph unicode="%" d="M60 260l380 290v-80l-380 -290v80zM160 740q61 0 95.5 -41t34.5 -119t-34.5 -119t-95.5 -41t-95.5 41t-34.5 119t34.5 119t95.5 41zM340 310q61 0 95.5 -41t34.5 -119t-34.5 -119t-95.5 -41t-95.5 41t-34.5 119t34.5 119t95.5 41zM160 488q52 0 52 92t-52 92t-52 -92 t52 -92zM340 58q52 0 52 92t-52 92t-52 -92t52 -92z" />
<glyph unicode="&#x26;" d="M228 665q-38 0 -60.5 -20t-22.5 -55q0 -29 12.5 -59t53.5 -95q59 51 79 83.5t20 70.5q0 33 -22 54t-60 21zM151 385l-9 14q-47 71 -63.5 111.5t-16.5 79.5q0 66 45 108t118 42t119 -42t46 -108q0 -57 -30.5 -106.5t-106.5 -112.5l119 -183v217h80v-253q-13 -28 -26 -46 l69 -106h-87l-33 49q-69 -59 -175 -59q-82 0 -128.5 46t-46.5 129q0 107 126 220zM331 115l-137 206q-84 -79 -84 -153q0 -51 27 -77t78 -26q70 0 116 50z" />
<glyph unicode="'" d="M195 780h110l-25 -280h-60z" />
<glyph unicode="(" d="M125 315q0 275 194 455h76q-196 -184 -196 -455t196 -455h-76q-194 180 -194 455z" />
<glyph unicode=")" d="M375 315q0 -275 -194 -455h-76q196 184 196 455t-196 455h76q194 -180 194 -455z" />
<glyph unicode="*" d="M214 750h72l-3 -169l160 55l22 -68l-161 -50l101 -135l-58 -42l-97 138l-97 -138l-58 42l101 135l-161 50l22 68l160 -55z" />
<glyph unicode="+" d="M291 555v-214h149v-72h-149v-214h-82v214h-149v72h149v214h82z" />
<glyph unicode="," d="M210 150h120l-110 -280h-70z" />
<glyph unicode="-" d="M100 269v72h300v-72h-300z" />
<glyph unicode="." d="M185 0v150h130v-150h-130z" />
<glyph unicode="/" d="M452 730l-332 -770h-72l332 770h72z" />
<glyph unicode="0" d="M250 740q48 0 82 -18t59 -60t37 -115.5t12 -181.5t-12 -181.5t-37 -115.5t-59 -60t-82 -18t-82 18t-59 60t-37 115.5t-12 181.5t12 181.5t37 115.5t59 60t82 18zM142 249l196 339q-26 82 -88 82q-36 0 -60 -26t-38 -95t-14 -184q0 -50 4 -116zM158 155q26 -95 92 -95 q36 0 60 26t38 95t14 184q0 78 -6 133z" />
<glyph unicode="1" d="M258 0v645l-2 1l-173 -101v80l175 105h82v-730h-82z" />
<glyph unicode="2" d="M175 74v-2h245v-72h-340v72q251 288 251 478q0 116 -93 116q-30 0 -76 -22.5t-82 -55.5v87q75 65 170 65q85 0 125 -47t40 -143q0 -99 -54 -208t-186 -268z" />
<glyph unicode="3" d="M330 656v2h-250v72h345v-72l-180 -229v-2h10q91 0 133 -51t42 -166q0 -220 -195 -220q-73 0 -145 30v87q77 -43 130 -43q64 0 95 34.5t31 111.5q0 89 -25 117t-101 28h-70v72z" />
<glyph unicode="4" d="M293 590h-2l-175 -341v-2h177v343zM293 175h-253v82l243 473h92v-483h85v-72h-85v-175h-82v175z" />
<glyph unicode="5" d="M180 430h2q33 30 88 30q160 0 160 -230q0 -125 -49.5 -182.5t-145.5 -57.5q-74 0 -145 30v87q75 -43 140 -43q116 0 116 166q0 156 -96 156q-46 0 -80 -41h-75l10 385h305v-72h-223z" />
<glyph unicode="6" d="M285 740q61 0 115 -20v-77q-50 25 -105 25q-70 0 -101 -48.5t-39 -184.5h2q50 50 113 50q87 0 128.5 -56t41.5 -184q0 -134 -46.5 -194.5t-138.5 -60.5q-65 0 -104 28.5t-60 101.5t-21 200q0 158 25.5 252t71 131t118.5 37zM255 62q54 0 78.5 39t24.5 144q0 94 -23.5 132 t-74.5 38q-106 0 -106 -160q0 -107 25 -150t76 -43z" />
<glyph unicode="7" d="M345 656v2h-270v72h350v-72q-128 -296 -210 -658h-88q84 353 218 656z" />
<glyph unicode="8" d="M255 670q-53 0 -81.5 -27.5t-28.5 -77.5q0 -54 29 -94t76 -51q52 14 80.5 51.5t28.5 93.5q0 47 -28.5 76t-75.5 29zM250 -10q-96 0 -148 51t-52 149q0 68 33 119t92 75v2q-48 23 -79 73.5t-31 105.5q0 82 49 128.5t136 46.5t136 -47t49 -128q0 -56 -30.5 -103.5 t-79.5 -70.5v-2q59 -23 92 -75t33 -124q0 -98 -52 -149t-148 -51zM255 60q53 0 84 33.5t31 96.5q0 130 -125 160q-61 -16 -90 -54.5t-29 -105.5q0 -62 35 -96t94 -34z" />
<glyph unicode="9" d="M215 -10q-61 0 -115 20v80q52 -26 105 -26q70 0 101 47.5t39 183.5h-2q-50 -50 -113 -50q-84 0 -127 59t-43 191q0 126 46 185.5t139 59.5q68 0 107 -28t58.5 -100.5t19.5 -201.5q0 -158 -25.5 -252t-71 -131t-118.5 -37zM245 668q-55 0 -79 -38t-24 -135t25 -138.5 t73 -41.5q49 0 77.5 41.5t28.5 128.5q0 100 -25 141.5t-76 41.5z" />
<glyph unicode=":" d="M190 390v150h120v-150h-120zM190 0v150h120v-150h-120z" />
<glyph unicode=";" d="M200 150h120l-110 -280h-70zM200 390v150h120v-150h-120z" />
<glyph unicode="&#x3c;" d="M435 510l-330 -204v-2l330 -204v-80l-380 245v80l380 245v-80z" />
<glyph unicode="=" d="M60 165v72h380v-72h-380zM60 373v72h380v-72h-380z" />
<glyph unicode="&#x3e;" d="M65 510v80l380 -245v-80l-380 -245v80l330 204v2z" />
<glyph unicode="?" d="M445 580q0 -41 -14 -77t-28.5 -55t-42.5 -49q-29 -33 -43 -52t-28 -55t-14 -77h-80q0 55 16.5 101.5t32.5 68t47 56.5q24 27 36 42.5t23 41.5t11 55q0 41 -29.5 63.5t-86.5 22.5q-85 0 -180 -61v90q93 45 190 45q91 0 140.5 -42t49.5 -118zM180 0v130h110v-130h-110z" />
<glyph unicode="@" d="M375 258v167q0 41 -16 63t-44 22q-40 0 -56 -29.5t-16 -115.5q0 -82 17 -113.5t55 -31.5q44 0 60 38zM165 365q0 215 140 215q38 0 73 -25h2v5q0 50 -27.5 79t-72.5 29q-83 0 -124 -70.5t-41 -232.5q0 -166 40 -234.5t125 -68.5q62 0 125 38v-80q-59 -30 -130 -30 q-122 0 -181 86t-59 289q0 197 60.5 286t179.5 89q87 0 133.5 -50t46.5 -150v-325q-65 -65 -140 -65q-76 0 -113 49t-37 166z" />
<glyph unicode="A" d="M249 660h-2l-83 -380h168zM348 210h-200l-46 -210h-82l180 730h100l180 -730h-86z" />
<glyph unicode="B" d="M157 430h45q80 0 116.5 29.5t36.5 90.5q0 57 -36 88.5t-102 31.5q-36 0 -60 -8v-232zM157 360v-292q37 -8 90 -8q126 0 126 160q0 140 -161 140h-55zM455 210q0 -220 -225 -220q-80 0 -155 15v720q75 15 155 15q205 0 205 -180q0 -61 -30.5 -103t-84.5 -56v-2 q58 -11 96.5 -64t38.5 -125z" />
<glyph unicode="C" d="M55 365q0 197 60.5 286t179.5 89q66 0 125 -30v-75q-60 33 -120 33q-165 0 -165 -303q0 -164 42 -233.5t123 -69.5q62 0 125 38v-80q-59 -30 -130 -30q-122 0 -181 86t-59 289z" />
<glyph unicode="D" d="M383 365q0 168 -43.5 235.5t-137.5 67.5q-33 0 -55 -8v-590q22 -8 55 -8q65 0 102.5 24.5t58 91.5t20.5 187zM465 365q0 -207 -63.5 -291t-199.5 -84q-70 0 -137 15v720q67 15 137 15q137 0 200 -85.5t63 -289.5z" />
<glyph unicode="E" d="M162 658v-228h248v-70h-248v-288h258v-72h-340v730h340v-72h-258z" />
<glyph unicode="F" d="M172 360v-360h-82v730h330v-72h-248v-228h238v-70h-238z" />
<glyph unicode="G" d="M370 85v275h-155v70h235v-400q-80 -40 -170 -40q-118 0 -179 89t-61 286q0 196 63.5 285.5t191.5 89.5q59 0 130 -25v-77q-66 30 -130 30q-87 0 -132 -72t-45 -231q0 -303 167 -303q45 0 85 23z" />
<glyph unicode="H" d="M140 730v-298h216v298h84v-730h-84v360h-216v-360h-80v730h80z" />
<glyph unicode="I" d="M410 0h-320v70h118v590h-118v70h320v-70h-118v-590h118v-70z" />
<glyph unicode="J" d="M400 730v-540q0 -110 -43.5 -155t-146.5 -45q-82 0 -150 30v87q29 -17 75.5 -31t74.5 -14q53 0 79 30.5t26 99.5v468h-165v70h250z" />
<glyph unicode="K" d="M157 400h2l206 330h95l-225 -350l230 -380h-95l-211 360h-2v-360h-82v730h82v-330z" />
<glyph unicode="L" d="M182 730v-658h238v-72h-320v730h82z" />
<glyph unicode="M" d="M378 540h-2l-88 -340h-80l-88 340h-2v-540h-78v730h92l119 -450h2l119 450h88v-730h-82v540z" />
<glyph unicode="N" d="M151 550h-2v-550h-84v730h84l204 -550h2v550h80v-730h-80z" />
<glyph unicode="O" d="M250 740q107 0 158.5 -84.5t51.5 -290.5t-51.5 -290.5t-158.5 -84.5t-158.5 84.5t-51.5 290.5t51.5 290.5t158.5 84.5zM250 62q44 0 71 25.5t43 93.5t16 184t-16 184t-43 93.5t-71 25.5t-71 -25.5t-43 -93.5t-16 -184t16 -184t43 -93.5t71 -25.5z" />
<glyph unicode="P" d="M375 520q0 79 -36 114.5t-112 35.5q-41 0 -70 -8v-292q30 -5 70 -5q77 0 112.5 35.5t35.5 119.5zM455 520q0 -120 -52.5 -172.5t-165.5 -52.5q-35 0 -80 5v-300h-82v725q78 15 160 15q114 0 167 -52.5t53 -167.5z" />
<glyph unicode="Q" d="M250 740q107 0 158.5 -84.5t51.5 -290.5q0 -273 -100 -344v-2q41 -21 73 -66t47 -103h-88q-21 78 -54 109t-88 31q-107 0 -158.5 84.5t-51.5 290.5t51.5 290.5t158.5 84.5zM250 62q44 0 71 25.5t43 93.5t16 184t-16 184t-43 93.5t-71 25.5t-71 -25.5t-43 -93.5t-16 -184 t16 -184t43 -93.5t71 -25.5z" />
<glyph unicode="R" d="M370 540q0 130 -148 130q-41 0 -70 -8v-272h60q87 0 122.5 33.5t35.5 116.5zM152 320v-320h-82v725q78 15 160 15q112 0 166 -49.5t54 -150.5q0 -143 -109 -193v-2q31 -15 66 -131l63 -214h-86l-59 216q-17 64 -41 84t-82 20h-50z" />
<glyph unicode="S" d="M260 668q-47 0 -77.5 -30.5t-30.5 -77.5q0 -50 21.5 -82.5t71.5 -55.5q111 -49 153 -102.5t42 -139.5q0 -94 -51.5 -142t-148.5 -48q-91 0 -165 55v95q80 -78 170 -78q113 0 113 118q0 55 -26 91t-87 64q-94 42 -134.5 95.5t-40.5 129.5q0 80 51 130t134 50q53 0 87 -8 t78 -32v-90q-77 58 -160 58z" />
<glyph unicode="T" d="M209 0v660h-154v70h390v-70h-154v-660h-82z" />
<glyph unicode="U" d="M250 -10q-95 0 -142.5 48.5t-47.5 151.5v540h84v-520q0 -81 26.5 -114.5t81.5 -33.5t81.5 33.5t26.5 114.5v520h80v-540q0 -103 -47.5 -151.5t-142.5 -48.5z" />
<glyph unicode="V" d="M253 70l135 660h82l-170 -730h-100l-170 730h86l135 -660h2z" />
<glyph unicode="W" d="M153 120h2l54 510h90l54 -510h2l45 610h75l-60 -730h-109l-55 520h-2l-55 -520h-109l-60 730h83z" />
<glyph unicode="X" d="M251 440h2l112 290h83l-148 -355l150 -375h-90l-111 305h-2l-112 -305h-85l150 375l-148 355h88z" />
<glyph unicode="Y" d="M251 375h2l132 355h85l-179 -440v-290h-82v290l-179 440h90z" />
<glyph unicode="Z" d="M335 658v2h-260v70h350v-70l-260 -588v-2h260v-70h-350v70z" />
<glyph unicode="[" d="M390 710h-178v-790h178v-60h-250v910h250v-60z" />
<glyph unicode="\" d="M48 730h72l332 -770h-72z" />
<glyph unicode="]" d="M110 710v60h250v-910h-250v60h178v790h-178z" />
<glyph unicode="^" d="M251 680h-2l-147 -400h-72l170 450h100l170 -450h-72z" />
<glyph unicode="_" d="M50 -140v56h400v-56h-400z" />
<glyph unicode="`" d="M130 810h120l100 -280h-70z" />
<glyph unicode="a" d="M255 530q100 0 137.5 -40t37.5 -150v-340h-72l-2 75h-2q-47 -85 -149 -85q-65 0 -105 41.5t-40 113.5q0 91 61.5 140.5t183.5 49.5h48v25q0 57 -22 80t-76 23q-33 0 -84 -12t-86 -28v72q35 15 85 25t85 10zM353 275h-48q-170 0 -170 -125q0 -45 23 -69t62 -24q59 0 96 48 t37 135v35z" />
<glyph unicode="b" d="M144 445h2q43 85 134 85q175 0 175 -270q0 -135 -48 -202.5t-127 -67.5q-84 0 -137 85h-2l-2 -75h-74v730h79v-285zM376 260q0 195 -116 195q-51 0 -83.5 -49.5t-32.5 -140.5v-10q0 -91 32.5 -140.5t83.5 -49.5q53 0 84.5 48.5t31.5 146.5z" />
<glyph unicode="c" d="M70 260q0 134 55 202t155 68q61 0 125 -25v-80q-60 33 -120 33q-63 0 -98 -50t-35 -148q0 -101 37 -151t101 -50q59 0 120 36v-80q-64 -25 -125 -25q-102 0 -158.5 67.5t-56.5 202.5z" />
<glyph unicode="d" d="M356 730h79v-730h-74l-2 75h-2q-53 -85 -137 -85q-79 0 -127 67.5t-48 202.5q0 270 175 270q91 0 134 -85h2v285zM124 260q0 -98 31.5 -146.5t84.5 -48.5q51 0 83.5 49.5t32.5 140.5v10q0 91 -32.5 140.5t-83.5 49.5q-116 0 -116 -195z" />
<glyph unicode="e" d="M138 234q4 -93 38 -134t99 -41q61 0 135 36v-80q-74 -25 -140 -25q-215 0 -215 270q0 141 50 205.5t150 64.5q91 0 135.5 -62t44.5 -203q0 -11 -2 -31h-295zM138 300h218q-1 161 -101 161q-57 0 -85 -36t-32 -125z" />
<glyph unicode="f" d="M75 431v69h120v60q0 98 33 139t107 41q45 0 90 -15v-72q-38 18 -75 18q-47 0 -61.5 -23.5t-14.5 -107.5v-40h151v-69h-151v-431h-79v431h-120z" />
<glyph unicode="g" d="M50 260q0 270 175 270q83 0 137 -85h2l2 75h74v-515q0 -125 -50.5 -180t-154.5 -55q-71 0 -140 25v80q71 -36 140 -36q126 0 126 166v80h-2q-43 -85 -134 -85q-80 0 -127.5 66t-47.5 194zM129 260q0 -92 31.5 -138.5t84.5 -46.5q52 0 84 45.5t32 134.5v10 q0 91 -32.5 140.5t-83.5 49.5q-58 0 -87 -46.5t-29 -148.5z" />
<glyph unicode="h" d="M440 330v-330h-77v312q0 88 -20 117.5t-73 29.5q-50 0 -85.5 -56t-35.5 -151v-252h-79v730h79v-285h2q19 39 56.5 62t82.5 23q79 0 114.5 -45.5t35.5 -154.5z" />
<glyph unicode="i" d="M316 520v-452h109v-68h-330v68h139v384h-109v68h191zM214 640v120h102v-120h-102z" />
<glyph unicode="j" d="M249 -33v485h-119v68h201v-553q0 -65 -8.5 -101t-36.5 -59t-72 -30t-123 -7v68q40 0 63 1t42.5 6.5t28.5 12.5t15.5 23.5t7.5 34.5t1 51zM229 640v120h102v-120h-102z" />
<glyph unicode="k" d="M460 520l-230 -250l230 -270h-95l-206 253v-253h-79v730h79v-444l207 234h94z" />
<glyph unicode="l" d="M281 150q0 -66 10.5 -79t63.5 -13q33 0 75 6v-69q-47 -5 -85 -5q-90 0 -118 28.5t-28 121.5v522h-129v68h211v-580z" />
<glyph unicode="m" d="M290 0h-78v360q-1 58 -10.5 77.5t-32.5 19.5q-20 0 -35 -24t-25 -83.5t-10 -149.5v-200h-79v520h70l2 -70h2q17 38 42.5 59t53.5 21q31 0 50.5 -18.5t33.5 -61.5h2q39 80 104 80q53 0 76.5 -32.5t23.5 -117.5v-380h-77v360q-1 59 -11.5 78t-37.5 19q-64 0 -64 -197v-260z " />
<glyph unicode="n" d="M440 330v-330h-77v312q0 88 -20 117.5t-73 29.5q-50 0 -85.5 -56t-35.5 -151v-252h-79v520h74l2 -75h2q19 38 58 61.5t84 23.5q79 0 114.5 -45.5t35.5 -154.5z" />
<glyph unicode="o" d="M250 530q200 0 200 -270t-200 -270t-200 270t200 270zM250 59q61 0 89.5 45.5t28.5 155.5t-28.5 155.5t-89.5 45.5t-89.5 -45.5t-28.5 -155.5t28.5 -155.5t89.5 -45.5z" />
<glyph unicode="p" d="M141 75h-2v-295h-79v740h74l2 -75h2q54 85 137 85q175 0 175 -270q0 -135 -48 -202.5t-127 -67.5q-91 0 -134 85zM371 260q0 195 -116 195q-51 0 -83.5 -49.5t-32.5 -140.5v-10q0 -91 32.5 -140.5t83.5 -49.5q53 0 84.5 48.5t31.5 146.5z" />
<glyph unicode="q" d="M359 75q-43 -85 -134 -85q-79 0 -127 67.5t-48 202.5q0 270 175 270q83 0 137 -85h2l2 75h74v-740h-79v295h-2zM129 260q0 -98 31.5 -146.5t84.5 -48.5q51 0 83.5 49.5t32.5 140.5v10q0 91 -32.5 140.5t-83.5 49.5q-116 0 -116 -195z" />
<glyph unicode="r" d="M186 520v-100h2q62 110 172 110q37 0 70 -10v-70q-35 11 -70 11q-73 0 -122 -61t-49 -160v-240h-79v520h76z" />
<glyph unicode="s" d="M255 463q-96 0 -96 -73q0 -34 21 -54.5t75 -35.5q106 -30 140.5 -63t34.5 -102t-47 -107t-133 -38t-165 40v80q78 -53 155 -53q111 0 111 78q0 37 -21.5 57t-84.5 38q-92 26 -128.5 62t-36.5 98q0 66 43.5 103t126.5 37q84 0 160 -35v-75q-79 43 -155 43z" />
<glyph unicode="t" d="M244 500h181v-69h-181v-281q0 -56 16.5 -74.5t64.5 -18.5q50 0 90 18v-70q-48 -15 -100 -15q-84 0 -117 32.5t-33 117.5v291h-100v69h100v190h79v-190z" />
<glyph unicode="u" d="M65 180v340h77v-322q0 -83 18.5 -110t69.5 -27q49 0 82.5 55t33.5 152v252h79v-520h-74l-2 75h-2q-19 -40 -56 -62.5t-81 -22.5q-77 0 -111 43t-34 147z" />
<glyph unicode="v" d="M251 60h2l115 460h82l-145 -520h-110l-145 520h86z" />
<glyph unicode="w" d="M351 80h2l49 440h78l-80 -520h-99l-54 440h-2l-49 -440h-96l-80 520h82l49 -440h2l49 440h100z" />
<glyph unicode="x" d="M251 305h2l104 215h88l-145 -260l145 -260h-94l-102 215h-2l-102 -215h-90l145 260l-145 260h92z" />
<glyph unicode="y" d="M259 120h2l117 400h87l-240 -740h-83l78 230l-175 510h88z" />
<glyph unicode="z" d="M80 520h340v-69l-248 -380v-2h248v-69h-340v69l248 380v2h-248v69z" />
<glyph unicode="{" d="M195 316l4 -2q81 -38 81 -149v-135q0 -72 16.5 -91t78.5 -19h40v-60h-65q-73 0 -107.5 35.5t-34.5 114.5v150q0 66 -21.5 95.5t-66.5 29.5h-45v60h45q45 0 66.5 29.5t21.5 95.5v150q0 79 34.5 114.5t107.5 35.5h65v-60h-40q-62 0 -78.5 -19t-16.5 -91v-135q0 -61 -20 -95 t-65 -54z" />
<glyph unicode="|" d="M212 -220v1030h76v-1030h-76z" />
<glyph unicode="}" d="M305 316q-45 20 -65 54t-20 95v135q0 72 -16.5 91t-78.5 19h-40v60h65q73 0 107.5 -35.5t34.5 -114.5v-150q0 -66 21.5 -95.5t66.5 -29.5h45v-60h-45q-45 0 -66.5 -29.5t-21.5 -95.5v-150q0 -79 -34.5 -114.5t-107.5 -35.5h-65v60h40q62 0 78.5 19t16.5 91v135 q0 111 81 149z" />
<glyph unicode="~" d="M50 602v75q42 33 95 33q61 0 125 -48q48 -35 80 -35q25 0 47 10t53 39v-75q-42 -33 -95 -33q-61 0 -125 48q-47 35 -80 35q-25 0 -47 -10t-53 -39z" />
<glyph unicode="&#xa0;" />
<glyph unicode="&#xa5;" d="M251 375h2l132 355h85l-153 -375h123v-65h-149v-85h149v-65h-149v-140h-82v140h-149v65h149v85h-149v65h123l-153 375h90z" />
<glyph unicode="&#xad;" d="M100 269v72h300v-72h-300z" />
<glyph unicode="&#x2000;" horiz-adv-x="407" />
<glyph unicode="&#x2001;" horiz-adv-x="815" />
<glyph unicode="&#x2002;" horiz-adv-x="407" />
<glyph unicode="&#x2003;" horiz-adv-x="815" />
<glyph unicode="&#x2004;" horiz-adv-x="271" />
<glyph unicode="&#x2005;" horiz-adv-x="203" />
<glyph unicode="&#x2006;" horiz-adv-x="135" />
<glyph unicode="&#x2007;" horiz-adv-x="135" />
<glyph unicode="&#x2008;" horiz-adv-x="101" />
<glyph unicode="&#x2009;" horiz-adv-x="163" />
<glyph unicode="&#x200a;" horiz-adv-x="45" />
<glyph unicode="&#x2010;" d="M100 269v72h300v-72h-300z" />
<glyph unicode="&#x2011;" d="M100 269v72h300v-72h-300z" />
<glyph unicode="&#x2013;" d="M60 269v72h380v-72h-380z" />
<glyph unicode="&#x2014;" d="M20 269v72h460v-72h-460z" />
<glyph unicode="&#x2018;" d="M275 500h-120l110 280h70z" />
<glyph unicode="&#x2019;" d="M220 780h120l-110 -280h-70z" />
<glyph unicode="&#x201c;" d="M340 500h-110l110 280h60zM190 500h-110l110 280h60z" />
<glyph unicode="&#x201d;" d="M300 780h110l-110 -280h-60zM150 780h110l-110 -280h-60z" />
<glyph unicode="&#x2026;" horiz-adv-x="1000" d="M102 288v150h130v-150h-130zM435 288v150h130v-150h-130zM768 288v150h130v-150h-130z" />
<glyph unicode="&#x202f;" horiz-adv-x="163" />
<glyph unicode="&#x205f;" horiz-adv-x="203" />
<glyph unicode="&#x2122;" horiz-adv-x="1000" d="M878 540h-2l-88 -340h-80l-88 340h-2v-540h-78v730h92l119 -450h2l119 450h88v-730h-82v540zM209 0v660h-154v70h390v-70h-154v-660h-82z" />
</font>
</defs></svg>

Before

Width:  |  Height:  |  Size: 17 KiB

View file

@ -1,217 +0,0 @@
/*
* TABLE OF CONTENTS:
* - Browser reset
* - HTML elements
* - JsDoc styling
* - Media query check
*/
/*
* HTML ELEMENTS
*/
body {
padding: 1% 4% 1% 4%;
}
/*
* HTML ELEMENTS
*/
/*
* BEGIN JSDOC
*/
/* Start menu */
div.index div.menu {
position: fixed;
top: 0;
right: 0;
-moz-border-radius-bottomleft: 15px;
-webkit-border-bottom-left-radius: 15px;
-border-bottom-left-radius: 15px;
padding: 4px 5px 8px 10px;
-moz-box-shadow: 0px 0px 10px #c4c4c4;
-webkit-box-shadow: 0px 0px 10px #c4c4c4;
box-shadow: 0px 0px 10px #c4c4c4;
background-color: rgba(255, 255, 255, 0.9);
}
div.index input.classFilter {
display: none;
}
div.index div.indexLinks a {
float: right;
clear: both;
font-size: 1.1em;
}
div.index *.heading1 {
display:none;
}
div.index ul.classList {
display:none;
}
div.index div.fineprint {
display:none;
}
div.indexStatic {
display: none;
}
/* End menu */
/* Start content */
div.content *.classTitle {
margin-right: 60px;
margin-bottom: 15px;
}
div.content div.intro {
margin: 15px 0 35px;
}
div.content p.description.summary {
margin-bottom: 0.2em;
}
div.content div.props {
margin: 1.5em -2% 0 -2%;
padding: 2%;
}
table.summaryTable {
position: relative;
left: -10px;
width: 100%;
border-collapse: collapse;
box-sizing: content-box;
-moz-box-sizing: content-box;
-webkit-box-sizing: content-box;
-ms-box-sizing: content-box;
-o-box-sizing: content-box;
-icab-box-sizing: content-box;
-khtml-box-sizing: content-box;
}
*.sectionTitle {
padding: 0 10px 10px 0;
}
caption.sectionTitle {
padding-left: 10px;
}
table.summaryTable td,
table.summaryTable th {
padding: 0px 10px 10px 10px;
}
table.summaryTable tr:last-child td {
padding-bottom: 0;
}
table.summaryTable td.attributes {
width: 35%;
}
table.summaryTable td.nameDescription {
width: 65%
}
dl.detailList {
margin-top: 0.5em;
}
dl.detailList.nomargin + dl.detailList.nomargin {
margin-top: 0;
}
dl.detailList dt {
display: inline;
margin-right: 5px;
}
dl.detailList dt:before {
display: block;
content: "";
}
dl.detailList dd {
display: inline;
}
dl.detailList.params dt {
display: block;
}
dl.detailList.params dd {
display: block;
padding-left: 2em;
padding-bottom: 0.4em;
}
ul.fileList li {
margin-bottom: 1.5em;
}
.fixedFont.heading {
margin-bottom: 0.5em;
}
pre.code {
margin: 10px 0 10px 0;
padding: 10px;
border: 1px solid #ccc;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
}
/* End content */
/*
* END JSDOC
*/
/*
* START MEDIA QUERY CHECK
*/
.cssLoadCheck {
position: absolute;
top: -99999px;
left: -99999px;
border: 0;
width: 100px;
padding: 0;
overflow: hidden;
}
/*
* END MEDIA QUERY CHECK
*/

View file

@ -1,297 +0,0 @@
/*
* TABLE OF CONTENTS:
* - JsDoc styling
* - Media query check
*/
/*
* BEGIN JSDOC
*/
/* Start menu */
div.index {
position: fixed;
top: 0;
bottom: 0;
float: left;
width: 30%;
min-width: 100px;
max-width: 300px;
padding: 0 0 10px 0;
overflow: auto;
}
div.index *.heading1 {
padding: 8px 0 0 0;
}
div.index div.menu {
margin: 0 15px 0 -15px;
-moz-border-radius-bottomright: 15px;
-webkit-border-bottom-right-radius: 15px;
-border-bottom-right-radius: 15px;
padding: 15px 15px 15px 30px;
-moz-box-shadow: 0px 0px 10px #c4c4c4;
-webkit-box-shadow: 0px 0px 10px #c4c4c4;
box-shadow: 0px 0px 10px #c4c4c4;
background-color: rgba(255, 255, 255, 0.5);
}
div.index div.indexLinks {
margin-top: 13px;
position: absolute;
right: 30px;
}
div.index div.indexLinks a {
color: #999999;
text-transform: lowercase;
}
div.index div.indexLinks a:first-child {
margin-right: 3px;
border-right: 1px solid #999999;
padding-right: 5px;
}
div.index input.classFilter {
margin-bottom: 4px;
width: 100%;
border-width: 1px;
border-style: solid;
border-color: #CCCCCC #999999 #999999 #CCCCCC;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
-border-radius: 3px;
}
div.index ul.classList a {
line-height: 1.3em;
}
div.index ul.classList a + a {
margin-left: 0.5em;
}
div.index div.fineprint {
margin: 1em 0 0 15px;
color: #777;
font-size: 0.9em;
}
div.index div.fineprint a {
color: #777;
}
div.indexStatic {
position: static;
min-height: 1em;
}
/* End menu */
/* Start content */
div.content {
float: left;
width: 70%;
min-width: 300px;
max-width: 600px;
}
div.innerContent {
padding: 0 0 0 2.5em;
}
div.content ul,
div.content ol {
margin-bottom: 3em;
}
div.content ul.methodDetail {
margin-bottom: 0;
}
div.content *.classTitle {
position: relative;
left: -10px;
margin: -30px 0 15px 0;
-moz-border-radius: 15px;
-webkit-border-radius: 15px;
border-radius: 15px;
padding: 25px 15px 15px 15px;
background-color: #FFFFFF;
background-color: rgba(255, 255, 255, 0.5);
-moz-box-shadow: 0px 0px 10px #c4c4c4;
-webkit-box-shadow: 0px 0px 10px #c4c4c4;
box-shadow: 0px 0px 10px #c4c4c4;
}
div.content div.intro {
margin: 15px 0 45px
}
div.content p.summary {
margin-bottom: 0.5em;
}
div.content ul.summary {
margin-bottom: 1.5em;
}
div.content ul *.classname a,
div.content ul *.filename a {
font-family: Consolas, "Courier New", Courier, monospace;
text-decoration: none;
font-weight: bold;
}
div.content ul *.classname a:hover,
div.content ul *.filename a:hover {
text-decoration: underline;
}
div.content div.props {
position: relative;
left: -10px;
margin-bottom: 2.5em;
padding: 10px 15px 15px 15px;
overflow: hidden;
}
div.content div.hr {
margin: 0 10px 0 0;
height: 4em;
}
table.summaryTable {
position: relative;
left: -10px;
width: 100%;
border-collapse: collapse;
box-sizing: content-box;
-moz-box-sizing: content-box;
-webkit-box-sizing: content-box;
-ms-box-sizing: content-box;
-o-box-sizing: content-box;
-icab-box-sizing: content-box;
-khtml-box-sizing: content-box;
}
*.sectionTitle {
padding: 0 10px 10px 0;
}
caption.sectionTitle {
padding-left: 10px;
}
table.summaryTable td,
table.summaryTable th {
padding: 0px 10px 10px 10px;
}
table.summaryTable tr:last-child td {
padding-bottom: 0;
}
table.summaryTable td.attributes {
width: 35%;
}
table.summaryTable td.nameDescription {
width: 65%
}
dl.detailList {
margin-top: 0.5em;
}
dl.detailList.nomargin + dl.detailList.nomargin {
margin-top: 0;
}
dl.detailList dt {
display: inline;
margin-right: 5px;
}
dl.detailList dt:before {
display: block;
content: "";
}
dl.detailList dd {
display: inline;
}
dl.detailList.params dt {
display: block;
}
dl.detailList.params dd {
display: block;
padding-left: 2em;
padding-bottom: 0.4em;
}
ul.fileList li {
margin-bottom: 1.5em;
}
.fixedFont.heading {
margin-bottom: 0.5em;
}
pre.code {
margin: 10px 0 10px 0;
padding: 10px;
border: 1px solid #ccc;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
}
/* End content */
.clear {
clear: both;
width: 100%;
min-height: 0;
}
/*
* END JSDOC
*/
/*
* START MEDIA QUERY CHECK
*/
.cssLoadCheck {
position: absolute;
top: -99999px;
left: -99999px;
border: 0;
width: 100px;
padding: 0;
overflow: hidden;
}
/*
* END MEDIA QUERY CHECK
*/

View file

@ -1,326 +0,0 @@
/**
* @fileOverview Contains standard code in the namespace 'wbos' and code specifically written for Codeview in the namespace 'codeview'
* @author Wouter Bos (www.thebrightlines.com)
* @since 1.0 - 2010-09-10
* @version 1.0 - 2010-09-10
*/
if (typeof(wbos) == "undefined") {
/**
* @namespace Standard code of Wouter Bos (wbos)
*/
wbos = {}
}
if (typeof(wbos.CssTools) == "undefined") {
/**
* @namespace Namespace for CSS-related functionality
*/
wbos.CssTools = {}
}
/**
* @namespace Fallback for CSS advanced media query
* @class
* @since 1.0 - 2010-09-10
* @version 1.0 - 2010-09-10
*/
wbos.CssTools.MediaQueryFallBack = ( function() {
var config = {
cssScreen: "/css/screen.css",
cssHandheld: "/css/handheld.css",
mobileMaxWidth: 660,
testDivClass: "cssLoadCheck",
dynamicCssLinkId: "DynCssLink",
resizeDelay: 30
}
var noMediaQuery = false;
var delay;
var currentCssMediaType;
// Adding events to elements in the DOM without overwriting it
function addEvent(element, newFunction, eventType) {
var oldEvent = eval("element." + eventType);
var eventContentType = eval("typeof element." + eventType)
if ( eventContentType != 'function' ) {
eval("element." + eventType + " = newFunction")
} else {
eval("element." + eventType + " = function(e) { oldEvent(e); newFunction(e); }")
}
}
// Get the the inner width of the browser window
function getWindowWidth() {
if (window.innerWidth) {
return window.innerWidth;
} else if (document.documentElement.clientWidth) {
return document.documentElement.clientWidth;
} else if (document.body.clientWidth) {
return document.body.clientWidth;
} else{
return 0;
}
}
function addCssLink(cssHref) {
var cssNode = document.createElement('link');
var windowWidth;
cssNode.type = 'text/css';
cssNode.rel = 'stylesheet';
cssNode.media = 'screen, handheld, fallback';
cssNode.href = cssHref;
document.getElementsByTagName("head")[0].appendChild(cssNode);
}
/* Start public */
return {
/**
* Adds link to CSS in the head if no CSS is loaded
*
* @since 1.0 - 2010-08-21
* @version 1.0 - 2010-08-21
* @param {String|Object} cssScreen URL to CSS file for larger screens
* @param {String|Object} cssHandheld URL to CSS file for smaller screens
* @param {Number} mobileMaxWidth Maximum width for handheld devices
* @example
* wbos.CssTools.MediaQueryFallBack.LoadCss(['screen.css', 'screen2.css'], 'mobile.css', 480)
*/
LoadCss: function(cssScreen, cssHandheld, mobileMaxWidth) {
// Set config values
if (typeof(cssScreen) != "undefined") {
config.cssScreen = cssScreen;
}
if (typeof(cssHandheld) != "undefined") {
config.cssHandheld = cssHandheld;
}
if (typeof(mobileMaxWidth) != "undefined") {
config.mobileMaxWidth = mobileMaxWidth;
}
// Check if CSS is loaded
var cssloadCheckNode = document.createElement('div');
cssloadCheckNode.className = config.testDivClass;
document.getElementsByTagName("body")[0].appendChild(cssloadCheckNode);
if (cssloadCheckNode.offsetWidth != 100 && noMediaQuery == false) {
noMediaQuery = true;
}
cssloadCheckNode.parentNode.removeChild(cssloadCheckNode)
if (noMediaQuery == true) {
// Browser does not support Media Queries, so JavaScript will supply a fallback
var cssHref = "";
// Determines what CSS file to load
if (getWindowWidth() <= config.mobileMaxWidth) {
cssHref = config.cssHandheld;
newCssMediaType = "handheld";
} else {
cssHref = config.cssScreen;
newCssMediaType = "screen";
}
// Add CSS link to <head> of page
if (cssHref != "" && currentCssMediaType != newCssMediaType) {
var currentCssLinks = document.styleSheets
for (var i = 0; i < currentCssLinks.length; i++) {
for (var ii = 0; ii < currentCssLinks[i].media.length; ii++) {
if (typeof(currentCssLinks[i].media) == "object") {
if (currentCssLinks[i].media.item(ii) == "fallback") {
currentCssLinks[i].ownerNode.parentNode.removeChild(currentCssLinks[i].ownerNode)
i--
break;
}
} else {
if (currentCssLinks[i].media.indexOf("fallback") >= 0) {
currentCssLinks[i].owningElement.parentNode.removeChild(currentCssLinks[i].owningElement)
i--
break;
}
}
}
}
if (typeof(cssHref) == "object") {
for (var i = 0; i < cssHref.length; i++) {
addCssLink(cssHref[i])
}
} else {
addCssLink(cssHref)
}
currentCssMediaType = newCssMediaType;
}
// Check screen size again if user resizes window
addEvent(window, wbos.CssTools.MediaQueryFallBack.LoadCssDelayed, 'onresize')
}
},
/**
* Runs LoadCSS after a short delay
*
* @since 1.0 - 2010-08-21
* @version 1.0 - 2010-08-21
* @example
* wbos.CssTools.MediaQueryFallBack.LoadCssDelayed()
*/
LoadCssDelayed: function() {
clearTimeout(delay);
delay = setTimeout( "wbos.CssTools.MediaQueryFallBack.LoadCss()", config.resizeDelay)
}
}
/* End public */
})();
/**
* @namespace Adds a function to an event of a single element. Use this if
* you don't want to use jQuery
* @class
* @since 1.0 - 2010-02-23
* @version 1.0 - 2010-02-23
*/
wbos.Events = ( function() {
/* Start public */
return {
/**
* Adds a function to an event of a single element
*
* @since 1.0 - 2010-02-23
* @version 1.0 - 2010-02-23
* @param {Object} element The element on which the event is placed
* @param {Function} newFunction The function that has to be linked to the event
* @param {String} eventType Name of the event
* @example
* wbos.Events.AddEvent( document.getElementById('elementId'), functionName, "onclick" )
*/
AddEvent: function( element, newFunction, eventType ) {
var oldEvent = eval("element." + eventType);
var eventContentType = eval("typeof element." + eventType)
if ( eventContentType != 'function' ) {
eval("element." + eventType + " = newFunction")
} else {
eval("element." + eventType + " = function(e) { oldEvent(e); newFunction(e); }")
}
}
}
/* End public */
})();
if (typeof(codeview) == "undefined") {
/**
* @namespace Code written for the Codeview template
*/
codeview = {}
}
/**
* @namespace Enables filtering in class lists
* @class
* @since 1.0 - 2010-11-08
* @version 1.0 - 2010-11-08
*/
codeview.classFilter = ( function() {
function onkeyup_ClassFilter() {
var listItems
var search = document.getElementById('ClassFilter').value
search = search.toLowerCase()
if (document.getElementById('ClassList')) {
listItems = document.getElementById('ClassList').getElementsByTagName('li')
filterList(listItems, search)
}
if (document.getElementById('ClassList2')) {
listItems = document.getElementById('ClassList2').getElementsByTagName('li')
filterList(listItems, search)
}
if (document.getElementById('FileList')) {
listItems = document.getElementById('FileList').getElementsByTagName('li')
filterList(listItems, search)
}
if (document.getElementById('MethodsListInherited')) {
var links = document.getElementById('MethodsListInherited').getElementsByTagName('a')
var linksSelected = new Array()
for (var i=0; i < links.length; i++) {
if (links[i].parentNode.parentNode.tagName == "DD") {
linksSelected.push(links[i])
}
}
filterList(linksSelected, search)
}
if (document.getElementById('MethodsList')) {
listItems = document.getElementById('MethodsList').getElementsByTagName('tbody')[0].getElementsByTagName('tr')
filterList(listItems, search, document.getElementById('MethodDetail').getElementsByTagName('li'))
}
}
function filterList(listItems, search, relatedElements) {
var itemContent = ""
for (var i=0; i < listItems.length; i++) {
itemContent = listItems[i].textContent||listItems[i].innerText
if (itemContent != undefined) {
itemContent = itemContent.toLowerCase()
itemContent = itemContent.replace(/\s/g, "")
if (itemContent.indexOf(search) >= 0 || itemContent == "") {
listItems[i].style.display = ""
} else {
listItems[i].style.display = "none"
}
if (relatedElements != null) {
filterRelatedList(listItems[i], search, relatedElements)
}
}
}
}
function filterRelatedList(listItem, search, relatedElements) {
var itemIndex = parseInt(listItem.className.replace('item', ''))
if (itemIndex <= relatedElements.length) {
if (relatedElements[itemIndex].className == "item"+ itemIndex) {
relatedElements[itemIndex].style.display = listItem.style.display
}
}
}
/* Start public */
return {
Init: function() {
wbos.Events.AddEvent(
document.getElementById('ClassFilter'),
onkeyup_ClassFilter,
"onkeyup"
)
}
}
/* End public */
})();

View file

@ -1,6 +0,0 @@
// html5shiv MIT @rem remysharp.com/html5-enabling-script
// iepp v1.6.2 MIT @jon_neal iecss.com/print-protector
/*@cc_on(function(m,c){var z="abbr|article|aside|audio|canvas|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video";function n(d){for(var a=-1;++a<o;)d.createElement(i[a])}function p(d,a){for(var e=-1,b=d.length,j,q=[];++e<b;){j=d[e];if((a=j.media||a)!="screen")q.push(p(j.imports,a),j.cssText)}return q.join("")}var g=c.createElement("div");g.innerHTML="<z>i</z>";if(g.childNodes.length!==1){var i=z.split("|"),o=i.length,s=RegExp("(^|\\s)("+z+")",
"gi"),t=RegExp("<(/*)("+z+")","gi"),u=RegExp("(^|[^\\n]*?\\s)("+z+")([^\\n]*)({[\\n\\w\\W]*?})","gi"),r=c.createDocumentFragment(),k=c.documentElement;g=k.firstChild;var h=c.createElement("body"),l=c.createElement("style"),f;n(c);n(r);g.insertBefore(l,
g.firstChild);l.media="print";m.attachEvent("onbeforeprint",function(){var d=-1,a=p(c.styleSheets,"all"),e=[],b;for(f=f||c.body;(b=u.exec(a))!=null;)e.push((b[1]+b[2]+b[3]).replace(s,"$1.iepp_$2")+b[4]);for(l.styleSheet.cssText=e.join("\n");++d<o;){a=c.getElementsByTagName(i[d]);e=a.length;for(b=-1;++b<e;)if(a[b].className.indexOf("iepp_")<0)a[b].className+=" iepp_"+i[d]}r.appendChild(f);k.appendChild(h);h.className=f.className;h.innerHTML=f.innerHTML.replace(t,"<$1font")});m.attachEvent("onafterprint",
function(){h.innerHTML="";k.removeChild(h);k.appendChild(f);l.styleSheet.cssText=""})}})(this,document);@*/

View file

@ -1,21 +0,0 @@
The Codeview template is, like JsDoc Toolkit itself, published under the X11/MIT License.
Codeview is Copyright (c) 2010 Wouter Bos (www.thebrightlines.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View file

@ -1,236 +0,0 @@
/** Called automatically by JsDoc Toolkit. */
function publish(symbolSet) {
publish.conf = { // trailing slash expected for dirs
ext: ".html",
outDir: JSDOC.opt.d || SYS.pwd+"../out/jsdoc/",
templatesDir: JSDOC.opt.t || SYS.pwd+"../templates/jsdoc/",
staticDir: "static/",
symbolsDir: "symbols/",
srcDir: "symbols/src/",
cssDir: "css/",
fontsDir: "css/fonts/",
jsDir: "javascript/",
templateName: "Codeview",
templateVersion: "1.2",
templateLink: "http://www.thebrightlines.com/2010/05/06/new-template-for-jsdoctoolkit-codeview/"
};
// is source output is suppressed, just display the links to the source file
if (JSDOC.opt.s && defined(Link) && Link.prototype._makeSrcLink) {
Link.prototype._makeSrcLink = function(srcFilePath) {
return "&lt;"+srcFilePath+"&gt;";
}
}
// create the folders and subfolders to hold the output
IO.mkPath((publish.conf.outDir+publish.conf.cssDir));
IO.mkPath((publish.conf.outDir+publish.conf.fontsDir));
IO.mkPath((publish.conf.outDir+publish.conf.jsDir));
IO.mkPath((publish.conf.outDir+"symbols/src").split("/"));
// used to allow Link to check the details of things being linked to
Link.symbolSet = symbolSet;
// create the required templates
try {
var classTemplate = new JSDOC.JsPlate(publish.conf.templatesDir+"class.tmpl");
}
catch(e) {
print("Couldn't create the required templates: "+e);
quit();
}
// some utility filters
function hasNoParent($) {return ($.memberOf == "")}
function isaFile($) {return ($.is("FILE"))}
function isaClass($) {return (($.is("CONSTRUCTOR") || $.isNamespace) && ($.alias != "_global_" || !JSDOC.opt.D.noGlobal))}
// get an array version of the symbolset, useful for filtering
var symbols = symbolSet.toArray();
// create the hilited source code files
var files = JSDOC.opt.srcFiles;
for (var i = 0, l = files.length; i < l; i++) {
var file = files[i];
var srcDir = publish.conf.outDir + publish.conf.srcDir;
makeSrcFile(file, srcDir);
}
// get a list of all the classes in the symbolset
publish.classes = symbols.filter(isaClass).sort(makeSortby("alias"));
// create a filemap in which outfiles must be to be named uniquely, ignoring case
if (JSDOC.opt.u) {
var filemapCounts = {};
Link.filemap = {};
for (var i = 0, l = publish.classes.length; i < l; i++) {
var lcAlias = publish.classes[i].alias.toLowerCase();
if (!filemapCounts[lcAlias]) filemapCounts[lcAlias] = 1;
else filemapCounts[lcAlias]++;
Link.filemap[publish.classes[i].alias] =
(filemapCounts[lcAlias] > 1)?
lcAlias+"_"+filemapCounts[lcAlias] : lcAlias;
}
}
// create each of the class pages
for (var i = 0, l = publish.classes.length; i < l; i++) {
var symbol = publish.classes[i];
symbol.events = symbol.getEvents(); // 1 order matters
symbol.methods = symbol.getMethods(); // 2
var output = "";
output = classTemplate.process(symbol);
IO.saveFile(publish.conf.outDir+publish.conf.symbolsDir, ((JSDOC.opt.u)? Link.filemap[symbol.alias] : symbol.alias) + publish.conf.ext, output);
}
// create the class index page
try {
var classesindexTemplate = new JSDOC.JsPlate(publish.conf.templatesDir+"allclasses.tmpl");
}
catch(e) { print(e.message); quit(); }
var classesIndex = classesindexTemplate.process(publish.classes);
IO.saveFile(publish.conf.outDir, (JSDOC.opt.D.index=="files"?"allclasses":"index")+publish.conf.ext, classesIndex);
classesindexTemplate = classesIndex = classes = null;
// create the file index page
try {
var fileindexTemplate = new JSDOC.JsPlate(publish.conf.templatesDir+"allfiles.tmpl");
}
catch(e) { print(e.message); quit(); }
var documentedFiles = symbols.filter(isaFile); // files that have file-level docs
var allFiles = []; // not all files have file-level docs, but we need to list every one
for (var i = 0; i < files.length; i++) {
allFiles.push(new JSDOC.Symbol(files[i], [], "FILE", new JSDOC.DocComment("/** */")));
}
for (var i = 0; i < documentedFiles.length; i++) {
var offset = files.indexOf(documentedFiles[i].alias);
allFiles[offset] = documentedFiles[i];
}
allFiles = allFiles.sort(makeSortby("name"));
// output the file index page
var filesIndex = fileindexTemplate.process(allFiles);
IO.saveFile(publish.conf.outDir, (JSDOC.opt.D.index=="files"?"index":"files")+publish.conf.ext, filesIndex);
fileindexTemplate = filesIndex = files = null;
// copy static files
IO.copyFile(publish.conf.templatesDir+"/"+publish.conf.cssDir+"all.css", publish.conf.outDir+"/"+publish.conf.cssDir);
IO.copyFile(publish.conf.templatesDir+"/"+publish.conf.cssDir+"screen.css", publish.conf.outDir+"/"+publish.conf.cssDir);
IO.copyFile(publish.conf.templatesDir+"/"+publish.conf.cssDir+"handheld.css", publish.conf.outDir+"/"+publish.conf.cssDir);
IO.copyFile(publish.conf.templatesDir+"/"+publish.conf.jsDir+"all.js", publish.conf.outDir+"/"+publish.conf.jsDir);
IO.copyFile(publish.conf.templatesDir+"/"+publish.conf.jsDir+"html5.js", publish.conf.outDir+"/"+publish.conf.jsDir);
IO.copyFile(publish.conf.templatesDir+"/"+publish.conf.fontsDir+"mplus-1m-regular-webfont.eot", publish.conf.outDir+"/"+publish.conf.fontsDir);
IO.copyFile(publish.conf.templatesDir+"/"+publish.conf.fontsDir+"mplus-1m-regular-webfont.svg", publish.conf.outDir+"/"+publish.conf.fontsDir);
IO.copyFile(publish.conf.templatesDir+"/"+publish.conf.fontsDir+"mplus-1m-regular-webfont.ttf", publish.conf.outDir+"/"+publish.conf.fontsDir);
IO.copyFile(publish.conf.templatesDir+"/"+publish.conf.fontsDir+"mplus-1m-regular-webfont.woff", publish.conf.outDir+"/"+publish.conf.fontsDir);
IO.copyFile(publish.conf.templatesDir+"/"+publish.conf.fontsDir+"mplus-1m-bold-webfont.eot", publish.conf.outDir+"/"+publish.conf.fontsDir);
IO.copyFile(publish.conf.templatesDir+"/"+publish.conf.fontsDir+"mplus-1m-bold-webfont.svg", publish.conf.outDir+"/"+publish.conf.fontsDir);
IO.copyFile(publish.conf.templatesDir+"/"+publish.conf.fontsDir+"mplus-1m-bold-webfont.ttf", publish.conf.outDir+"/"+publish.conf.fontsDir);
IO.copyFile(publish.conf.templatesDir+"/"+publish.conf.fontsDir+"mplus-1m-bold-webfont.woff", publish.conf.outDir+"/"+publish.conf.fontsDir); }
/** Include a sub-template in the current template, specifying a data object */
function subtemplate(template, data) {
try {
return new JSDOC.JsPlate(publish.conf.templatesDir+template).process(data);
}
catch(e) { print(e.message); quit(); }
}
/** Just the first sentence (up to a full stop). Should not break on dotted variable names. */
function summarize(desc) {
if (typeof desc != "undefined")
return desc.match(/([\w\W]+?\.)[^a-z0-9_$]/i)? RegExp.$1 : desc;
}
/** Make a symbol sorter by some attribute. */
function makeSortby(attribute) {
return function(a, b) {
if (a[attribute] != undefined && b[attribute] != undefined) {
a = a[attribute].toLowerCase();
b = b[attribute].toLowerCase();
if (a < b) return -1;
if (a > b) return 1;
return 0;
}
}
}
function wordwrapNamespace(classLink) {
var classText = classLink.match(/[^<>]+(?=[<])/) + "";
var classTextNew = classText.replace(/\./g, "<span class='break'> </span>.<span class='break'> </span>") + "";
classLink = classLink.replace(/[^<>]+(?=[<])/, classTextNew);
return classLink;
}
/** Pull in the contents of an external file at the given path. */
function include(path) {
var path = publish.conf.templatesDir+path;
return IO.readFile(path);
}
/** Turn a raw source file into a code-hilited page in the docs. */
function makeSrcFile(path, srcDir, name) {
if (JSDOC.opt.s) return;
if (!name) {
name = path.replace(/\.\.?[\\\/]/g, "").replace(/[\\\/]/g, "_");
name = name.replace(/\:/g, "_");
}
var src = {path: path, name:name, charset: IO.encoding, hilited: ""};
if (defined(JSDOC.PluginManager)) {
JSDOC.PluginManager.run("onPublishSrc", src);
}
if (src.hilited) {
IO.saveFile(srcDir, name+publish.conf.ext, src.hilited);
}
}
/** Build output for displaying function parameters. */
function makeSignature(params) {
if (!params) return "()";
var signature = "("
+
params.filter(
function($) {
return $.name.indexOf(".") == -1; // don't show config params in signature
}
).map(
function($) {
return $.name;
}
).join(", ")
+
")";
return signature;
}
/** Find symbol {@link ...} strings in text and turn into html links */
function resolveLinks(str, from) {
str = str.replace(/\{@link ([^}]+)\}/gi,
function(match, symbolName) {
symbolName = symbolName.trim();
var index = symbolName.indexOf(' ');
if (index > 0) {
var label = symbolName.substring(index + 1);
symbolName = symbolName.substring(0, index);
return new Link().toSymbol(symbolName).withText(label);
} else {
return new Link().toSymbol(symbolName);
}
}
);
return str;
}

View file

@ -1,6 +0,0 @@
<script type="text/javascript">
wbos.CssTools.MediaQueryFallBack.LoadCss('{+Link.base+}css/screen.css', '{+Link.base+}css/handheld.css', 660)
codeview.classFilter.Init()
</script>
</body>
</html>

View file

@ -1,22 +0,0 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta charset="{+IO.encoding+}"></meta>
<meta name="generator" content="JsDoc Toolkit"></meta>
<title>{+data.subtitle+} | <if test="JSDOC.opt.D.title">{+JSDOC.opt.D.title+}<else />JsDoc Reference</if></title>
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0;"></meta>
<meta name="mobileoptimized" content="0"></meta>
<link rel="stylesheet" href="{+Link.base+}css/all.css" media="all"></link>
<link rel="stylesheet" href="{+Link.base+}css/handheld.css" media="only screen and (max-width: 660px)"></link>
<link rel="stylesheet" href="{+Link.base+}css/handheld.css" media="handheld"></link>
<link rel="stylesheet" href="{+Link.base+}css/screen.css" media="screen and (min-width: 661px)"></link>
<script src="{+Link.base+}javascript/all.js"></script>
<!--[if lt IE 9]>
<script src="{+Link.base+}javascript/html5.js"></script>
<![endif]-->
</head>
<body>

View file

@ -1,38 +0,0 @@
<div class="index">
<div class="menu">
<div class="indexLinks">
{+new Link().toFile(JSDOC.opt.D.index=="files"?"allclasses.html":"index.html").withText("Classes")+}
{+new Link().toFile(JSDOC.opt.D.index=="files"?"index.html":"files.html").withText("Files")+}
</div>
<h2 class="heading1">Classes</h2>
<input type="text" name="classFilter" class="classFilter" id="ClassFilter" placeholder="Filter"></input>
<nav>
<ul class="classList" id="ClassList">
<for each="thisClass" in="publish.classes">
<li>{!
var classLink = new Link().toClass(thisClass.alias) + "";
output += wordwrapNamespace(classLink);
!}</li>
</for>
</ul>
</nav>
</div>
<div class="fineprint" style="clear:both">
<if test="JSDOC.opt.D.copyright">&copy;{+JSDOC.opt.D.copyright+}<br /></if>
Documentation generator: <a href="http://code.google.com/p/jsdoc-toolkit/" target="_blank">JsDoc Toolkit</a> {+JSDOC.VERSION+}<br />
Template: <a href="{+publish.conf.templateLink+}" target="_blank">{+publish.conf.templateName+}</a> {+publish.conf.templateVersion+}<br />
Generated on: {!
var date = new Date();
var minutes = date.getMinutes() +"";
if (minutes.length == 1) {
minutes = '0'+ minutes;
}
output += date.getFullYear() +"-"+ date.getMonth() +"-"+ date.getDate() +" "+ date.getHours() +":"+ minutes;
!}
</div>
</div>
<div class="index indexStatic"></div>

View file

@ -1,17 +0,0 @@
<div align="center">{+new Link().toFile("index.html").withText("Class Index")+}
| {+new Link().toFile("files.html").withText("File Index")+}</div>
<hr />
<h2>Classes</h2>
<ul class="classList">
<for each="thisClass" in="data">
<li>{!
if (thisClass.alias == "_global_") {
output += "<i>"+new Link().toClass(thisClass.alias)+"</i>";
}
else {
output += new Link().toClass(thisClass.alias);
}
!}</li>
</for>
</ul>
<hr />

View file

@ -1,57 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset={+IO.encoding+}" />
{! Link.base = ""; /* all generated links will be relative to this */ !}
<title>JsDoc Reference - File Index</title>
<meta name="generator" content="JsDoc Toolkit" />
<style type="text/css">
{+include("static/default.css")+}
</style>
</head>
<body>
<div><strong>{+JSDOC.opt.D.title+}</strong></div>
{+include("static/header.html")+}
<div id="index">
{+publish.classesIndex+}
</div>
<div id="content">
<h1 class="classTitle">File Index</h1>
<for each="item" in="data">
<div>
<h2>{+new Link().toSrc(item.alias).withText(item.name)+}</h2>
<if test="item.desc">{+resolveLinks(item.desc)+}</if>
<dl>
<if test="item.author">
<dt class="heading">Author:</dt>
<dd>{+item.author+}</dd>
</if>
<if test="item.version">
<dt class="heading">Version:</dt>
<dd>{+item.version+}</dd>
</if>
{! var locations = item.comment.getTag('location').map(function($){return $.toString().replace(/(^\$ ?| ?\$$)/g, '').replace(/^HeadURL: https:/g, 'http:');}) !}
<if test="locations.length">
<dt class="heading">Location:</dt>
<for each="location" in="locations">
<dd><a href="{+location+}">{+location+}</a></dd>
</for>
</if>
</dl>
</div>
<hr />
</for>
</div>
<div class="fineprint" style="clear:both">
<if test="JSDOC.opt.D.copyright">&copy;{+JSDOC.opt.D.copyright+}<br /></if>
Documentation generated by <a href="http://code.google.com/p/jsdoc-toolkit/" target="_blankt">JsDoc Toolkit</a> {+JSDOC.VERSION+} on {+new Date()+}
</div>
</body>
</html>

View file

@ -1,650 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset={+IO.encoding+}" />
<meta name="generator" content="JsDoc Toolkit" />
{! Link.base = "../"; /* all generated links will be relative to this */ !}
<title>JsDoc Reference - {+data.alias+}</title>
<style type="text/css">
{+include("static/default.css")+}
</style>
</head>
<body>
<!-- ============================== header ================================= -->
<!-- begin static/header.html -->
<div><strong>{+JSDOC.opt.D.title+}</strong></div>
{+include("static/header.html")+}
<!-- end static/header.html -->
<!-- ============================== classes index ============================ -->
<div id="index">
<!-- begin publish.classesIndex -->
{+publish.classesIndex+}
<!-- end publish.classesIndex -->
</div>
<div id="content">
<!-- ============================== class title ============================ -->
<h1 class="classTitle">
{!
var classType = "";
if (data.isBuiltin()) {
classType += "Built-In ";
}
if (data.isNamespace) {
if (data.is('FUNCTION')) {
classType += "Function ";
}
classType += "Namespace ";
}
else {
classType += "Class ";
}
!}
{+classType+}{+data.alias+}
</h1>
<!-- ============================== class summary ========================== -->
<p class="description">
<if test="data.version"><br />Version
{+ data.version +}.<br />
</if>
<if test="data.augments.length"><br />Extends
{+
data.augments
.sort()
.map(
function($) { return new Link().toSymbol($); }
)
.join(", ")
+}.<br />
</if>
{+resolveLinks(data.classDesc)+}
<if test="!data.isBuiltin()">{# isn't defined in any file #}
<br /><i>Defined in: </i> {+new Link().toSrc(data.srcFile)+}.
</if>
</p>
<!-- ============================== constructor summary ==================== -->
<if test="!data.isBuiltin() && (data.isNamespace || data.is('CONSTRUCTOR'))">
<table class="summaryTable" cellspacing="0" summary="A summary of the constructor documented in the class {+data.alias+}.">
<caption>{+classType+}Summary</caption>
<thead>
<tr>
<th scope="col">Constructor Attributes</th>
<th scope="col">Constructor Name and Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="attributes">{!
if (data.isPrivate) output += "&lt;private&gt; ";
if (data.isInner) output += "&lt;inner&gt; ";
!}&nbsp;</td>
<td class="nameDescription" {!if (data.comment.getTag("hilited").length){output += 'style="color: red"'}!}>
<div class="fixedFont">
<b>{+ new Link().toSymbol(data.alias).inner('constructor')+}</b><if test="classType != 'Namespace '">{+ makeSignature(data.params) +}</if>
</div>
<div class="description">{+resolveLinks(summarize(data.desc))+}</div>
</td>
</tr>
</tbody>
</table>
</if>
<!-- ============================== properties summary ===================== -->
<if test="data.properties.length">
{! var ownProperties = data.properties.filter(function($){return $.memberOf == data.alias && !$.isNamespace}).sort(makeSortby("name")); !}
<if test="ownProperties.length">
<table class="summaryTable" cellspacing="0" summary="A summary of the fields documented in the class {+data.alias+}.">
<caption>Field Summary</caption>
<thead>
<tr>
<th scope="col">Field Attributes</th>
<th scope="col">Field Name and Description</th>
</tr>
</thead>
<tbody>
<for each="member" in="ownProperties">
<tr>
<td class="attributes">{!
if (member.isPrivate) output += "&lt;private&gt; ";
if (member.isInner) output += "&lt;inner&gt; ";
if (member.isStatic) output += "&lt;static&gt; ";
if (member.isConstant) output += "&lt;constant&gt; ";
!}&nbsp;</td>
<td class="nameDescription">
<div class="fixedFont">
<if test="member.isStatic && member.memberOf != '_global_'">{+member.memberOf+}.</if><b>{+new Link().toSymbol(member.alias).withText(member.name)+}</b>
</div>
<div class="description">{+resolveLinks(summarize(member.desc))+}</div>
</td>
</tr>
</for>
</tbody>
</table>
</if>
<if test="data.inheritsFrom.length">
<dl class="inheritsList">
{!
var borrowedMembers = data.properties.filter(function($) {return $.memberOf != data.alias});
var contributers = [];
borrowedMembers.map(function($) {if (contributers.indexOf($.memberOf) < 0) contributers.push($.memberOf)});
for (var i = 0, l = contributers.length; i < l; i++) {
output +=
"<dt>Fields borrowed from class "+new Link().toSymbol(contributers[i])+": </dt>"
+
"<dd>" +
borrowedMembers
.filter(
function($) { return $.memberOf == contributers[i] }
)
.sort(makeSortby("name"))
.map(
function($) { return new Link().toSymbol($.alias).withText($.name) }
)
.join(", ")
+
"</dd>";
}
!}
</dl>
</if>
</if>
<!-- ============================== methods summary ======================== -->
<if test="data.methods.length">
{! var ownMethods = data.methods.filter(function($){return $.memberOf == data.alias && !$.isNamespace}).sort(makeSortby("name")); !}
<if test="ownMethods.length">
<table class="summaryTable" cellspacing="0" summary="A summary of the methods documented in the class {+data.alias+}.">
<caption>Method Summary</caption>
<thead>
<tr>
<th scope="col">Method Attributes</th>
<th scope="col">Method Name and Description</th>
</tr>
</thead>
<tbody>
<for each="member" in="ownMethods">
<tr>
<td class="attributes">{!
if (member.isPrivate) output += "&lt;private&gt; ";
if (member.isInner) output += "&lt;inner&gt; ";
if (member.isStatic) output += "&lt;static&gt; ";
!}&nbsp;</td>
<td class="nameDescription">
<div class="fixedFont"><if test="member.isStatic && member.memberOf != '_global_'">{+member.memberOf+}.</if><b>{+new Link().toSymbol(member.alias).withText(member.name.replace(/\^\d+$/, ''))+}</b>{+makeSignature(member.params)+}
</div>
<div class="description">{+resolveLinks(summarize(member.desc))+}</div>
</td>
</tr>
</for>
</tbody>
</table>
</if>
<if test="data.inheritsFrom.length">
<dl class="inheritsList">
{!
var borrowedMembers = data.methods.filter(function($) {return $.memberOf != data.alias});
var contributers = [];
borrowedMembers.map(function($) {if (contributers.indexOf($.memberOf) < 0) contributers.push($.memberOf)});
for (var i = 0, l = contributers.length; i < l; i++) {
output +=
"<dt>Methods borrowed from class "+new Link().toSymbol(contributers[i])+": </dt>"
+
"<dd>" +
borrowedMembers
.filter(
function($) { return $.memberOf == contributers[i] }
)
.sort(makeSortby("name"))
.map(
function($) { return new Link().toSymbol($.alias).withText($.name) }
)
.join(", ")
+
"</dd>";
}
!}
</dl>
</if>
</if>
<!-- ============================== events summary ======================== -->
<if test="data.events.length">
{! var ownEvents = data.events.filter(function($){return $.memberOf == data.alias && !$.isNamespace}).sort(makeSortby("name")); !}
<if test="ownEvents.length">
<table class="summaryTable" cellspacing="0" summary="A summary of the events documented in the class {+data.alias+}.">
<caption>Event Summary</caption>
<thead>
<tr>
<th scope="col">Event Attributes</th>
<th scope="col">Event Name and Description</th>
</tr>
</thead>
<tbody>
<for each="member" in="ownEvents">
<tr>
<td class="attributes">{!
if (member.isPrivate) output += "&lt;private&gt; ";
if (member.isInner) output += "&lt;inner&gt; ";
if (member.isStatic) output += "&lt;static&gt; ";
!}&nbsp;</td>
<td class="nameDescription">
<div class="fixedFont"><if test="member.isStatic && member.memberOf != '_global_'">{+member.memberOf+}.</if><b>{+new Link().toSymbol(member.alias).withText(member.name)+}</b>{+makeSignature(member.params)+}
</div>
<div class="description">{+resolveLinks(summarize(member.desc))+}</div>
</td>
</tr>
</for>
</tbody>
</table>
</if>
<if test="data.inheritsFrom.length">
<dl class="inheritsList">
{!
var borrowedMembers = data.events.filter(function($) {return $.memberOf != data.alias});
var contributers = [];
borrowedMembers.map(function($) {if (contributers.indexOf($.memberOf) < 0) contributers.push($.memberOf)});
for (var i = 0, l = contributers.length; i < l; i++) {
output +=
"<dt>Events borrowed from class "+new Link().toSymbol(contributers[i])+": </dt>"
+
"<dd>" +
borrowedMembers
.filter(
function($) { return $.memberOf == contributers[i] }
)
.sort(makeSortby("name"))
.map(
function($) { return new Link().toSymbol($.alias).withText($.name) }
)
.join(", ")
+
"</dd>";
}
!}
</dl>
</if>
</if>
<!-- ============================== constructor details ==================== -->
<if test="!data.isBuiltin() && (data.isNamespace || data.is('CONSTRUCTOR'))">
<div class="details"><a name="constructor"> </a>
<div class="sectionTitle">
{+classType+}Detail
</div>
<div class="fixedFont">{!
if (data.isPrivate) output += "&lt;private&gt; ";
if (data.isInner) output += "&lt;inner&gt; ";
!}
<b>{+ data.alias +}</b><if test="classType != 'Namespace '">{+ makeSignature(data.params) +}</if>
</div>
<div class="description">
{+resolveLinks(data.desc)+}
<if test="data.author"><br /><i>Author: </i>{+data.author+}.</if>
</div>
<if test="data.example.length">
<for each="example" in="data.example">
<pre class="code">{+example+}</pre>
</for>
</if>
<if test="data.params.length">
<dl class="detailList">
<dt class="heading">Parameters:</dt>
<for each="item" in="data.params">
<dt>
{+((item.type)?""+("<span class=\"light fixedFont\">{"+(new Link().toSymbol(item.type)+"}</span> ")) : "")+} <b>{+item.name+}</b>
<if test="item.isOptional"><i>Optional<if test="item.defaultValue">, Default: {+item.defaultValue+}</if></i></if>
</dt>
<dd>{+resolveLinks(item.desc)+}</dd>
</for>
</dl>
</if>
<if test="data.deprecated">
<dl class="detailList">
<dt class="heading">Deprecated:</dt>
<dt>
{+resolveLinks(data.deprecated)+}
</dt>
</dl>
</if>
<if test="data.since">
<dl class="detailList">
<dt class="heading">Since:</dt>
<dd>{+ data.since +}</dd>
</dl>
</if>
<if test="data.exceptions.length">
<dl class="detailList">
<dt class="heading">Throws:</dt>
<for each="item" in="data.exceptions">
<dt>
{+((item.type)?"<span class=\"light fixedFont\">{"+(new Link().toSymbol(item.type))+"}</span> " : "")+} <b>{+item.name+}</b>
</dt>
<dd>{+resolveLinks(item.desc)+}</dd>
</for>
</dl>
</if>
<if test="data.returns.length">
<dl class="detailList">
<dt class="heading">Returns:</dt>
<for each="item" in="data.returns">
<dd>{+((item.type)?"<span class=\"light fixedFont\">{"+(new Link().toSymbol(item.type))+"}</span> " : "")+}{+resolveLinks(item.desc)+}</dd>
</for>
</dl>
</if>
<if test="data.requires.length">
<dl class="detailList">
<dt class="heading">Requires:</dt>
<for each="item" in="data.requires">
<dd>{+ new Link().toSymbol(item) +}</dd>
</for>
</dl>
</if>
<if test="data.see.length">
<dl class="detailList">
<dt class="heading">See:</dt>
<for each="item" in="data.see">
<dd>{+ new Link().toSymbol(item) +}</dd>
</for>
</dl>
</if>
</div>
</if>
<!-- ============================== field details ========================== -->
<if test="defined(ownProperties) && ownProperties.length">
<div class="sectionTitle">
Field Detail
</div>
<for each="member" in="ownProperties">
<a name="{+Link.symbolNameToLinkName(member)+}"> </a>
<div class="fixedFont">{!
if (member.isPrivate) output += "&lt;private&gt; ";
if (member.isInner) output += "&lt;inner&gt; ";
if (member.isStatic) output += "&lt;static&gt; ";
if (member.isConstant) output += "&lt;constant&gt; ";
!}
<if test="member.type"><span class="light">{{+new Link().toSymbol(member.type)+}}</span></if>
<if test="member.isStatic && member.memberOf != '_global_'"><span class="light">{+member.memberOf+}.</span></if><b>{+member.name+}</b>
</div>
<div class="description">
{+resolveLinks(member.desc)+}
<if test="member.srcFile != data.srcFile">
<br />
<i>Defined in: </i> {+new Link().toSrc(member.srcFile)+}.
</if>
<if test="member.author"><br /><i>Author: </i>{+member.author+}.</if>
</div>
<if test="member.example.length">
<for each="example" in="member.example">
<pre class="code">{+example+}</pre>
</for>
</if>
<if test="member.deprecated">
<dl class="detailList">
<dt class="heading">Deprecated:</dt>
<dt>
{+ resolveLinks(member.deprecated) +}
</dt>
</dl>
</if>
<if test="member.since">
<dl class="detailList">
<dt class="heading">Since:</dt>
<dd>{+ member.since +}</dd>
</dl>
</if>
<if test="member.see.length">
<dl class="detailList">
<dt class="heading">See:</dt>
<for each="item" in="member.see">
<dd>{+ new Link().toSymbol(item) +}</dd>
</for>
</dl>
</if>
<if test="member.defaultValue">
<dl class="detailList">
<dt class="heading">Default Value:</dt>
<dd>
{+resolveLinks(member.defaultValue)+}
</dd>
</dl>
</if>
<if test="!$member_last"><hr /></if>
</for>
</if>
<!-- ============================== method details ========================= -->
<if test="defined(ownMethods) && ownMethods.length">
<div class="sectionTitle">
Method Detail
</div>
<for each="member" in="ownMethods">
<a name="{+Link.symbolNameToLinkName(member)+}"> </a>
<div class="fixedFont">{!
if (member.isPrivate) output += "&lt;private&gt; ";
if (member.isInner) output += "&lt;inner&gt; ";
if (member.isStatic) output += "&lt;static&gt; ";
!}
<if test="member.type"><span class="light">{{+new Link().toSymbol(member.type)+}}</span></if>
<if test="member.isStatic && member.memberOf != '_global_'"><span class="light">{+member.memberOf+}.</span></if><b>{+member.name.replace(/\^\d+$/, '')+}</b>{+makeSignature(member.params)+}
</div>
<div class="description">
{+resolveLinks(member.desc)+}
<if test="member.srcFile != data.srcFile">
<br />
<i>Defined in: </i> {+new Link().toSrc(member.srcFile)+}.
</if>
<if test="member.author"><br /><i>Author: </i>{+member.author+}.</if>
</div>
<if test="member.example.length">
<for each="example" in="member.example">
<pre class="code">{+example+}</pre>
</for>
</if>
<if test="member.params.length">
<dl class="detailList">
<dt class="heading">Parameters:</dt>
<for each="item" in="member.params">
<dt>
{+((item.type)?"<span class=\"light fixedFont\">{"+(new Link().toSymbol(item.type))+"}</span> " : "")+}<b>{+item.name+}</b>
<if test="item.isOptional"><i>Optional<if test="item.defaultValue">, Default: {+item.defaultValue+}</if></i></if>
</dt>
<dd>{+resolveLinks(item.desc)+}</dd>
</for>
</dl>
</if>
<if test="member.deprecated">
<dl class="detailList">
<dt class="heading">Deprecated:</dt>
<dt>
{+ resolveLinks(member.deprecated) +}
</dt>
</dl>
</if>
<if test="member.since">
<dl class="detailList">
<dt class="heading">Since:</dt>
<dd>{+ member.since +}</dd>
</dl>
</dl>
</if>
<if test="member.exceptions.length">
<dl class="detailList">
<dt class="heading">Throws:</dt>
<for each="item" in="member.exceptions">
<dt>
{+((item.type)?"<span class=\"light fixedFont\">{"+(new Link().toSymbol(item.type))+"}</span> " : "")+} <b>{+item.name+}</b>
</dt>
<dd>{+resolveLinks(item.desc)+}</dd>
</for>
</dl>
</if>
<if test="member.returns.length">
<dl class="detailList">
<dt class="heading">Returns:</dt>
<for each="item" in="member.returns">
<dd>{+((item.type)?"<span class=\"light fixedFont\">{"+(new Link().toSymbol(item.type))+"}</span> " : "")+}{+resolveLinks(item.desc)+}</dd>
</for>
</dl>
</if>
<if test="member.requires.length">
<dl class="detailList">
<dt class="heading">Requires:</dt>
<for each="item" in="member.requires">
<dd>{+ resolveLinks(item) +}</dd>
</for>
</dl>
</if>
<if test="member.see.length">
<dl class="detailList">
<dt class="heading">See:</dt>
<for each="item" in="member.see">
<dd>{+ new Link().toSymbol(item) +}</dd>
</for>
</dl>
</if>
<if test="!$member_last"><hr /></if>
</for>
</if>
<!-- ============================== event details ========================= -->
<if test="defined(ownEvents) && ownEvents.length">
<div class="sectionTitle">
Event Detail
</div>
<for each="member" in="ownEvents">
<a name="event:{+Link.symbolNameToLinkName(member)+}"> </a>
<div class="fixedFont">{!
if (member.isPrivate) output += "&lt;private&gt; ";
if (member.isInner) output += "&lt;inner&gt; ";
if (member.isStatic) output += "&lt;static&gt; ";
!}
<if test="member.type"><span class="light">{{+new Link().toSymbol(member.type)+}}</span></if>
<if test="member.isStatic && member.memberOf != '_global_'"><span class="light">{+member.memberOf+}.</span></if><b>{+member.name+}</b>{+makeSignature(member.params)+}
</div>
<div class="description">
{+resolveLinks(member.desc)+}
<if test="member.srcFile != data.srcFile">
<br />
<i>Defined in: </i> {+new Link().toSrc(member.srcFile)+}.
</if>
<if test="member.author"><br /><i>Author: </i>{+member.author+}.</if>
</div>
<if test="member.example.length">
<for each="example" in="member.example">
<pre class="code">{+example+}</pre>
</for>
</if>
<if test="member.params.length">
<dl class="detailList">
<dt class="heading">Parameters:</dt>
<for each="item" in="member.params">
<dt>
{+((item.type)?"<span class=\"light fixedFont\">{"+(new Link().toSymbol(item.type))+"}</span> " : "")+}<b>{+item.name+}</b>
<if test="item.isOptional"><i>Optional<if test="item.defaultValue">, Default: {+item.defaultValue+}</if></i></if>
</dt>
<dd>{+ resolveLinks(item.desc) +}</dd>
</for>
</dl>
</if>
<if test="member.deprecated">
<dl class="detailList">
<dt class="heading">Deprecated:</dt>
<dt>
{+ resolveLinks(member.deprecated) +}
</dt>
</dl>
</if>
<if test="member.since">
<dl class="detailList">
<dt class="heading">Since:</dt>
<dd>{+ member.since +}</dd>
</dl>
</dl>
</if>
<if test="member.exceptions.length">
<dl class="detailList">
<dt class="heading">Throws:</dt>
<for each="item" in="member.exceptions">
<dt>
{+((item.type)?"<span class=\"light fixedFont\">{"+(new Link().toSymbol(item.type))+"}</span> " : "")+} <b>{+item.name+}</b>
</dt>
<dd>{+ resolveLinks(item.desc) +}</dd>
</for>
</dl>
</if>
<if test="member.returns.length">
<dl class="detailList">
<dt class="heading">Returns:</dt>
<for each="item" in="member.returns">
<dd>{+((item.type)?"<span class=\"light fixedFont\">{"+(new Link().toSymbol(item.type))+"}</span> " : "")+}{+resolveLinks(item.desc)+}</dd>
</for>
</dl>
</if>
<if test="member.requires.length">
<dl class="detailList">
<dt class="heading">Requires:</dt>
<for each="item" in="member.requires">
<dd>{+ resolveLinks(item) +}</dd>
</for>
</dl>
</if>
<if test="member.see.length">
<dl class="detailList">
<dt class="heading">See:</dt>
<for each="item" in="member.see">
<dd>{+ new Link().toSymbol(item) +}</dd>
</for>
</dl>
</if>
<if test="!$member_last"><hr /></if>
</for>
</if>
<hr />
</div>
<!-- ============================== footer ================================= -->
<div class="fineprint" style="clear:both">
<if test="JSDOC.opt.D.copyright">&copy;{+JSDOC.opt.D.copyright+}<br /></if>
Documentation generated by <a href="http://code.google.com/p/jsdoc-toolkit/" target="_blank">JsDoc Toolkit</a> {+JSDOC.VERSION+} on {+new Date()+}
</div>
</body>
</html>

View file

@ -1,40 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset={+IO.encoding+}" />
<title>{+JSDOC.opt.D.title+} - Index</title>
<meta name="generator" content="JsDoc Toolkit" />
<style type="text/css">
{+include("static/default.css")+}
</style>
</head>
<body>
<div><strong>{+JSDOC.opt.D.title+}</strong></div>
{+include("static/header.html")+}
<div id="index">
{+publish.classesIndex+}
</div>
<div id="content">
<h1 class="classTitle">Class Index</h1>
<for each="thisClass" in="data">
<div>
<h2>{+(new Link().toSymbol(thisClass.alias))+}</h2>
{+resolveLinks(summarize(thisClass.classDesc))+}
</div>
<hr />
</for>
</div>
<div class="fineprint" style="clear:both">
<if test="JSDOC.opt.D.copyright">&copy;{+JSDOC.opt.D.copyright+}<br /></if>
Documentation generated by <a href="http://code.google.com/p/jsdoc-toolkit/" target="_blankt">JsDoc Toolkit</a> {+JSDOC.VERSION+} on {+new Date()+}
</div>
</body>
</html>

View file

@ -1,201 +0,0 @@
/** Called automatically by JsDoc Toolkit. */
function publish(symbolSet) {
publish.conf = { // trailing slash expected for dirs
ext: ".html",
outDir: JSDOC.opt.d || SYS.pwd+"../out/jsdoc/",
templatesDir: JSDOC.opt.t || SYS.pwd+"../templates/jsdoc/",
symbolsDir: "symbols/",
srcDir: "symbols/src/"
};
// is source output is suppressed, just display the links to the source file
if (JSDOC.opt.s && defined(Link) && Link.prototype._makeSrcLink) {
Link.prototype._makeSrcLink = function(srcFilePath) {
return "&lt;"+srcFilePath+"&gt;";
}
}
// create the folders and subfolders to hold the output
IO.mkPath((publish.conf.outDir+"symbols/src").split("/"));
// used to allow Link to check the details of things being linked to
Link.symbolSet = symbolSet;
// create the required templates
try {
var classTemplate = new JSDOC.JsPlate(publish.conf.templatesDir+"class.tmpl");
var classesTemplate = new JSDOC.JsPlate(publish.conf.templatesDir+"allclasses.tmpl");
}
catch(e) {
print("Couldn't create the required templates: "+e);
quit();
}
// some ustility filters
function hasNoParent($) {return ($.memberOf == "")}
function isaFile($) {return ($.is("FILE"))}
function isaClass($) {return ($.is("CONSTRUCTOR") || $.isNamespace)}
// get an array version of the symbolset, useful for filtering
var symbols = symbolSet.toArray();
// create the hilited source code files
var files = JSDOC.opt.srcFiles;
for (var i = 0, l = files.length; i < l; i++) {
var file = files[i];
var srcDir = publish.conf.outDir + "symbols/src/";
makeSrcFile(file, srcDir);
}
// get a list of all the classes in the symbolset
var classes = symbols.filter(isaClass).sort(makeSortby("alias"));
// create a filemap in which outfiles must be to be named uniquely, ignoring case
if (JSDOC.opt.u) {
var filemapCounts = {};
Link.filemap = {};
for (var i = 0, l = classes.length; i < l; i++) {
var lcAlias = classes[i].alias.toLowerCase();
if (!filemapCounts[lcAlias]) filemapCounts[lcAlias] = 1;
else filemapCounts[lcAlias]++;
Link.filemap[classes[i].alias] =
(filemapCounts[lcAlias] > 1)?
lcAlias+"_"+filemapCounts[lcAlias] : lcAlias;
}
}
// create a class index, displayed in the left-hand column of every class page
Link.base = "../";
publish.classesIndex = classesTemplate.process(classes); // kept in memory
// create each of the class pages
for (var i = 0, l = classes.length; i < l; i++) {
var symbol = classes[i];
symbol.events = symbol.getEvents(); // 1 order matters
symbol.methods = symbol.getMethods(); // 2
Link.currentSymbol= symbol;
var output = "";
output = classTemplate.process(symbol);
IO.saveFile(publish.conf.outDir+"symbols/", ((JSDOC.opt.u)? Link.filemap[symbol.alias] : symbol.alias) + publish.conf.ext, output);
}
// regenerate the index with different relative links, used in the index pages
Link.base = "";
publish.classesIndex = classesTemplate.process(classes);
// create the class index page
try {
var classesindexTemplate = new JSDOC.JsPlate(publish.conf.templatesDir+"index.tmpl");
}
catch(e) { print(e.message); quit(); }
var classesIndex = classesindexTemplate.process(classes);
IO.saveFile(publish.conf.outDir, "index"+publish.conf.ext, classesIndex);
classesindexTemplate = classesIndex = classes = null;
// create the file index page
try {
var fileindexTemplate = new JSDOC.JsPlate(publish.conf.templatesDir+"allfiles.tmpl");
}
catch(e) { print(e.message); quit(); }
var documentedFiles = symbols.filter(isaFile); // files that have file-level docs
var allFiles = []; // not all files have file-level docs, but we need to list every one
for (var i = 0; i < files.length; i++) {
allFiles.push(new JSDOC.Symbol(files[i], [], "FILE", new JSDOC.DocComment("/** */")));
}
for (var i = 0; i < documentedFiles.length; i++) {
var offset = files.indexOf(documentedFiles[i].alias);
allFiles[offset] = documentedFiles[i];
}
allFiles = allFiles.sort(makeSortby("name"));
// output the file index page
var filesIndex = fileindexTemplate.process(allFiles);
IO.saveFile(publish.conf.outDir, "files"+publish.conf.ext, filesIndex);
fileindexTemplate = filesIndex = files = null;
}
/** Just the first sentence (up to a full stop). Should not break on dotted variable names. */
function summarize(desc) {
if (typeof desc != "undefined")
return desc.match(/([\w\W]+?\.)[^a-z0-9_$]/i)? RegExp.$1 : desc;
}
/** Make a symbol sorter by some attribute. */
function makeSortby(attribute) {
return function(a, b) {
if (a[attribute] != undefined && b[attribute] != undefined) {
a = a[attribute].toLowerCase();
b = b[attribute].toLowerCase();
if (a < b) return -1;
if (a > b) return 1;
return 0;
}
}
}
/** Pull in the contents of an external file at the given path. */
function include(path) {
var path = publish.conf.templatesDir+path;
return IO.readFile(path);
}
/** Turn a raw source file into a code-hilited page in the docs. */
function makeSrcFile(path, srcDir, name) {
if (JSDOC.opt.s) return;
if (!name) {
name = path.replace(/\.\.?[\\\/]/g, "").replace(/[\\\/]/g, "_");
name = name.replace(/\:/g, "_");
}
var src = {path: path, name:name, charset: IO.encoding, hilited: ""};
if (defined(JSDOC.PluginManager)) {
JSDOC.PluginManager.run("onPublishSrc", src);
}
if (src.hilited) {
IO.saveFile(srcDir, name+publish.conf.ext, src.hilited);
}
}
/** Build output for displaying function parameters. */
function makeSignature(params) {
if (!params) return "()";
var signature = "("
+
params.filter(
function($) {
return $.name.indexOf(".") == -1; // don't show config params in signature
}
).map(
function($) {
return $.name;
}
).join(", ")
+
")";
return signature;
}
/** Find symbol {@link ...} strings in text and turn into html links */
function resolveLinks(str, from) {
str = str.replace(/\{@link ([^} ]+) ?\}/gi,
function(match, symbolName) {
return new Link().toSymbol(symbolName);
}
);
return str;
}

View file

@ -1,162 +0,0 @@
/* default.css */
body
{
font: 12px "Lucida Grande", Tahoma, Arial, Helvetica, sans-serif;
width: 800px;
}
.header
{
clear: both;
background-color: #ccc;
padding: 8px;
}
h1
{
font-size: 150%;
font-weight: bold;
padding: 0;
margin: 1em 0 0 .3em;
}
hr
{
border: none 0;
border-top: 1px solid #7F8FB1;
height: 1px;
}
pre.code
{
display: block;
padding: 8px;
border: 1px dashed #ccc;
}
#index
{
margin-top: 24px;
float: left;
width: 160px;
position: absolute;
left: 8px;
background-color: #F3F3F3;
padding: 8px;
}
#content
{
margin-left: 190px;
width: 600px;
}
.classList
{
list-style-type: none;
padding: 0;
margin: 0 0 0 8px;
font-family: arial, sans-serif;
font-size: 1em;
overflow: auto;
}
.classList li
{
padding: 0;
margin: 0 0 8px 0;
}
.summaryTable { width: 100%; }
h1.classTitle
{
font-size:170%;
line-height:130%;
}
h2 { font-size: 110%; }
caption, div.sectionTitle
{
background-color: #7F8FB1;
color: #fff;
font-size:130%;
text-align: left;
padding: 2px 6px 2px 6px;
border: 1px #7F8FB1 solid;
}
div.sectionTitle { margin-bottom: 8px; }
.summaryTable thead { display: none; }
.summaryTable td
{
vertical-align: top;
padding: 4px;
border-bottom: 1px #7F8FB1 solid;
border-right: 1px #7F8FB1 solid;
}
/*col#summaryAttributes {}*/
.summaryTable td.attributes
{
border-left: 1px #7F8FB1 solid;
width: 140px;
text-align: right;
}
td.attributes, .fixedFont
{
line-height: 15px;
color: #002EBE;
font-family: "Courier New",Courier,monospace;
font-size: 13px;
}
.summaryTable td.nameDescription
{
text-align: left;
font-size: 13px;
line-height: 15px;
}
.summaryTable td.nameDescription, .description
{
line-height: 15px;
padding: 4px;
padding-left: 4px;
}
.summaryTable { margin-bottom: 8px; }
ul.inheritsList
{
list-style: square;
margin-left: 20px;
padding-left: 0;
}
.detailList {
margin-left: 20px;
line-height: 15px;
}
.detailList dt { margin-left: 20px; }
.detailList .heading
{
font-weight: bold;
padding-bottom: 6px;
margin-left: 0;
}
.light, td.attributes, .light a:link, .light a:visited
{
color: #777;
font-style: italic;
}
.fineprint
{
text-align: right;
font-size: 10px;
}

View file

@ -1,2 +0,0 @@
<!--div id="header">
</div-->

View file

@ -1,19 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>Generated Javascript Documentation</title>
</head>
<frameset cols="20%,80%">
<frame src="allclasses-frame.html" name="packageFrame" />
<frame src="splash.html" name="classFrame" />
<noframes>
<body>
<p>
This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client.
</p>
</body>
</noframes>
</frameset>
</html>

View file

@ -1,35 +0,0 @@
<symbol alias="{+data.alias+}">
<name>{+data.name+}</name>
<memberOf>{+data.memberOf+}</memberOf>
<isStatic>{+data.isStatic+}</isStatic>
<isa>{+data.isa+}</isa>
<desc>{+data.desc+}</desc>
<classDesc>{+data.classDesc+}</classDesc>
<methods><for each="method" in="data.methods">
<method>
<name>{+method.name+}</name>
<memberOf>{+method.memberOf+}</memberOf>
<isStatic>{+method.isStatic+}</isStatic>
<desc>{+method.desc+}</desc>
<params><for each="param" in="method.params">
<param>
<type>{+param.type+}</type>
<name>{+param.name+}</name>
<desc>{+param.desc+}</desc>
<defaultValue>{+param.defaultValue+}</defaultValue>
</param></for>
</params>
</method></for>
</methods>
<properties><for each="property" in="data.properties">
<property>
<name>{+property.name+}</name>
<memberOf>{+property.memberOf+}</memberOf>
<isStatic>{+property.isStatic+}</isStatic>
<desc>{+property.desc+}</desc>
<type>{+property.type+}</type>
</property></for>
</properties>
</symbol>

View file

@ -1,5 +0,0 @@
require('JSON/json2.js');
global.node = {
sanitizeHtml: require('sanitize-html')
};

52
claustra/add-claustra.js Executable file
View file

@ -0,0 +1,52 @@
#!/usr/bin/env node
const fs = require('fs');
const readline = require('readline');
const name = process.argv[2];
if (!name) {
getName();
} else {
createClaustra(name);
}
function getName(interface = getInterface()) {
interface.question('Please enter the name of the new claustra: ', name => {
if (!name) return getName(interface);
interface.close();
createClaustra(name);
});
}
function createClaustra(name) {
const firstLetter = name.substr(0, 1).toUpperCase();
const title = firstLetter + name.substr(1);
const claustraDir = `claustra/${name.toLowerCase()}/${title}`;
if (fs.existsSync(claustraDir)) {
return console.error(`ERROR: Claustra at ${claustraDir} already exists; aborting`);
}
fs.mkdirSync(claustraDir, { recursive: true });
fs.mkdirSync(`${claustraDir}/../Claustra`, { recursive: true });
fs.writeFileSync(`${claustraDir}/${title}.properties`, '#sites = collection(Site)');
fs.writeFileSync(`${claustraDir}/../Claustra/Claustra.properties`, `${name} = mountpoint(${title})`);
fs.writeFileSync(`${claustraDir}/${title}.js`, [
`${title}.prototype.main_action = function () {`,
' //res.debug(this.sites.count());',
'}'
].join('\n'));
console.info(`Created new claustra at ${claustraDir}`);
}
function getInterface() {
return readline.createInterface({
input: process.stdin,
output: process.stdout
});
}

View file

@ -0,0 +1 @@
construction = mountpoint(Construction)

View file

@ -0,0 +1,41 @@
<% #main %>
window.onload = function() {
const tape = document.createElement('div');
tape.setAttribute('title', '⚠️ <strong>Warning!</strong> This is a test installation. Any content may be deleted at any time.');
tape.dataset.ukTooltip = "{ pos: 'right' }";
tape.style.position = 'fixed';
tape.style.top = '0';
tape.style.bottom = '0';
tape.style.left = '0';
tape.style.width = '15px';
tape.style.height = '100%';
tape.style.background = 'url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAMAAAC5zwKfAAAApVBMVEUAAAD/8AH/8AAAAAH/8RAPDw//8wEAAAT/9AHv5AH88AA0MQFCQADr3wGjnAHt4QCCfAGwqgGglwEJCgEsKgGmnwK2rwA7NAFHRQAgHwGrpQHe0gE/OwFLSQExLwD26wB2cgDZzQ+XkgGKhAEsKgByagAVFwCIhBAiIwAsJgJ5dAAZGwAUEwGRigAfGwHd1QEcHBwzMQ9IRA8fIQDFvwHGwQAUEw/eI/5xAAAFCklEQVRYhY2Zi3baSAyG50JsPNg4YEi5G0JpQ9ssmyab93+0lTRjINgjMSXNOXH4+KX5R5Id9e/DPevz7aPu9VxPWkmmHtQdq5o9lc5obWILrjgNr3IsAq1VVuWjWmvtOCBc16Yc/5WB8JWPSngPAOMLrrukHq8e5JCtnT3VzjXvM51fQNO6eB2oe4DrhYPsoAZ2JcX0aFmgxWhVtV6UHMeE5LpimMOvM0BLS31bZI7R1lwCfasqZYFErDb/1UKoRDX164Qi4nOYVrNRdiUjynPleEDx8EBr81FmRB78QjZcKRkIfhkVBOOSCPuf1MMcw2VCxs9C/znKjxQx+A/PEx6pOBDWbFEnfOrwk0xSTl+8w1RUIV6uMF5emyeC/y68KBD8R/srSHQO9OXV1Vs7gcCrBh81nje+IEB669ejuhIYU1jNFqgPzxQn0emi8Z8ABD+jPk4eKkzAf4Tjcuj3t9QmTkOvo/YkG+dXrE4gqc+fHGdlHaQnxfPG3vBugGRPyJ8Tjhtdh/092juA1XrE1r8QNdS/ad7mdeRwgP5zYMC4RhII+1FZJSiE8/HtI/NNkS2qxtX7CSVICFmtoV96Vgzof14MB6GCRIEpvtZU/4TsQYfD+te9zsAU9aP/eDNTSwJenkrAUP/OQwCnD/yXdmzwVyD4Lx+5RAwYkNni2LUdt0Cof6V8fLEeUP3rxl0DN6MsEXEmgf6x8hExQEhwtQL/cTzaDczgfhPRdq3QwvxSC7XPfxrUv6i4CxB4GK/Y3rSvf6JC8p9reg7HK7/0o7hCqH90PrkUgnrw33er4hvcAMF/YR5iQ4bzMZ2Q/YQcfs7k+kf7RfNfDOZ/TpPD22Xe7Q7Wp8+A/1JG2gX4kcn6YNXoPy7WcBY/VW0M0+C0736mGG4qHhf+f1M94X6BAs4wXhboNdofP1WPNpdpIOiXKfXfWA08x2zn2x0ApRE1KZ8nntal0Z55ys4fiz6EzJ4QuJQNvwvBhvYyf1zqXhxowvCK/mMM41lo95dDURsG6OVh/bOx8nwRCa9qu+xrAQhbUu+FehW2Q032SzxQAhD9J/Hwamr/7E/Uz3ngef4TVqp+/8J4o0D0Ovlv0Zr/uiN+3+68mbtzSLf7qO/5yMgLkyv5GfynqWVGNsUf7my4EeOl6oj+075kRRQSk61/IVT6Nj8UPePvmSNAh/cfDvYjOh+c9cF+oP/8HSGehAhQuyz4j8mh14j+CxsSDRnncTi/Ngr0xQq+gb79CSMNTakFDBegH7H91996Un3ZnvrX9fkW6D+rqX989hD4ftg5c30P0lKI0KR+fhHPG0kE/93cXbZyaM7+u6Pgvz8u/UB0aejtTXHO1787Chb4r3Wv0AYmbkz1QDrC6L9d3/e3rk3xP8fnJa8D7viGgk/+O3U0y1uFsL8TVhhpRx74r98c4CgQ7/el+c+Hq+bbZee09hWI/quE8xv622EJDZtG5AiQ/qH/JB4KpPrXHLa4QpcN/fMDfsayKda/OukeJj3Ql8ZynMdhzZyJn/j7UOh2sGegI4H0/FRo52H9+YX+iyyvEIPG56fivIYyof75RxjxkHXz/JRbYeKw4L+kbb+vQNj9wj//Y4nEe9kuaQCNDi8UMvkv5SuWv3v/53ByTbDRkOETsf4JFZAEYv0znmXitsHnp2z6zllE/0kPJwFYRp8f3Kwf28KPz8yC2SYb//286y8gbz93ffHPH73e/6MFSUugyaE3AAAAAElFTkSuQmCC)';
const margin = parseInt(document.body.style.paddingLeft, 10) || 0;
document.body.appendChild(tape);
document.body.style.paddingLeft = margin + 15;
// TODO: What exactly is this code needed for? 🤔
const html = document.createElement('div');
html.classList.add('uk-modal');
html.id = 'uk-modal';
html.innerHTML = '<div class="uk-modal-dialog"><div class="uk-modal-header"></div><div class="uk-modal-footer"></div></div></div>';
document.body.appendChild(html);
const modal = UIkit.modal('#uk-modal');
document.addEventListener('show-modal', function() {
document.style.paddingRight = '';
modal.show();
});
document.addEventListener('hide-modal', function() {
modal.hide();
});
};

View file

@ -0,0 +1,3 @@
Construction.prototype.main = function () {
this.renderSkin('$Construction#main');
};

View file

@ -0,0 +1,16 @@
# The Construction Claustra
The Antville Construction Claustra just adds a simple graphical ornament to each Antville page warning that the data of this installation might not be persisting.
This comes in handy e.g. for testing your Antville installation.
## Installation
Enable the Claustra in your applications `app.properties` file:
```properties
# Multiple claustra can be enabled comma-separated
claustra = construction
```
Thats it there is no further configuration or setup necessary.

View file

@ -0,0 +1 @@
proxy = mountpoint(Proxy)

View file

@ -0,0 +1,68 @@
// The Antville Project
// http://code.google.com/p/antville
//
// Copyright 20012014 by the Workers of Antville.
//
// Licensed under the Apache License, Version 2.0 (the ``License'');
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an ``AS IS'' BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Defines the Antville proxy Feature.
*/
Proxy.prototype.main_action = function () {
const url = req.data.url;
if (!url) return res.status = 400;
const callback = req.data.callback;
const http = new helma.Http();
http.setBinaryMode(true);
http.setHeader('Accept', '*/*');
http.setHeader('Accept-Encoding', 'gzip');
http.setHeader('Cache-Control', 'no-cache');
http.setHeader('Pragma', 'no-cache');
http.setHeader('User-Agent', req.data.http_browser);
const data = http.getUrl(url);
if (!data.content) {
throw Error('Failed to retrieve URL.');
}
if (callback) {
res.contentType = 'application/javascript';
let content = new java.lang.String(data.content, 'utf-8');
if (!data.type.startsWith('text/')) {
content = new java.lang.String(content.enbase64());
}
// The String() call prevents stack overflow
res.write(JSON.pad({ content: String(content) }, callback));
} else {
res.contentType = data.type;
if (data.type.startsWith('text/')) {
res.write(java.lang.String(data.content, 'utf-8'));
} else {
res.writeBinary(data.content);
}
}
};
Proxy.prototype.getPermission = function() {
return User.require(User.REGULAR);
};

34
claustra/proxy/README.md Normal file
View file

@ -0,0 +1,34 @@
# The Proxy Claustra
The Antville Proxy Claustra allows to retrieve URLs via HTTP from outside Antvilles domain, e.g. for fetching site content with JavaScript.
It is required for using the Formica bookmarklet available from the settings of each Antville site.
## Installation
Enable the Claustra in your applications `app.properties` file:
```properties
# Multiple claustra can be enabled comma-separated
claustra = proxy
```
## Usage
To use the proxy you must be logged in to the corresponding Antville installation.
It is available under the path `/claustra/proxy`, e.g. under the URL `http://localhost:8080/claustra/proxy`.
Use the `url` query parameter to retrieve a URL via the Proxy Claustra:
```sh
curl -G --data-urlencode 'url=https://postman-echo.com/time/now' 'http://localhost:8080/claustra/proxy'
Fri, 24 Apr 2020 19:00:43 GMT
```
The proxy also supports JSONP requests simply by appending the `callback` query parameter:
```sh
curl -G --data-urlencode 'url=https://postman-echo.com/time/now' 'http://localhost:8080/claustra/proxy?callback=evaluate'
evaluate({"content":"Fri, 24 Apr 2020 19:00:43 GMT"});
```

View file

@ -46,13 +46,46 @@
</div>
</fieldset>
<fieldset class='uk-margin-top'>
<legend><% gettext 'Registration &amp; Login' %></legend>
<div class='uk-form-row'>
<label class='uk-form-label' for='loginScope'>
<% gettext 'Required Account Status' %>
</label>
<div class='uk-form-controls'>
<% root.select loginScope %>
</div>
</div>
<div class='uk-form-row'>
<label class='uk-form-label' for='termsStory'>
<% gettext 'Story about Terms and Conditions' %>
</label>
<div class='uk-form-controls'>
<% root.input termsStory class=uk-width-1-4 pattern="[a-zA-Z0-9]+/[0-9]+" placeholder=<% gettext "e.g. {0}" www/12345 %> %>
<a href='<% if <% root.termsStory %> is null then <% site.href stories %> else <% story <% root.termsStory %> url %> %>'>
<i class='uk-icon-link'></i>
</a>
</div>
</div>
<div class='uk-form-row'>
<label class='uk-form-label' for='privacyStory'>
<% gettext 'Story about Data Privacy Statement' %>
</label>
<div class='uk-form-controls'>
<% root.input privacyStory class=uk-width-1-4 pattern="[a-zA-Z0-9]+/[0-9]+" placeholder=<% gettext "e.g. {0}" www/12345 %> %>
<a href='<% if <% root.privacyStory %> is null then <% site.href stories %> else <% story <% root.privacyStory %> url %> %>'>
<i class='uk-icon-link'></i>
</a>
</div>
</div>
</fieldset>
<fieldset class='uk-margin-top' x-data='{ creationScope: "<% root.creationScope %>" }'>
<legend><% gettext 'Site Creation' %></legend>
<div class='uk-form-row'>
<label class='uk-form-label' for='creationScope'>
<% gettext 'Required Account Status' %>
</label>
<div class='uk-form-controls'>
<% root.select creationScope %>
<% root.select creationScope x-model='creationScope' %>
</div>
</div>
<div class='uk-form-row'>
@ -60,7 +93,7 @@
<% gettext 'Probation Period' %>
</label>
<div class='uk-form-controls'>
<% root.input probationPeriod class=uk-width-1-6 type=number min=0 %> <% gettext days %>
<% root.input probationPeriod class=uk-width-1-6 type=number min=0 :disabled="creationScope !== 'regular'" %> <% gettext days %>
</div>
</div>
<div class='uk-form-row'>
@ -68,18 +101,18 @@
<% gettext Interval %>
</label>
<div class='uk-form-controls'>
<% root.input creationDelay class=uk-width-1-6 type=number min=0 %> <% gettext days %>
<% root.input creationDelay class=uk-width-1-6 type=number min=0 :disabled="creationScope !== 'regular'" %> <% gettext days %>
</div>
</div>
</fieldset>
<fieldset class='uk-margin-top'>
<fieldset class='uk-margin-top' x-data='{ phaseOutMode: "<% root.phaseOutMode %>" }'>
<legend><% gettext 'Site Phase-Out' %></legend>
<div class='uk-form-row'>
<label class='uk-form-label' for='phaseOutMode'>
<% gettext Mode %>
</label>
<div class='uk-form-controls'>
<% root.select phaseOutMode %>
<% root.select phaseOutMode x-model='phaseOutMode' %>
</div>
</div>
<div class='uk-form-row'>
@ -87,7 +120,7 @@
<% gettext 'Notification Period' %>
</label>
<div class='uk-form-controls'>
<% root.input phaseOutNotificationPeriod class=uk-width-1-6 type=number min=1 %> <% gettext days %>
<% root.input phaseOutNotificationPeriod class=uk-width-1-6 type=number min=1 :disabled="phaseOutMode === 'disabled'" %> <% gettext days %>
</div>
</div>
<div class='uk-form-row'>
@ -95,7 +128,7 @@
<% gettext 'Grace Period' %>
</label>
<div class='uk-form-controls'>
<% root.input phaseOutGracePeriod class=uk-width-1-6 type=number min=1 %> <% gettext days %>
<% root.input phaseOutGracePeriod class=uk-width-1-6 type=number min=1 :disabled="phaseOutMode === 'disabled'" %> <% gettext days %>
</div>
</div>
</fieldset>
@ -106,18 +139,6 @@
<a href='..' class="uk-button uk-button-link"><% gettext Cancel %></a>
</div>
</form>
<script type="text/javascript">
$("#creationScope").on('change', function() {
var disabled = $(this).val() === "regular" ? false : true;
$("#probationPeriod").attr("disabled", disabled);
$("#creationDelay").attr("disabled", disabled);
}).change();
$("#phaseOutMode").on('change', function() {
var disabled = $(this).val() !== "disabled" ? false : true;
$("#phaseOutNotificationPeriod").attr("disabled", disabled);
$("#phaseOutGracePeriod").attr("disabled", disabled);
}).change();
</script>
<% #activities %>
<h1><% response.title %></h1>
@ -174,7 +195,7 @@
</div>
<div>
<% gettext '{0} sites sorted by {1} in {2} order.'
<% admin.dropdown name="display" <% markgettext all %> <% markgettext blocked %> <% markgettext trusted %> <% markgettext open %> <% markgettext restricted %> <% markgettext public %> <% markgettext closed %> <% markgettext deleted %> %>
<% admin.dropdown name="display" <% markgettext all %> <% markgettext deleted %> <% markgettext blocked %> <% markgettext trusted %> <% markgettext open %> <% markgettext restricted %> <% markgettext public %> <% markgettext closed %> %>
<% admin.dropdown name="sorting" <% markgettext modified %> <% markgettext created %> <% markgettext name %> %>
<% admin.dropdown name="order" <% markgettext descending %> <% markgettext ascending %> %>
%>
@ -220,7 +241,7 @@
</div>
<div>
<% gettext '{0} accounts sorted by {1} in {2} order.'
<% admin.dropdown name="display" <% markgettext all %> <% markgettext blocked %> <% markgettext trusted %> <% markgettext privileged %> %>
<% admin.dropdown name="display" <% markgettext all %> <% markgettext deleted %> <% markgettext blocked %> <% markgettext trusted %> <% markgettext privileged %> %>
<% admin.dropdown name="sorting" <% markgettext Registration %> <% markgettext 'last login' %> <% markgettext Name %> %>
<% admin.dropdown name="order" <% markgettext descending %> <% markgettext ascending %> %>
%>
@ -263,8 +284,10 @@
<table class='uk-table uk-table-striped uk-table-hover uk-table-condensed'>
<thead>
<tr>
<th><% gettext Date %></th>
<th><% gettext Method %></th>
<th><% gettext Reference %></th>
<th><% gettext Name %></th>
<th><% gettext Account %></th>
<th></th>
</tr>
@ -336,19 +359,37 @@
<td>
<% item.notes prefix="<span title='" suffix="' data-uk-tooltip><i class='uk-icon-info-circle uk-text-muted'></i></span>" %>
</td>
<td class='uk-text-right uk-text-nowrap;'>
<td class='uk-text-right uk-text-nowrap'>
<% item.link delete "<i class='uk-icon-trash-o'></i>" %>
<% admin.link block "<i class='uk-icon-ban'></i>" <% item.self %> %>
<% item.link edit "<i class='uk-icon-pencil'></i>" %>
</td>
</tr>
<% #timelineItem %>
<tr>
<td><% param.icon %></td>
<td><% param.site %></td>
<td class='uk-text-truncate' title='<% param.date | format short %>' data-uk-tooltip="{pos: 'top-left'}">
<% param.date | format text %>
</td>
<td class='av-overflow'>
<a href='<% param.href %>'><% param.reference %></a>
</td>
</tr>
<% #job %>
<tr>
<td><% item.date | format short %></td>
<td><% gettext <% item.method %> | titleize %></td>
<td><a href='<% item.target.href %>'><% item.target.name %></a></td>
<td><% item.name %></td>
<td><% item.user.name %></td>
<td class='uk-text-right'><% admin.link <% item.target.id prefix='job?delete=' %> "<i class='uk-icon-trash-o'></i>" %></td>
<td class='uk-text-right'>
<a href='<% admin.href job %>?name=<% item.name %>&amp;<% item.target.type %>&amp;id=<% item.target.id %>'>
<i class='uk-icon-trash-o'></i>
</a>
</td>
</tr>
<% #blockedSite %>
@ -358,7 +399,7 @@
<div class='uk-badge uk-badge-success'><% gettext Trusted %></div>
<% #deletedSite %>
<i class='uk-icon-ban'></i>
<div class='uk-badge'><% gettext Deleted %></div>
<% #closedSite %>
<i class='uk-icon-lock'></i>
@ -369,6 +410,9 @@
<% #openSite %>
<i class='uk-icon-globe'></i>
<% #deletedUser %>
<div class='uk-badge uk-badge-warning'><% gettext Deleted %></div>
<% #blockedUser %>
<div class='uk-badge uk-badge-danger'><% gettext Blocked %></div>

View file

@ -23,7 +23,6 @@ markgettext('export');
markgettext('import');
markgettext('remove');
Admin.SITEREMOVALGRACEPERIOD = 14; // days
Admin.MAXBATCHSIZE = 50;
/**
@ -34,8 +33,9 @@ Admin.MAXBATCHSIZE = 50;
* @constructor
*/
Admin.Job = function(target, method, user) {
var file;
user || (user = session.user);
if (!user) user = session.user;
var file, date;
this.__defineGetter__('target', function() {
return target;
@ -53,6 +53,10 @@ Admin.Job = function(target, method, user) {
return file.getName();
});
this.__defineGetter__('date', function() {
return date;
});
this.remove = function(isCareless) {
// isCareless is `true` after a site is completely removed, to prevent NullPointer exception
if (!isCareless) target.job = null;
@ -69,6 +73,7 @@ Admin.Job = function(target, method, user) {
target = global[data.type].getById(data.id);
method = data.method;
user = User.getById(data.user);
date = new Date(file.lastModified());
}
} else {
throw Error('Insufficient arguments');
@ -102,6 +107,13 @@ Admin.getPhaseOutModes = defineConstants(Admin, markgettext('Disabled'), markget
*/
Admin.getCreationScopes = defineConstants(Admin, markgettext('Privileged'), markgettext('Trusted'), markgettext('Regular'));
/**
* @function
* @returns {String[]}
* @see defineConstants
*/
Admin.getLoginScopes = defineConstants(Admin, markgettext('Privileged'), markgettext('Trusted'), markgettext('Regular'), markgettext('None'));
/**
* Convenience method for easily queueing jobs.
* @param {HopObject} target
@ -125,16 +137,17 @@ Admin.queue.dir.exists() || Admin.queue.dir.mkdirs();
*
*/
Admin.dequeue = function() {
var jobs = Admin.queue.dir.list();
var jobs = Admin.getJobs('desc');
var max = Math.min(jobs.length, Admin.MAXBATCHSIZE);
for (let i=0; i<max; i+=1) {
let job = new Admin.Job(jobs[i]);
let job = new Admin.Job(jobs[i].name);
if (job.target) {
try {
app.log('Processing queued job ' + (i + 1) + ' of ' + max);
switch (job.method) {
case 'remove':
Site.remove.call(job.target);
if (job.target.constructor === Site) Site.remove.call(job.target);
if (job.target.constructor === User) User.remove.call(job.target);
break;
case 'import':
Importer.run(job.target, job.user);
@ -153,19 +166,28 @@ Admin.dequeue = function() {
return;
}
/**
*
*/
Admin.getJobs = function(sort) {
if (!sort) sort = 'asc';
return Admin.queue.dir.listFiles().sort((a, b) => {
return (a.lastModified() - b.lastModified()) * (sort === 'asc' ? -1 : 1);
});
};
Admin.purgeAccounts = function() {
var now = Date.now();
root.admin.deletedUsers.forEach(function() {
if (this.job || this.deleted) return; // already gone
this.job = Admin.queue(this, 'remove', this);
});
};
Admin.purgeSites = function() {
var now = new Date;
root.admin.deletedSites.forEach(function() {
if (now - this.deleted > Date.ONEDAY * Admin.SITEREMOVALGRACEPERIOD) {
if (this.job) {
return; // Site is already scheduled for deletion
}
this.job = Admin.queue(this, 'remove', this.modifier);
}
if (this.job) return;
this.job = Admin.queue(this, 'remove', this.modifier);
});
var notificationPeriod = root.phaseOutNotificationPeriod * Date.ONEDAY;
@ -177,7 +199,7 @@ Admin.purgeSites = function() {
return;
}
var age = now - (this.stories.size() > 0 ?
this.stories.get(0).modified : this.created);
this.stories.get(0).modified : this.modified);
if (age - notificationPeriod > 0) {
if (!this.notified) {
var site = res.handlers.site = this;
@ -189,7 +211,7 @@ Admin.purgeSites = function() {
});
this.notified = now;
} else if (now - this.notified > gracePeriod) {
this.mode = Site.DELETED;
this.status = Site.DELETED;
this.deleted = now;
this.notified = null;
}
@ -277,13 +299,14 @@ Admin.commitEntries = function() {
}
// Only log unique combinations of context, ip and referrer
referrer = String(referrer);
referrer = Admin.resolveUrl(referrer);
var key = item.context._prototype + '-' + item.context._id + ':' +
item.ip + ':' + referrer;
if (history.indexOf(key) > -1) {
continue;
}
history.push(key);
item.referrer = referrer;
// Exclude requests coming from the same site
if (item.site) {
@ -370,6 +393,26 @@ Admin.updateDomains = function() {
return;
}
Admin.resolveUrl = function(url) {
var http = new helma.Http();
http.setMethod('HEAD');
http.setFollowRedirects(false);
var response;
var location = url;
while (location) {
try {
response = http.getUrl(location);
location = response.location;
} catch (error) {
location = null;
}
};
return String(response ? response.url : url);
};
/**
* The Admin prototype is mounted at root and provides actions needed
* for system administration. A user needs the User.PRIVILEGED permission
@ -501,7 +544,7 @@ Admin.prototype.activity_action = function () {
}
Admin.prototype.jobs_action = function() {
var files = Admin.queue.dir.listFiles();
var files = Admin.getJobs();
res.data.count = files.length;
res.data.list = renderList(files, this.renderItem);
res.data.title = gettext('Jobs');
@ -512,9 +555,8 @@ Admin.prototype.jobs_action = function() {
};
Admin.prototype.job_action = function () {
var site = Site.getById(req.data.delete);
if (site && site.job) {
var job = new Admin.Job(site.job);
if (req.data.name) {
const job = new Admin.Job(req.data.name);
job.remove();
}
return res.redirect(req.data.http_referer);
@ -568,13 +610,16 @@ Admin.prototype.update = function(data) {
root.map({
creationScope: data.creationScope,
creationDelay: data.creationDelay,
replyTo: data.replyTo,
loginScope: data.loginScope,
notificationScope: data.notificationScope,
phaseOutGracePeriod: data.phaseOutGracePeriod,
phaseOutMode: data.phaseOutMode,
phaseOutNotificationPeriod: data.phaseOutNotificationPeriod,
privacyStory: data.privacyStory,
probationPeriod: data.probationPeriod,
quota: data.quota
quota: data.quota,
replyTo: data.replyTo,
termsStory: data.termsStory
});
return;
}
@ -588,12 +633,12 @@ Admin.prototype.filterSites = function(data) {
var displays = {
1: "status = 'blocked'",
2: "status = 'trusted'",
3: "mode = 'open'",
4: "mode = 'restricted'",
5: "mode = 'public'",
6: "mode = 'closed'",
7: "mode = 'deleted'"
2: "status = 'deleted'",
3: "status = 'trusted'",
4: "mode = 'open'",
5: "mode = 'restricted'",
6: "mode = 'public'",
7: "mode = 'closed'"
};
var sortings = {
@ -630,9 +675,10 @@ Admin.prototype.filterUsers = function(data) {
data || (data = {});
var displays = {
1: "status = 'blocked'",
2: "status = 'trusted'",
3: "status = 'privileged'"
1: "status = 'deleted'",
2: "status = 'blocked'",
3: "status = 'trusted'",
4: "status = 'privileged'"
};
var sortings = {
@ -685,7 +731,9 @@ Admin.prototype.renderItem = function(item) {
return;
}
Admin.prototype.renderActivity = function (item) {
Admin.prototype.renderActivity = function (item, skin) {
if (!skin) skin = '$Admin#activity';
var param = {
item: item,
icon: getIcon(item),
@ -694,11 +742,13 @@ Admin.prototype.renderActivity = function (item) {
user: item.creator ? item.creator.name : item.name,
href: item.href(item.constructor === User ? 'edit' : ''),
linkCount: getLinkCount(item),
alert: getAlert(item)
//site: item.site && item.site.name
alert: getAlert(item),
site: (item.parent && item.parent.site || item.parent || item.site || {}).name
};
param.warn = param.linkCount > 2 ? true : false;
Admin.prototype.renderSkin('$Admin#activity', param);
Admin.prototype.renderSkin(skin, param);
function getReference(item) {
switch (item.constructor) {
@ -754,7 +804,7 @@ Admin.prototype.renderActivity = function (item) {
function getAlert(item) {
switch (item.constructor) {
case User:
return item.status !== User.BLOCKED && item.created - item.modified < 1;
return item.status !== User.BLOCKED && item.status !== User.DELETED && item.created - item.modified < 1;
case Site:
return item.status !== Site.DELETED && item.created - item.modified < 1;
}
@ -782,7 +832,7 @@ Admin.prototype.log = function(context, action) {
*/
Admin.prototype.href_macro = function (param, action, id) {
res.write(this.href.apply(this, arguments));
res.write(this.href.call(this, action, id));
return;
};
@ -849,7 +899,7 @@ Admin.prototype.link_macro = function (param, action, text, target) {
switch (action) {
case 'block':
var user = target.creator || target;
if (user.status !== User.PRIVILEGED && user.status !== User.BLOCKED) {
if (user.status !== User.PRIVILEGED && user.status !== User.BLOCKED && user.status !== User.DELETED) {
var url = user.href('block');
return renderLink.call(global, param, url, text || String.EMPTY, this);
}
@ -857,7 +907,7 @@ Admin.prototype.link_macro = function (param, action, text, target) {
case 'delete':
var site = target.constructor === Site ? target : target.site;
if (site && site.getPermission(action) && site.mode !== Site.DELETED) {
if (site && site.getPermission(action) && site.status !== Site.DELETED) {
var url = site.href('delete') + '?safemode';
return renderLink.call(global, param, url, text || String.EMPTY, this);
}

View file

@ -28,9 +28,14 @@ restrictedSites = collection(Site)
restrictedSites.filter = mode = 'restricted' and status <> 'blocked'
deletedSites = collection(Site)
deletedSites.filter = mode = 'deleted'
deletedSites.filter = status = 'deleted'
deletedSites.order = modified desc
users = collection(User)
users.accessName = name
users.order = created desc
deletedUsers = collection(User)
deletedUsers.filter = status = 'deleted'
deletedUsers.order = modified desc

View file

@ -15,28 +15,11 @@
</tr>
<% #delete %>
<div class='uk-alert uk-alert-warning uk-hidden av-alert-confirm'>
<input type="checkbox" id="mode" name="mode" value="user" />
<label for="mode"><% gettext "Erase all comments of user {0}" <% comment.creator %> %></label>
<div id="confirmation">
<input type="checkbox" id="confirm" name="confirm" value="1" />
<label for="confirm"><% ngettext "Yes, really erase {0} comment" "Yes, really erase {0} comments" <% comment.related.size %> %></label>
</div>
<div class='uk-alert uk-alert-warning av-alert-confirm' x-data='{ confirm: false, confirmed: false }' hidden :hidden='false'>
<input type="checkbox" id="mode" name="mode" value="user" @click='confirm = document.querySelector("button").disabled = !confirm'/>
<label for="mode"><% gettext "Erase all comments of user {0}" <% comment.creator %> %></label>
<div id="confirmation" x-show='confirm'>
<input type="checkbox" id="confirm" name="confirm" value="1" x-model='confirmed' @click='confirmed = !confirmed; document.querySelector("button").disabled = !confirmed'/>
<label for="confirm"><% ngettext "Yes, really erase {0} comment" "Yes, really erase {0} comments" <% comment.related.size %> %></label>
</div>
</div>
<script type="text/javascript">
$('#confirmation').hide();
$('#mode').on('click', function() {
if ($(this).prop('checked')) {
$('#confirm').attr('checked', false);
$('#confirmation').show();
$('button').attr('disabled', true);
} else {
$('#confirmation').hide();
$('button').attr('disabled', false);
}
});
$('#confirm').on('click', function() {
$('button').attr('disabled', !$(this).prop('checked'));
});
$('.av-alert-confirm').removeClass('uk-hidden');
</script>

View file

@ -23,6 +23,8 @@ markgettext('Comment');
markgettext('comment');
markgettext('a comment // accusative');
Comment.HTML_WHITELIST = Packages.org.jsoup.safety.Whitelist.relaxed();
/**
* @see defineConstants
*/
@ -192,11 +194,8 @@ Comment.prototype.filter_action = function () {
* @param {Object} data
*/
Comment.prototype.update = function(data) {
if (!User.require(User.TRUSTED) && !Membership.require(Membership.CONTRIBUTOR)) {
var spec = {
allowedTags: node.sanitizeHtml.defaults.allowedTags.concat(['img'])
};
data.text = data.text ? node.sanitizeHtml(data.text, spec) : String.EMPTY;
if (data.text && !User.require(User.TRUSTED) && !Membership.require(Membership.CONTRIBUTOR)) {
data.text = sanitizeHtml(data.text, Comment.HTML_WHITELIST);
}
if (!data.text) {
@ -214,14 +213,19 @@ Comment.prototype.update = function(data) {
this.status = Comment.PENDING;
} else if (delta > 50) {
this.modified = new Date;
if (this.story.status !== Story.CLOSED) {
this.site.modified = this.modified;
}
// We need persistence for adding the callback
this.isTransient() && this.persist();
if (this.isTransient()) this.persist();
res.handlers.site.callback(this);
// Notification is sent in Story.comment_action()
}
this.clearCache();
this.modifier = session.user;
return;
@ -235,7 +239,7 @@ Comment.prototype.getConfirmText = function() {
if (this.status === Comment.DELETED && size > 1) {
return gettext('You are about to delete a comment thread consisting of {0} postings.', size);
}
return gettext('You are about to delete a comment by user {0}.', this.creator.name);
return gettext('You are about to delete a comment by {0}.', this.creator.name);
};
Comment.prototype.getConfirmExtra = function () {

View file

@ -1,15 +1,15 @@
<% #listItem %>
<tr>
<td class='uk-text-right'><% file.requests %></td>
<td class='uk-text-muted'><i class='uk-icon-file<% file.contentType generic prefix=- %>-o' title='<% file.contentType %>' data-uk-tooltip></i></td>
<td class='uk-width-1-2 av-overflow'>
<span title='<% file.description %>' data-uk-tooltip="{pos: 'top-left'}"><% file.name | file.link %></span>
</td>
<!-- td class='uk-text-nowrap'><% //file.contentLength %></td -->
<td class='uk-text-nowrap'><% file.contentLength %></td>
<td><% file.creator %></td>
<td class='uk-text-nowrap' title='<% file.created short %>' data-uk-tooltip="{pos: 'top-left'}">
<% file.modified text %>
</td>
<td class='uk-text-muted'><i class='uk-icon-file<% file.contentType generic prefix=- %>-o' title='<% file.contentType %>' data-uk-tooltip></i></td>
<td class='uk-text-right uk-text-nowrap'>
<a href='javascript:' class='av-clipboard-copy' data-text='<% gettext 'Press CTRL & C to copy to clipboard.' %>' data-value="<% file.macro %>"><i class='uk-icon-clipboard'></i></a>
<% file.link delete "<i class='uk-icon-trash-o'></i>" %>
@ -24,7 +24,7 @@
</h1>
<div class='uk-article-meta'><% file.skin $HopObject#meta %></div>
<% site.skin $Site#noscript %>
<form class='uk-margin-top uk-form uk-form-stacked' method="post" action="<% response.action %>" enctype="multipart/form-data">
<form class='uk-margin-top uk-form uk-form-stacked' method="post" action="<% response.action %>" enctype="multipart/form-data" x-data='{ name: "<% file.name %>" }'>
<div class='uk-form-row'>
<label class='uk-form-label' for='file'>
<% gettext File %>
@ -33,13 +33,13 @@
<% file.upload file class='uk-width-1-2' %>
</div>
</div>
<div class='uk-form-row uk-hidden av-row-name'>
<div class='uk-form-row av-name-row' hidden :hidden='false'>
<label class='uk-form-label' for='name'>
<% gettext Name %>
<i class='uk-icon-info-circle uk-text-muted' title='<% gettext "If you do not specify a name Antville will create one based on the filename." %>' data-uk-tooltip='{pos: "right"}'></i>
</label>
<div class='uk-form-controls'>
<% file.input name class='uk-width-1-2' %>
<% file.input name class='uk-width-1-2' :disabled='!!name' %>
</div>
</div>
<div class='uk-form-row'>
@ -64,11 +64,3 @@
<a href='<% site.files.href %>' class="uk-button uk-button-link"><% gettext Cancel %></a>
</div>
</form>
<script type="text/javascript">
$(function() {
if ('<% file.name %>') {
$('#name').attr('disabled', true);
}
$('.av-row-name').removeClass('uk-hidden');
});
</script>

View file

@ -65,11 +65,8 @@ File.remove = function() {
* @param {String} name
*/
File.getName = function(name) {
if (name) {
//return name.replace(/[^\w\d\s._-]/g, String.EMPTY);
return String(name).trim().replace(/[\/\\:;?+\[\]{}|#"`<>^]/g, String.EMPTY);
}
return null;
// TODO: Maybe return a hash if name is undefined?
return name ? String(name).replace(/[^\w\d\s,._-]/g, String.EMPTY) : null;
}
File.getGenericType = function (contentType) {
@ -273,20 +270,16 @@ File.prototype.update = function(data) {
}
if (mime.contentLength > 0) {
this.origin = origin;
var mimeName = mime.normalizeFilename(mime.name);
this.contentLength = mime.contentLength;
this.contentType = mime.contentType;
this.setOrigin(origin);
if (!this.name) {
var name = File.getName(data.name) || mimeName.split('.')[0];
this.name = this.site.files.getAccessName(name);
}
if (!data.description && origin) {
data.description = gettext('Source: {0}', origin);
}
// Make the file persistent before proceeding with writing
// it to disk (also see Helma bug #607)
this.isTransient() && this.persist();
@ -331,6 +324,19 @@ File.prototype.contentType_macro = function (param, mode) {
return res.write(this.contentType);
}
File.prototype.description_macro = function(param) {
if (this.description) {
res.write(this.description);
} else if (param['default']) {
res.write(param['default']);
} else if (this.origin) {
var text = this.origin.replace(new RegExp('^.+:///?(?:www\.)?([^/]+).*$'), '$1');
var link = html.linkAsString({href: this.origin}, text);
res.write(gettext('Source: {0}', link));
}
return;
};
/**
*
*/
@ -347,6 +353,10 @@ File.prototype.getUrl = function() {
return site.getStaticUrl('files/' + this.fileName);
}
File.prototype.setOrigin = function(origin) {
if (/(?:https?|ftp)/i.test(origin)) this.origin = origin;
};
/**
* @returns {String}
*/

View file

@ -10,12 +10,12 @@
<thead>
<tr>
<th class='uk-text-right'><i class='uk-icon-download'></i></th>
<th></th>
<th><% gettext Name %></th>
<!-- th><% gettext Size %></th -->
<th><% gettext Size %></th>
<th><% gettext Account %></th>
<th><% gettext Modified %></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>

View file

@ -31,38 +31,20 @@
<noscript>
<input type="file" id="<% param.name %>" name="<% param.name %>">
</noscript>
<div class="av-upload uk-hidden">
<input type="file">
<div class="av-upload" hidden :hidden='false'>
<input type="file" x-ref='file' :name='"<% param.name %>"' @change='$refs.text.value = $event.currentTarget.value'>
<div class="uk-width-1-1 av-upload-controls">
<input class='uk-width-1-2' type="text" value="<% param.value %>">
<button class='uk-button' id="<% param.name %>_control" name="<% param.name %>_control" type="button">
<% gettext "Browse" suffix=… %>
<input class='uk-width-1-2' type="text" value="<% param.value %>" x-ref='text' :name='"<% param.name %>_origin"' @blur='$refs.file.value = ""'>
<button class='uk-button' id="<% param.name %>_control" name="<% param.name %>_control" type="button" @click='$refs.file.click()'>
<% gettext "Select" suffix=… %>
</button>
</div>
</div>
<script>
$('noscript').remove();
$('.av-upload').removeClass('uk-hidden');
$('.av-upload input[type="file"]')
.attr('id', '<% param.name %>')
.attr('name', '<% param.name %>')
.on('change', function (event) {
$('#<% param.name %>_origin').val($(this).val());
});
$('.av-upload input[type="text"]')
.attr('id', '<% param.name %>_origin')
.attr('name', '<% param.name %>_origin')
.on('blur', function (event) {
$('#<% param.name %>').val('');
});
$('.av-upload button').on('click', function (event) {
$('#<% param.name %>').click();
});
</script>
<% #listItemFlag %>
<td rowspan="2" width="10" align="center" valign="top" nowrap="nowrap"
class="listItemFlag"><% param.text %></td>
class="listItemFlag"><% param.text %></td>
<td rowspan="2" width="5" nowrap="nowrap"></td>
<% #mailFooter %>

File diff suppressed because one or more lines are too long

53
code/Global/Captcha.js Normal file
View file

@ -0,0 +1,53 @@
// The Antville Project
// http://code.google.com/p/antville
//
// Copyright 20012014 by the Workers of Antville.
//
// Licensed under the Apache License, Version 2.0 (the ``License'');
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an ``AS IS'' BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Defines the Antville Captcha prototype.
* @see https://hcaptcha.com
*/
Captcha = {};
Captcha.verify = function (data) {
const secret = getProperty('captcha.secret');
if (session.user || !secret) return;
const response = req.postParams['h-captcha-response'];
const http = new helma.Http();
http.setMethod('POST');
http.setContent({
response: response,
secret: secret
});
const request = http.getUrl('https://hcaptcha.com/siteverify');
const validation = JSON.parse(request.content);
if (!validation.success) {
throw Error(gettext('Do Androids dream of electric sheep?'));
}
};
Captcha.render = function(context, skin) {
const secret = getProperty('captcha.secret');
if (session.user || !context || !secret) { return; }
if (!skin) { skin = '$Members#captcha'; }
return context.renderSkinAsString(skin);
};

View file

@ -19,32 +19,413 @@
* @fileOverview Defines the Exporter namespace.
*/
/**
* The Exporter namespace provides methods for exporting a site.
* @namespace
*/
var Exporter = {}
app.addRepository('lib/gson-2.8.6.jar');
/**
* Exports a site with the specified users content
* The created XML file will be added to the sites file collection.
* @param {Site} site The site to export.
* @param {User} user The user whose content will be exported.
*/
Exporter.run = function(site, user) {
try {
var file;
if (site.export_id && (file = File.getById(site.export_id))) {
File.remove.call(file);
global.Exporter = (function() {
const gson = new JavaImporter(
Packages.com.google.gson,
Packages.com.google.gson.stream
);
const getJsonWriter = (dir, fname) => {
const file = new java.io.File(dir, fname);
const stream = new java.io.FileOutputStream(file);
const writer = new java.io.OutputStreamWriter(stream, 'utf-8');
const jsonWriter = new gson.JsonWriter(writer);
jsonWriter.beginArray();
return {
push(data) {
jsonWriter.jsonValue(JSON.stringify(data));
return this;
},
close() {
jsonWriter.endArray();
jsonWriter.flush();
jsonWriter.close();
writer.close();
stream.close();
return this;
}
};
};
const addMetadata = (object, Prototype) => {
object.metadata = {};
const sql = new Sql();
sql.retrieve("select name, value, type from metadata where parent_type = '$0' and parent_id = $1 order by lower(name)", Prototype.name, object.id);
sql.traverse(function() {
object.metadata[this.name] = global[this.type](this.value).valueOf();
});
return object;
};
const addImage = function(type, writer) {
app.log('Exporting ' + type + ' image #' + this.id);
const image = Image.getById(this.id);
if (image) {
this.href = image.href();
addMetadata(this, Image);
writer.push(this);
} else {
app.logger.warn('Could not export Image #' + this.id + '; might be a cache problem');
}
};
const addAssets = (site, zip) => {
const dir = site.getStaticFile();
if (dir.exists()) zip.add(dir, 'static');
};
/**
* The Exporter namespace provides methods for exporting a site.
* @namespace
*/
const Exporter = {}
/**
* Exports a site with the specified users content
* The created XML file will be added to the sites file collection.
* @param {Site} site The site to export.
* @param {User} user The user whose content will be exported.
*/
Exporter.run = function(target, user) {
switch (target.constructor) {
case Site:
Exporter.saveSite(target, user);
break;
case User:
Exporter.saveAccount(target);
break;
}
};
Exporter.saveSite = function(site, user) {
const sql = new Sql();
const zip = new helma.Zip();
const dirName = app.appsProperties['static'] + '/export';
const fileName = 'antville-site-' + java.util.UUID.randomUUID() + '.zip';
const dir = new java.io.File(dirName);
const file = new java.io.File(dir, fileName);
if (!dir.exists()) dir.mkdirs();
if (site.export) {
const archive = new java.io.File(dirName, site.export.split('/').pop());
if (archive.exists()) archive['delete']();
}
var rssUrl = site.href('rss.xml');
var baseDir = site.getStaticFile();
var member = site.members.get(user.name);
try {
const tempDir = new java.io.File(java.nio.file.Files.createTempDirectory(site.name));
const skinWriter = getJsonWriter(tempDir, 'skins.json');
let writer = getJsonWriter(tempDir, 'index.json');
var xml = [];
sql.retrieve('select s.*, c.name as creator_name, m.name as modifier_name from site s, account c, account m where s.id = $0 and s.creator_id = c.id and s.modifier_id = m.id order by lower(s.name)', site._id);
var add = function(s) {
sql.traverse(function() {
app.log('Exporting site #' + this.id + ' (' + this.name + ')');
const site = Site.getById(this.id);
this.href = site.href();
addAssets(site, zip);
addMetadata(this, Site);
writer.push(this);
const skinsSql = new Sql();
sql.retrieve('select * from skin where site_id = $0', this.id);
sql.traverse(function() {
app.log('Exporting skin #' + this.id);
skinWriter.push(this);
});
});
writer.close();
skinWriter.close();
writer = getJsonWriter(tempDir, 'members.json');
sql.retrieve('select m.*, c.name as creator_name, mod.name as modifier_name from site s, membership m, account c, account mod where s.id = $0 and s.id = m.site_id and m.creator_id = c.id and m.modifier_id = mod.id order by lower(m.name)', site._id);
sql.traverse(function() {
app.log('Exporting membership #' + this.creator_id);
writer.push(this);
});
writer.close();
const storyWriter = getJsonWriter(tempDir, 'stories.json');
const commentWriter = getJsonWriter(tempDir, 'comments.json');
sql.retrieve('select c.*, crt.name as creator_name, m.name as modifier_name from content c, account crt, account m where c.site_id = $0 and c.creator_id = crt.id and c.modifier_id = m.id order by created desc', site._id);
sql.traverse(function() {
app.log('Exporting story #' + this.id);
const content = Story.getById(this.id);
this.href = content.href();
addMetadata(this, Story);
this.rendered = content.format_filter(this.metadata.text, {}, 'markdown');
if (this.prototype === 'Story') {
storyWriter.push(this);
} else {
commentWriter.push(this);
}
});
storyWriter.close();
commentWriter.close();
writer = getJsonWriter(tempDir, 'files.json');
sql.retrieve('select f.*, c.name as creator_name, m.name as modifier_name from file f, account c, account m where f.site_id = $0 and f.creator_id = c.id and f.modifier_id = m.id order by created desc', site._id);
sql.traverse(function() {
app.log('Exporting file #' + this.id);
const file = File.getById(this.id);
this.href = file.href();
addMetadata(this, File);
writer.push(this);
});
writer.close();
writer = getJsonWriter(tempDir, 'images.json');
sql.retrieve("select i.*, c.name as creator_name, m.name as modifier_name from image i, account c, account m where i.parent_type = 'Site' and i.parent_id = $0 and i.creator_id = c.id and i.modifier_id = m.id order by created desc", site._id);
sql.traverse(function() {
addImage.call(this, 'site', writer);
});
sql.retrieve("select i.*, c.name as creator_name, m.name as modifier_name from image i, layout l, account c, account m where i.parent_type = 'Layout' and i.parent_id = l.id and l.site_id = $0 and i.creator_id = c.id and i.modifier_id = m.id order by created desc", site._id);
sql.traverse(function() {
addImage.call(this, 'layout', writer);
});
writer.close();
writer = getJsonWriter(tempDir, 'polls.json');
sql.retrieve('select p.*, c.name as creator_name, m.name as modifier_name from poll p, account c, account m where p.site_id = $0 and p.creator_id = c.id and p.modifier_id = m.id order by created desc', site._id);
sql.traverse(function() {
app.log('Exporting poll #' + this.id);
const poll = Poll.getById(this.id);
this.href = poll.href();
this.choices = poll.list().map(choice => {
return {
id: choice._id,
title: choice.title,
votes: choice.size()
};
});
addMetadata(this, Poll);
writer.push(this);
});
writer.close();
writer = getJsonWriter(tempDir, 'tags.json');
sql.retrieve('select t.name, h.* from tag t, tag_hub h where t.id = h.tag_id order by t.name');
sql.traverse(function() {
app.log('Exporting tag #' + this.id);
writer.push(this);
});
writer.close();
const xml = Exporter.getSiteXml(site);
zip.addData(xml, 'export.xml');
zip.add(tempDir);
zip.save(file);
site.export = app.appsProperties.staticMountpoint + '/export/' + fileName;
site.job = null;
} catch (ex) {
app.log(ex.rhinoException);
}
return;
};
Exporter.saveAccount = account => {
const zip = new helma.Zip();
const sql = new Sql();
const dirName = app.appsProperties['static'] + '/export';
const fileName = 'antville-account-' + java.util.UUID.randomUUID() + '.zip';
const dir = new java.io.File(dirName);
const file = new java.io.File(dir, fileName);
if (!dir.exists()) dir.mkdirs();
if (account.export) {
const archive = new java.io.File(dirName, account.export.split('/').pop());
if (archive.exists()) archive['delete']();
}
const tempDir = new java.io.File(java.nio.file.Files.createTempDirectory(account.name));
let writer = getJsonWriter(tempDir, 'index.json');
sql.retrieve("select * from account where id = $0", account._id);
// Cannot really include other accounts with the same e-mail address because we do not verify e-mail addresses
//sql.retrieve("select * from account where email = '$0' order by lower(name)", account.email);
sql.traverse(function() {
app.log('Exporting account #' + this.id + ' (' + this.name + ')');
addMetadata(this, User);
writer.push(this);
});
writer.close();
writer = getJsonWriter(tempDir, 'sites.json');
sql.retrieve("select s.*, m.role, c.name as creator_name, mod.name as modifier_name from site s, membership m, account c, account mod where m.creator_id = $0 and m.site_id = s.id and s.creator_id = c.id and s.modifier_id = mod.id order by lower(s.name)", account._id);
sql.traverse(function() {
app.log('Exporting site #' + this.id + ' (' + this.name + ')');
const site = Site.getById(this.id);
this.href = site.href();
if (this.role === Membership.OWNER) addMetadata(this, Site);
writer.push(this);
});
writer.close();
writer = getJsonWriter(tempDir, 'skins.json');
sql.retrieve('select s.*, m.name as modifier_name from skin s, account m where s.creator_id = $0 and s.modifier_id = m.id', account._id);
sql.traverse(function() {
app.log('Exporting skin #' + this.id);
writer.push(this);
});
writer.close();
writer = getJsonWriter(tempDir, 'memberships.json');
sql.retrieve('select m.*, mod.name as modifier_name from site s, membership m, account mod where m.creator_id = $0 and s.id = m.site_id and m.modifier_id = mod.id order by lower(m.name)', account._id);
sql.traverse(function() {
app.log('Exporting membership #' + this.id);
this.creator_name = account.name;
writer.push(this);
});
writer.close();
writer = getJsonWriter(tempDir, 'stories.json');
const commentWriter = getJsonWriter(tempDir, 'comments.json');
sql.retrieve('select c.*, m.name as modifier_name from content c, account m where creator_id = $0 and c.modifier_id = m.id order by c.created desc', account._id);
sql.traverse(function() {
app.log('Exporting story #' + this.id);
const content = Story.getById(this.id);
this.href = content.href();
this.creator_name = account.name;
addMetadata(this, Story);
this.rendered = content.format_filter(this.metadata.text, {}, 'markdown');
if (this.prototype === 'Story') {
writer.push(this);
} else {
commentWriter.push(this);
}
});
commentWriter.close();
writer.close()
writer = getJsonWriter(tempDir, 'files.json');
sql.retrieve('select f.*, m.name as modifier_name from file f, account m where f.creator_id = $0 and f.modifier_id = m.id order by f.created desc', account._id);
sql.traverse(function() {
app.log('Exporting file #' + this.id);
const file = File.getById(this.id);
const asset = file.getFile();
if (asset.exists()) zip.add(asset, file.site.name + '/files');
this.href = file.href();
this.creator_name = account.name;
addMetadata(this, File);
writer.push(this);
});
writer.close()
writer = getJsonWriter(tempDir, 'images.json');
sql.retrieve('select i.*, m.name as modifier_name from image i, account m where i.creator_id = $0 and i.modifier_id = m.id order by i.created desc', account._id);
sql.traverse(function() {
app.log('Exporting image #' + this.id);
const image = Image.getById(this.id);
if (image) {
try {
const asset = image.getFile();
const path = this.parent_type === 'Layout' ? image.parent.site.name + '/layout' : image.parent.name + '/images';
if (asset.exists()) zip.add(asset, path);
} catch (ex) {
console.warn('Could not export image #' + this.id);
console.warn(ex.rhinoException);
}
this.href = image.href();
this.creator_name = account.name;
addMetadata(this, Image);
writer.push(this);
} else {
app.logger.warn('Could not export Image #' + this.id + '; might be a cache problem');
}
});
writer.close()
writer = getJsonWriter(tempDir, 'polls.json');
sql.retrieve('select p.*, m.name as modifier_name from poll p, account m where p.creator_id = $0 and p.modifier_id = m.id order by p.created desc', account._id);
sql.traverse(function() {
app.log('Exporting poll #' + this.id);
const poll = Poll.getById(this.id);
this.href = poll.href();
this.creator_name = account.name;
this.choices = poll.list().map(choice => {
return {
id: choice._id,
title: choice.title,
votes: choice.size()
};
});
const vote = poll.votes.get(account.name);
if (vote) this.vote = vote.choice._id;
addMetadata(this, Poll);
writer.push(this);
});
writer.close();
zip.add(tempDir);
zip.save(file);
account.export = app.appsProperties.staticMountpoint + '/export/' + fileName;
account.job = null;
return zip;
};
Exporter.getSiteXml = site => {
const rssUrl = site.href('rss.xml');
const xml = [];
const add = function(s) {
return xml.push(s);
};
@ -65,7 +446,8 @@ Exporter.run = function(site, user) {
// Currently, blogger.com does not accept other generators
//add('<generator version="' + Root.VERSION + '" uri="' + root.href() + '">Antville</generator>');
add('<generator version="7.00" uri="http://www.blogger.com">Blogger</generator>');
member.stories.forEach(function() {
site.stories.forEach(function() {
add('<entry>');
add('<id>tag:blogger.com,1999:blog-' + site._id + '.post-' + this._id + '</id>');
add('<published>' + this.created.format(Date.ISOFORMAT) + '</published>');
@ -76,28 +458,15 @@ Exporter.run = function(site, user) {
add('<category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/blogger/2008/kind#post"/>');
add('<author>');
add('<name>' + this.creator.name + '</name>');
this.creator.url && add('<uri>' + this.creator.url + '</uri>');
if (this.creator.url) add('<uri>' + this.creator.url + '</uri>');
add('<email>' + this.creator.email + '</email>');
add('</author>');
add('</entry>');
});
add('</feed>');
var name = site.name + '-export.xml';
var content = java.lang.String(xml.join(String.EMPTY)).getBytes('utf-8');
return java.lang.String(xml.join(String.EMPTY)).getBytes('utf-8');
};
var data = {
file: new Packages.helma.util.MimePart(name, content, 'application/rss+xml'),
file_origin: site.href('export')
};
var file = File.add(data, site, user);
site.export_id = file._id;
} catch (ex) {
app.log(ex.rhinoException);
}
// Reset the sites export status
site.job = null;
return;
}
return Exporter;
})();

View file

@ -21,9 +21,10 @@
String.ELLIPSIS = '…';
app.addRepository(app.dir + '/../lib/jdom-1.0.jar');
app.addRepository(app.dir + '/../lib/jsoup-1.13.1.jar');
app.addRepository(app.dir + '/../lib/lesscss-1.7.0.1.1.jar');
app.addRepository(app.dir + '/../lib/rome-1.0.jar');
app.addRepository(app.dir + '/../lib/jdom.jar');
app.addRepository(app.dir + '/../lib/itunes-0.4.jar');
app.addRepository('modules/core/Global.js');
app.addRepository('modules/core/HopObject.js');
@ -50,6 +51,7 @@ app.addRepository('modules/jala/code/Utilities.js');
fname.endsWith('.js') && app.addRepository(app.dir + '/../i18n/' + fname);
}
})();
// I18n.js needs to be added *after* the message files or the translations get lost
app.addRepository('modules/jala/code/I18n.js');
@ -207,7 +209,20 @@ var html = new helma.Html();
* An instance of the LESS parser.
* @type less.Parser
*/
var lessParser = new less.Parser();
var lessParser = {
parse: function(lessCode, callback) {
var less = new Packages.org.lesscss.LessCompiler();
try {
callback(null, {
toCSS: function() {
return less.compile(lessCode);
}
});
} catch (error) {
callback(error);
}
}
};
/**
* A collection of Java classes and namespaces required for parsing and generating RSS.
@ -215,16 +230,16 @@ var lessParser = new less.Parser();
*/
var rome = new JavaImporter(
Packages.com.sun.syndication.io,
Packages.com.sun.syndication.feed.synd,
Packages.com.sun.syndication.feed.module.itunes,
Packages.com.sun.syndication.feed.module.itunes.types
Packages.com.sun.syndication.feed.synd
);
var sanitizeHtml = Packages.org.jsoup.Jsoup.clean;
/**
* A simple and hackish implementation of the console instance of some browsers.
* @namespace
*/
var console = function (type) {
var console = function(type) {
/**
* Convenience method for bridging log output from the server to the client.
* @methodOf console
@ -233,15 +248,26 @@ var console = function (type) {
return function(text /*, text, … */) {
var now = formatDate(new Date, 'yyyy/MM/dd HH:mm:ss');
var argString = Array.prototype.join.call(arguments, String.SPACE);
var shellColors = {
debug: '\u001B[34m',
error: '\u001B[35m',
debug: '\u001B[0m',
error: '\u001B[0;31m',
fatal: '\u001B[1;31m',
info: '\u001B[0m',
log: '\u001B[0m',
warn: '\u001B[31m'
warn: '\u001B[0;33m'
};
writeln(shellColors[type] + '[' + now + '] [' + type.toUpperCase() + '] [console] ' + argString + '\u001B[0m');
var output = [
shellColors[type],
'[', now, '] ',
'[', type === 'log' ? 'INFO' : type.toUpperCase(), '] ',
'[console] ',
argString,
'\u001B[0m'
];
writeln(output.join(''));
if (typeof res !== 'undefined') {
res.debug('<script>console.' + type + '("%c%s", "font-style: italic;", ' +
@ -322,9 +348,10 @@ function scheduler() {
Admin.invokeCallbacks();
Admin.updateDomains();
Admin.updateHealth();
Admin.purgeAccounts();
Admin.purgeSites();
return app.properties.schedulerInterval;
}
};
/**
* The nightly scheduler.
@ -470,7 +497,7 @@ function story_macro(param, id, mode) {
res.write(story.href());
break;
case 'link':
html.link({href: story.href()}, story.getTitle());
html.link({href: story.href()}, param.text || story.getTitle());
break;
default:
var skin = param.skin ? 'Story#' + param.skin : '$Story#embed';
@ -581,7 +608,7 @@ function image_macro(param, id, mode) {
break;
case 'thumbnail':
case 'popup':
var url = image.getUrl();
var url = param.link || image.getUrl();
html.openTag('a', {href: url});
// FIXME: Bloody popups belong to compatibility layer
if (mode === 'popup') {
@ -593,7 +620,8 @@ function image_macro(param, id, mode) {
case 'box':
// Default Images do not provide the renderSkin() method
if (image.renderSkin) {
image.renderSkin(param.skin || '$Image#embed');
if (!param.link) param.link = image.getUrl();
image.renderSkin(param.skin || '$Image#embed', param);
}
break;
default:
@ -758,13 +786,10 @@ function list_macro(param, id, limit) {
* @example <% value foo %> Renders the value of res.meta.value.foo
*/
function value_macro(param, name, value) {
if (!name) {
return;
}
if (!name) return;
if (!res.meta.values) res.meta.values = {};
name = name.toLowerCase();
if (!value) {
return res.meta.values[name];
}
if (!value) return res.meta.values[name];
res.meta.values[name] = value;
return;
}
@ -881,7 +906,21 @@ function age_filter(value, param) {
if (!value || value.constructor !== Date) {
return value;
}
return value.getAge()
return value.getAge();
}
/**
* Helma macro filter wrapping the {@link Date#getExpiry} method.
* @see Date#getExpiry
* @param {Date} value The original date.
* @param {Object} param The default Helma macro parameter object.
* @returns {String} The resulting expiry string of the original date.
*/
function expiry_filter(value, param) {
if (!value || value.constructor !== Date) {
return value;
}
return value.getExpiry();
}
/**
@ -908,7 +947,7 @@ function link_filter(text, param, url) {
* @see formatDate
* @param {Object} value The original value.
* @param {Object} param The default Helma macro parameter object.
* @param {String} pattern A formatting pattern suitable for the formatting method.
* @param {String} pattern A formatting pattern suitable for the formatting fmethod.
* @param {String} [type] Deprecated.
* @returns {String} The formatted string.
*/
@ -1060,15 +1099,35 @@ function formatNumber(number, pattern) {
* @returns {String} The formatted date string.
*/
function formatDate(date, format) {
if (!date) {
return null;
}
if (!date) return null;
var pattern;
var site = res.handlers.site;
var locale = site ? site.getLocale() : null;
var timezone = site ? site.getTimeZone() : null;
const getExpiry = diff => {
let text;
if (diff < Date.ONEMINUTE) {
text = gettext('soon');
} else if (diff < Date.ONEHOUR) {
text = ngettext('in {0} minute', 'in {0} minutes', Math.round(diff / Date.ONEMINUTE));
} else if (diff < Date.ONEDAY) {
text = ngettext('in {0} hour', 'in {0} hours', Math.round(diff / Date.ONEHOUR));
} else if (diff < 2 * Date.ONEDAY) {
text = gettext('tomorrow');
} else if (diff < 7 * Date.ONEDAY) {
text = ngettext('in {0} day', 'in {0} days', Math.round(diff / Date.ONEDAY));
} else if (diff < 30 * Date.ONEDAY) {
text = ngettext('in {0} week', 'in {0} weeks', Math.round(diff / 7 / Date.ONEDAY));
} else if (diff < 365 * Date.ONEDAY) {
text = ngettext('in {0} month', 'in {0} months', Math.round(diff / 30 / Date.ONEDAY));
} else {
text = ngettext('in {0} year', 'in {0} years', Math.round(diff / 365 / Date.ONEDAY));
}
return text;
};
switch (format) {
case null:
case undefined:
@ -1096,31 +1155,34 @@ function formatDate(date, format) {
break;
case 'text':
var text,
now = new Date,
diff = now - date;
var text;
var now = new Date;
var diff = now - date;
if (diff < 0) {
// FIXME: Do something similar for future dates
text = formatDate(date);
text = getExpiry(-diff);
} else if (diff < Date.ONEMINUTE) {
text = gettext('right now');
} else if (diff < Date.ONEHOUR) {
text = ngettext('{0} minute ago', '{0} minutes ago', parseInt(diff / Date.ONEMINUTE, 10));
text = ngettext('{0} minute ago', '{0} minutes ago', Math.round(diff / Date.ONEMINUTE));
} else if (diff < Date.ONEDAY) {
text = ngettext('{0} hour ago', '{0} hours ago', parseInt(diff / Date.ONEHOUR, 10));
text = ngettext('{0} hour ago', '{0} hours ago', Math.round(diff / Date.ONEHOUR));
} else if (diff < 2 * Date.ONEDAY) {
text = gettext('yesterday');
} else if (diff < 7 * Date.ONEDAY) {
text = ngettext('{0} day ago', '{0} days ago', parseInt(diff / Date.ONEDAY, 10));
text = ngettext('{0} day ago', '{0} days ago', Math.round(diff / Date.ONEDAY));
} else if (diff < 30 * Date.ONEDAY) {
text = ngettext('{0} week ago', '{0} weeks ago', parseInt(diff / 7 / Date.ONEDAY, 10));
text = ngettext('{0} week ago', '{0} weeks ago', Math.round(diff / 7 / Date.ONEDAY));
} else if (diff < 365 * Date.ONEDAY) {
text = ngettext('{0} month ago', '{0} months ago', parseInt(diff / 30 / Date.ONEDAY, 10));
text = ngettext('{0} month ago', '{0} months ago', Math.round(diff / 30 / Date.ONEDAY));
} else {
text = ngettext('{0} year ago', '{0} years ago', parseInt(diff / 365 / Date.ONEDAY, 10));
text = ngettext('{0} year ago', '{0} years ago', Math.round(diff / 365 / Date.ONEDAY));
}
return text.replace(/(\d+)\s+/, '$1\xa0'); // Add a no-break space after first digits
case 'expiry':
return getExpiry(date - new Date());
default:
pattern = format;
}
@ -1197,7 +1259,7 @@ function getLocales(language) {
for (var i in locales) {
locale = locales[i];
localeString = locale.toString();
if (!localeString.contains('_')) {
if (localeString && !localeString.contains('_')) {
var isTranslated = jala.i18n.getCatalog(jala.i18n.getLocale(localeString));
result.push({
value: localeString,
@ -1207,6 +1269,17 @@ function getLocales(language) {
}
}
// TODO: Automatically integrate gendered german language
/*
var builder = java.util.Locale.Builder();
var locale1 = new java.util.Locale('de__#x-male');
var locale2 = builder.setLanguage('de')
.setExtension('x', 'male')
.build();
var locale3 = java.util.Locale.forLanguageTag(this.locale);
var locale = locale3;
console.log(java.lang.System.getProperty('java.version'));
console.log(locale, locale.language, locale.toLanguageTag());
*/
result.push({
value: 'de-x-male',
display: 'Deutsch ♂'
@ -1466,3 +1539,7 @@ function getLinkCount(item) {
}
return (content.match(/https?:\/\//g) || []).length;
}
function getHrefScheme() {
return getProperty('hrefScheme', 'http') + '://';
}

View file

@ -9,9 +9,7 @@ Object.prototype.dontEnum('parseJSON');
* @param {Object} data An arbitrary JavaScript object
*/
JSON.pad = function(data, callback) {
if (!callback) {
return;
}
if (!callback) return;
return callback + '(' + JSON.stringify(data) + ')';
}
@ -25,9 +23,10 @@ JSON.pad = function(data, callback) {
JSON.sendPaddedResponse = function(data, key, resume) {
var callback = req.data[key || 'callback'];
if (callback) {
res.reset();
res.contentType = 'text/javascript';
res.write(JSON.pad(data, callback));
resume || res.stop();
if (!resume) res.stop();
}
return;
}

View file

@ -166,7 +166,7 @@ Sql.REFERRERS = 'select referrer, count(*) as requests from ' +
'by referrer order by requests desc, referrer asc';
/**
* SQL command for deleting all log entries older than 2 days.
* SQL command for deleting all log entries older than a specific period.
* @constant
*/
Sql.PURGEREFERRERS = "delete from log where action = 'main' and " +
@ -176,15 +176,15 @@ Sql.PURGEREFERRERS = "delete from log where action = 'main' and " +
* SQL query for searching stories.
* @constant
*/
Sql.STORY_SEARCH = "select content.id from content, site, metadata where site.id = $0 and content.prototype = 'Story' and site.id = content.site_id and content.status in ('public', 'shared', 'open') and content.id = metadata.parent_id and metadata.name in ('title', 'text') and lower(metadata.value) like lower('%$1%') group by content.id, content.created order by content.created desc limit $2";
Sql.STORY_SEARCH = "select content.id from content, site, metadata, account as creator, account as modifier where site.id = $0 and content.prototype = 'Story' and site.id = content.site_id and content.status in ('public', 'shared', 'open') and content.creator_id = creator.id and content.modifier_id = modifier.id and creator.status <> 'deleted' and modifier.status <> 'deleted' and content.prototype = metadata.parent_type and content.id = metadata.parent_id and metadata.name in ('title', 'text') and lower(metadata.value) like lower('%$1%') group by content.id, content.created order by content.created desc limit $2";
Sql.COMMENT_SEARCH = "select comment.id from content as comment, content as story, site, metadata where site.id = $0 and comment.prototype = 'Comment' and site.id = comment.site_id and comment.story_id = story.id and story.status in ('public', 'shared', 'open') and story.comment_mode in ('open') and comment.id = metadata.parent_id and metadata.name in ('title', 'text') and lower(metadata.value) like lower('%$1%') group by comment.id, comment.created order by comment.created desc limit $2";
Sql.COMMENT_SEARCH = "select comment.id from content as comment, content as story, site, metadata, account as creator, account as modifier where site.id = $0 and comment.prototype = 'Comment' and site.id = comment.site_id and comment.story_id = story.id and story.status in ('public', 'shared', 'open') and story.comment_mode in ('open') and comment.creator_id = creator.id and comment.modifier_id = modifier.id and creator.status <> 'deleted' and modifier.status <> 'deleted' and comment.prototype = metadata.parent_type and comment.id = metadata.parent_id and metadata.name in ('title', 'text') and lower(metadata.value) like lower('%$1%') group by comment.id, comment.created order by comment.created desc limit $2";
/**
* SQL query for searching accounts which are not already members of the desired site.
* @constant
*/
Sql.MEMBERSEARCH = "select id, name, created from account where name $0 '$1' order by name asc limit $2";
Sql.MEMBERSEARCH = "select id, name, created, status from account where status not in ('blocked', 'deleted') and name $0 '$1' order by name asc limit $2";
/**
* SQL query for retrieving all story IDs in a sites archive.

View file

@ -18,9 +18,9 @@
app.addRepository('modules/helma/Aspects.js');
(function() {
function skinMayDisplayEditLink(name) {
return req.cookies[User.COOKIE + 'LayoutSandbox'] &&
name !== 'Site#page' &&
res.handlers.layout.getPermission('main') &&
typeof name === 'string' &&
!name.startsWith('$') &&
@ -35,6 +35,7 @@ app.addRepository('modules/helma/Aspects.js');
// Fix names using short form (ie. missing prototype)
name = object.constructor.name + name;
}
var id = name.replace('#', '-').toLowerCase();
if (skinMayDisplayEditLink(name) && !res.meta.skins[name]) {

48
code/Global/markdown.js Normal file
View file

@ -0,0 +1,48 @@
app.addRepository(app.dir + '/../lib/autolink-0.10.0.jar');
app.addRepository(app.dir + '/../lib/commonmark-0.14.0.jar');
app.addRepository(app.dir + '/../lib/commonmark-ext-autolink-0.14.0.jar');
app.addRepository(app.dir + '/../lib/commonmark-ext-gfm-strikethrough-0.14.0.jar');
app.addRepository(app.dir + '/../lib/commonmark-ext-gfm-tables-0.14.0.jar');
var renderMarkdown = (function() {
const commonMark = new JavaImporter(
Packages.org.commonmark.ext.autolink,
Packages.org.commonmark.ext.gfm.strikethrough,
Packages.org.commonmark.ext.gfm.tables,
Packages.org.commonmark.parser.Parser,
Packages.org.commonmark.renderer.html.AttributeProvider,
Packages.org.commonmark.renderer.html.HtmlRenderer
);
const extensions = [
commonMark.AutolinkExtension.create(),
commonMark.StrikethroughExtension.create(),
commonMark.TablesExtension.create()
];
const parser = commonMark.Parser
.builder()
.extensions(extensions)
.build();
const AttributeProvider = function() {
return new commonMark.AttributeProvider({
setAttributes: function(node, tagName, attributes) {
if (tagName === 'table') {
attributes.put('class', 'uk-table uk-table-striped uk-table-hover uk-table-condensed');
}
}
});
};
const renderer = commonMark.HtmlRenderer
.builder()
.attributeProviderFactory(AttributeProvider)
.extensions(extensions)
.build();
return function(str) {
const document = parser.parse(str);
return renderer.render(document);
};
})();

View file

@ -19,7 +19,7 @@
<% param.extra %>
<p>
<button class='uk-button uk-button-danger' name="proceed" value="1"><% gettext Proceed %></button>
<a href='.' class="uk-button uk-button-link"><% gettext Cancel %></a>
<a href='<% session.location %>' class="uk-button uk-button-link"><% gettext Cancel %></a>
</p>
</form>

View file

@ -32,6 +32,7 @@ HopObject.remove = function(options) {
var item;
while (this.size() > 0) {
item = this.get(0);
if (!item) return;
if (item.constructor.remove) {
item.constructor.remove.call(item, options);
} else if (!options) {
@ -59,7 +60,7 @@ HopObject.getFromPath = function(name, collection) {
site = res.handlers.site;
}
if (site && site.getPermission('main')) {
return site[collection].get(name);
return (collection ? site[collection] : site).get(name);
}
}
return null;
@ -99,28 +100,44 @@ HopObject.prototype.onRequest = function() {
// Checking if we are on the correct host to prevent at least some XSS issues
if (req.action !== 'notfound' && req.action !== 'error' &&
this.href().contains('://') &&
!this.href().toLowerCase().startsWith(req.servletRequest.scheme +
'://' + req.servletRequest.serverName.toLowerCase())) {
!this.href().toLowerCase().startsWith(getHrefScheme() +
req.servletRequest.serverName.toLowerCase())) {
res.redirect(this.href(req.action === 'main' ? String.EMPTY : req.action));
}
User.autoLogin();
res.handlers.membership = User.getMembership();
if (User.getCurrentStatus() === User.BLOCKED) {
session.data.status = 403;
session.data.error = gettext('Your account has been blocked.') + String.SPACE +
gettext('Please contact an administrator for further information.');
// Logout persisting session if account has been deleted
if (User.getCurrentStatus() === User.DELETED) {
User.logout();
res.redirect(root.href('error'));
}
if (res.handlers.site.status === Site.BLOCKED &&
!User.require(User.PRIVILEGED)) {
session.data.status = 403;
session.data.error = gettext('The site you requested has been blocked.') +
String.SPACE + gettext('Please contact an administrator for further information.');
res.redirect(root.href('error'));
if (User.getCurrentStatus() === User.BLOCKED) {
User.logout();
res.status = 403;
res.data.error = gettext('Your account has been blocked.') + String.SPACE +
gettext('Please contact an administrator for further information.');
root.error_action();
res.stop();
}
if (!User.require(User.PRIVILEGED)) {
// Simulate 404 for sites which are due for deletion by cronjob
if (res.handlers.site.status === Site.DELETED) {
res.handlers.site = root;
root.notfound_action();
res.stop();
}
if (res.handlers.site.status === Site.BLOCKED) {
res.status = 403;
res.handlers.site = root;
res.data.error = gettext('The site you requested has been blocked.') +
String.SPACE + gettext('Please contact an administrator for further information.');
root.error_action();
res.stop();
}
}
HopObject.confirmConstructor(Layout);
@ -135,11 +152,8 @@ HopObject.prototype.onRequest = function() {
}
User.getLocation();
res.status = 401;
res.data.title = gettext('{0} 401 Error', root.title);
res.data.body = root.renderSkinAsString('$Root#error', {error:
gettext('You are not allowed to access this part of the site.')});
res.handlers.site.renderSkin('Site#page');
session.data.error = null;
res.data.error = gettext('You are not allowed to access this part of the site.');
root.error_action();
res.stop();
}
@ -162,33 +176,37 @@ markgettext('Image');
markgettext('Membership');
markgettext('Poll');
markgettext('Story');
markgettext('User');
HopObject.prototype.delete_action = function() {
let redirectUrl = req.data.http_referer;
if (req.postParams.proceed) {
try {
var parent = this._parent;
var type = this._prototype;
var url = this.constructor.remove.call(this, req.postParams) || parent.href();
res.message = gettext('{0} was successfully deleted.', gettext(this._prototype));
res.message = gettext('{0} was successfully deleted.', gettext(type));
res.redirect(User.getLocation() || url);
} catch(ex) {
redirectUrl = session.data.referer;
res.message = ex;
app.log(ex);
}
}
res.data.action = this.href(req.action);
if (req.data.http_get_remainder === 'safemode') { res.skinpath = [app.dir]; }
if (!res.data.action) { res.data.action = this.href(req.action); }
res.data.title = gettext('Confirm Deletion');
session.data.location = redirectUrl;
res.data.body = this.renderSkinAsString('$HopObject#confirm', {
text: this.getConfirmText(req.action),
extra: this.getConfirmExtra(req.action) || String.EMPTY
});
if (req.data.http_get_remainder === 'safemode') {
res.skinpath = root.layout.getSkinPath();
res.handlers.site.renderSkin('$Site#page');
} else {
res.handlers.site.renderSkin('Site#page');
}
res.handlers.site.renderSkin('Site#page');
return;
};
@ -331,7 +349,7 @@ HopObject.prototype.addTag = function(name) {
*/
HopObject.prototype.removeTag = function(tag) {
var parent = tag._parent;
if (parent.size() === 1) {
if (parent && parent.size() === 1) {
parent.remove();
}
tag.remove();

View file

@ -28,18 +28,15 @@ HopObject.prototype.handleMetadata = function(name) {
this.__defineGetter__(name, function() {
return this.getMetadata(name);
});
this.__defineSetter__(name, function(value) {
return this.setMetadata(name, value);
});
this[name + '_macro'] = function(param) {
var value;
if (value = this[name]) {
res.write(value);
}
return;
return this[name] || null;
};
return;
}
};
/**
*
@ -48,12 +45,12 @@ HopObject.prototype.handleMetadata = function(name) {
*/
HopObject.prototype.getMetadata = function(name) {
if (!this.metadata) {
throw Error('No metadata collection defined for prototype ' + this.constructor.name);
} else {
this.metadata.prefetchChildren();
app.log('No metadata collection defined for prototype ' + this.constructor.name);
return name ? null : {};
}
var self = this;
this.metadata.prefetchChildren();
if (!name) {
var result = {};
@ -121,7 +118,8 @@ HopObject.prototype.deleteMetadata = function(name) {
var self = this;
if (arguments.length === 0) {
return HopObject.remove.call(this.metadata);
HopObject.remove.call(this.metadata);
return;
}
Array.prototype.forEach.call(arguments, function(name) {

View file

@ -29,8 +29,10 @@
<% #embed %>
<div class='av-image-box'>
<% image.render | image.link class='uk-thumbnail' %>
<% image.source %>
<figure>
<% image.render | link <% param.link %> class='uk-thumbnail' %>
<% image.description prefix="<figcaption class='uk-text-small'>" suffix=</figcaption> %>
</figure>
</div>
<% #edit %>
@ -39,7 +41,7 @@
<% image.link . ' ' class='uk-icon-button uk-icon-link uk-text-middle' %>
</h1>
<div class='uk-article-meta'><% image.skin $HopObject#meta %></div>
<form class='uk-margin-top uk-form uk-form-stacked' method="post" action="<% response.action %>" enctype="multipart/form-data">
<form class='uk-margin-top uk-form uk-form-stacked' method="post" action="<% response.action %>" enctype="multipart/form-data" x-data="{ name: '<% image.name %>', layout: location.href.indexOf('/layout/') > -1 }">
<div class='uk-form-row'>
<label class='uk-form-label' for='file'>
<% gettext File %>
@ -48,13 +50,13 @@
<% image.upload file %>
</div>
</div>
<div class='uk-form-row uk-hidden av-name-row'>
<div class='uk-form-row av-name-row' hidden :hidden='false'>
<label class='uk-form-label' for='name'>
<% gettext Name %>
<i class='uk-icon-info-circle uk-text-muted' title='<% gettext "If you do not specify a name Antville will create one based on the filename." %>' data-uk-tooltip='{pos: "right"}'></i>
</label>
<div class='uk-form-controls'>
<% image.input name class='uk-width-1-2' %>
<% image.input name class='uk-width-1-2' :disabled='!!name' %>
</div>
</div>
<div class='uk-form-row'>
@ -65,7 +67,7 @@
<% image.input description class='uk-width-1-1' %>
</div>
</div>
<div class='uk-form-row uk-hidden av-tags-row'>
<div class='uk-form-row av-tags-row' x-show='!layout'>
<label class='uk-form-label' for='tags'>
<% gettext Tags %>
<i class='uk-icon-info-circle uk-text-muted' title='<% gettext 'Separated by commas' %>' data-uk-tooltip='{pos: "right"}'></i>
@ -88,14 +90,3 @@
<a href='.' class="uk-button uk-button-link"><% gettext Cancel %></a>
</div>
</form>
<script type="text/javascript">
$(function() {
if ('<% image.name %>') {
$('#name').attr('disabled', true);
}
$('.av-name-row').removeClass('uk-hidden');
if (location.href.indexOf('/layout/') < 0) {
$('.av-tags-row').removeClass('uk-hidden');
}
});
</script>

View file

@ -19,6 +19,8 @@
* @fileOverview Defines the Image prototype.
*/
app.addRepository("modules/helma/Http.js");
markgettext('Image');
markgettext('image');
markgettext('a image // accusative');
@ -256,10 +258,30 @@ Image.prototype.update = function(data) {
var mime = data.file;
var origin = data.file_origin;
var isLayout = (this.parent_type === 'Layout' || path && !!path.layout);
if (!mime || mime.contentLength < 1) {
if (origin && origin !== this.origin) {
mime = getURL(origin);
var http = new helma.Http();
http.setBinaryMode(true);
http.setHeader('Accept', 'image/*');
http.setHeader('Accept-Encoding', 'gzip');
http.setHeader('Cache-Control', 'no-cache');
http.setHeader('Pragma', 'no-cache');
http.setHeader('Referer', origin);
http.setHeader('User-Agent', req.data.http_browser);
var response = http.getUrl(origin);
mime = new Packages.helma.util.MimePart(
origin,
response.content,
response.type
);
if (!mime) {
throw Error(gettext('Could not fetch the file from the given URL.'));
}
@ -274,27 +296,26 @@ Image.prototype.update = function(data) {
throw Error(gettext('This does not seem to be a valid JPG, PNG or GIF image.'));
}
this.origin = origin;
var mimeName = mime.normalizeFilename(mime.name);
this.contentLength = mime.contentLength;
this.contentType = mime.contentType;
File.prototype.setOrigin.call(this, origin);
if (!this.name) {
var name = File.getName(data.name) || mimeName.split('.')[0];
var name = File.getName(data.name || mimeName.split('.')[0]);
this.name = this.parent.images.getAccessName(name);
}
if (!data.description && origin) {
data.description = gettext('Source: {0}', origin);
}
var image = this.getConstraint(mime, res.handlers.site.imageDimensionLimits);
this.height = image.height;
this.width = image.width;
var thumbnail;
if (image.width > Image.THUMBNAILWIDTH) {
thumbnail = this.getConstraint(mime, [Image.THUMBNAILWIDTH]);
var image = this.getHelmaImage(mime, isLayout ? null :
res.handlers.site.imageDimensionLimits);
this.width = image.width;
this.height = image.height;
// Create a thumbnail version if the image size exceeds
if (this.width > Image.THUMBNAILWIDTH) {
thumbnail = this.getHelmaImage(mime, [Image.THUMBNAILWIDTH]);
this.thumbnailWidth = thumbnail.width;
this.thumbnailHeight = thumbnail.height;
} else if (this.isPersistent()) {
@ -305,22 +326,26 @@ Image.prototype.update = function(data) {
// Make the image persistent before proceeding with writing files and
// setting tags (also see Helma bug #607)
this.isTransient() && this.persist();
if (this.isTransient()) this.persist();
var fileName = this.name + extension;
// Remove existing image files if the file name has changed
if (fileName !== this.fileName) {
// Remove existing image files if the file name has changed
this.removeFiles();
}
this.fileName = fileName;
thumbnail && (this.thumbnailName = this.name + '_small' + extension);
this.writeFiles(image.resized || mime, thumbnail && thumbnail.resized);
image.resized && (this.contentLength = this.getFile().getLength());
if (thumbnail) this.thumbnailName = this.name + '_small' + extension;
this.writeFiles(image.data || mime, thumbnail && thumbnail.data);
this.contentLength = this.getFile().getLength();
}
if (this.parent_type !== 'Layout') {
// Layout images cannot be tagged
if (!isLayout) {
this.setTags(data.tags || data.tag_array);
}
this.description = data.description;
this.touch();
return;
@ -374,7 +399,7 @@ Image.prototype.thumbnail_macro = function(param) {
return this.render_macro(param);
}
param.src = encodeURI(this.getUrl(this.getThumbnailFile().getName()));
param.title || (param.title = encode(this.description));
if (!param.title) { param.title = encode(this.description || ''); }
param.alt = encode(param.alt || param.title);
var width = param.width || this.thumbnailWidth;
var height = param.height || this.thumbnailHeight;
@ -396,7 +421,7 @@ Image.prototype.thumbnail_macro = function(param) {
*/
Image.prototype.render_macro = function(param) {
param.src = encodeURI(this.getUrl());
param.title || (param.title = encode(this.description));
if (!param.title) { param.title = encode(this.description || ''); }
param.alt = encode(param.alt || param.title);
var style = [];
param.width && style.push('width:', param.width + 'px;');
@ -410,6 +435,10 @@ Image.prototype.render_macro = function(param) {
return;
};
Image.prototype.description_macro = function() {
File.prototype.description_macro.apply(this, arguments);
};
/**
*
* @param {Object} name
@ -436,12 +465,14 @@ Image.prototype.getUrl = function(name) {
name || (name = this.fileName);
if (this.parent_type === 'Layout') {
var layout = this.parent || res.handlers.layout;
var url = String.EMPTY;
try {
return layout.site.getStaticUrl('layout/' + name);
url = layout.site.getStaticUrl('layout/' + name);
} catch (ex) {
console.error(ex);
console.error(this.toSource());
}
return url;
}
var site = this.parent || res.handlers.site;
return site.getStaticUrl('images/' + name);
@ -483,30 +514,49 @@ Image.prototype.getJSON = function() {
* @throws {Error}
* @returns {Object}
*/
Image.prototype.getConstraint = function(mime, dimensionLimits) {
Image.prototype.getHelmaImage = function(mime, dimensionLimits) {
if (!dimensionLimits) dimensionLimits = [];
var maxWidth = dimensionLimits[0] || Infinity;
var maxHeight = dimensionLimits[1] || Infinity;
var result = {
data: null,
width: 0,
height: 0
};
try {
var image = new helma.Image(mime.inputStream);
var factorH = 1, factorV = 1;
if (maxWidth && image.width > maxWidth) {
factorH = maxWidth / image.width;
}
if (maxHeight && image.height > maxHeight) {
factorV = maxHeight / image.height;
}
if (factorH !== 1 || factorV !== 1) {
var width = Math.ceil(image.width *
(factorH < factorV ? factorH : factorV));
var height = Math.ceil(image.height *
(factorH < factorV ? factorH : factorV));
image.resize(width, height);
if (mime.contentType.endsWith('gif')) {
image.reduceColors(256);
}
return {resized: image, width: image.width, height: image.height};
result.data = image;
}
return {width: image.width, height: image.height};
result.width = image.width;
result.height = image.height;
return result;
} catch (ex) {
app.log(ex);
throw Error(gettext('Could not resize the image.'));

View file

@ -19,7 +19,7 @@ _db = antville
_table = image
_id = id
_prototype = prototype
_parent = parent.images, parent
_parent = parent.images
name
prototype

View file

@ -3,13 +3,13 @@
<div class="uk-article-meta">
<% gettext "Posted by {0} on {1}" <% image.creator %> <% image.created short %> %>
</div>
<div class='uk-margin-top'>
<a href='<% image.url %>' class='uk-thumbnail' style='width: <% image.width %>px;'>
<% image.render %>
<div class='uk-thumbnail-caption'>
<% image.description default=<% image.name %> %>
</div>
</a>
<div class='av-image-box uk-margin-top'>
<figure>
<a href='<% image.url %>'>
<% image.render class='uk-thumbnail' %>
</a>
<% image.description prefix="<figcaption class='uk-text-small'>" suffix=</figcaption> %>
</figure>
</div>
<div class='uk-margin-top'>
<% image.link edit <% gettext Edit %> class='uk-button' %>

View file

@ -33,48 +33,56 @@
<div class='uk-hidden av-upload-drop'>
<i class='uk-icon uk-icon-cloud-upload'></i>
</div>
<script type='text/javascript'>
(function () {
var dropTimer, dropHasHilite;
var dropElement = $('.av-upload-drop');
var parent = location.href.lastIndexOf('/layout/images/') > -1 ? 'layout' : 'site';
var uploadUrl = '<% site.images.href upload %>?parent=' + parent;
<script>
// Setup drag&drop for image uploads
(function() {
const dropElement = document.querySelector('.av-upload-drop');
const parent = location.href.lastIndexOf('/layout/images/') > -1 ? 'layout' : 'site';
const uploadUrl = '<% site.images.href upload %>?parent=' + parent;
var target = $(document).on('dragstart dragenter dragover', function () {
if (!dropHasHilite) {
dropElement.removeClass('uk-hidden');
dropHasHilite = true;
}
}).on('dragleave dragend', function () {
let dropTimer;
let dropHasHilite;
['dragstart', 'dragenter', 'dragover'].forEach(function(type) {
document.addEventListener(type, function() {
if (!dropHasHilite) {
dropElement.classList.remove('uk-hidden');
dropHasHilite = true;
}
});
});
['dragleave', 'dragend'].forEach(function(type) {
dropHasHilite = false;
clearTimeout(dropTimer);
dropTimer = setTimeout(function () {
dropHasHilite || dropElement.addClass('uk-hidden');
dropTimer = setTimeout(function() {
dropHasHilite || dropElement.classList.add('uk-hidden');
}, 100);
});
});
var restoreDrop = function () {
dropElement.addClass('uk-hidden')
.find('i').removeClass('av-upload-glow');
};
const restoreDrop = function() {
dropElement.classList.add('uk-hidden');
dropElement.querySelector('i').classList.remove('av-upload-glow');
};
var uploadDrop = UIkit.uploadDrop(target, {
UIkit.uploadDrop(document, {
action: uploadUrl,
allow: '*.(jpg|jpeg|gif|png)',
loadstart: function (event) {
dropElement.find('i')
.addClass('av-upload-glow');
loadstart: function() {
dropElement.querySelector('i').classList.add('av-upload-glow');
},
progress: function (percent) {
//console.log(percent, '% progress');
},
allcomplete: function (response) {
location.href = response;
//progress: function(percent) {},
allcomplete: function(response) {
location.href = response;
},
notallowed: restoreDrop,
error: restoreDrop,
abort: restoreDrop
});
})();
});
})();
</script>

View file

@ -1,92 +1,101 @@
<% #main %>
<h1><% response.title %></h1>
<div class='uk-article-meta'><% layout.skin $HopObject#meta %></div>
<div class='uk-margin-top'>
<% layout.link skins <% gettext Skins %> %>
<% layout.link images <% gettext Images %> prefix=' | ' %>
<% layout.link import <% gettext Import %> prefix=' | ' %>
<% layout.link export <% gettext Export %> prefix=' | ' %>
<% layout.link skins <% gettext Skins %> %>
<% layout.link images <% gettext Images %> prefix=' | ' %>
<% layout.link import <% gettext Import %> prefix=' | ' %>
<% layout.link export <% gettext Export %> prefix=' | ' %>
</div>
<% site.skin $Site#noscript %>
<form class='uk-margin-top uk-form uk-form-stacked' id='prefs' method='post'>
<div class='uk-form-row'>
<div class='uk-form-label'>
<% gettext 'Show Controls' %>
<div class='uk-form-row'>
<div class='uk-form-label'>
<% gettext 'Show Controls' %>
</div>
<div class='uk-form-controls'>
<input id='sandbox' name='sandbox' type='checkbox' <% if <% layout.sandbox %> is true then checked %>>
<label for='sandbox'><% gettext enabled %></label>
</div>
</div>
<div class='uk-form-row uk-margin-top' x-data='{
showControls: function(event) {
event.currentTarget.querySelector(".av-value-controls").hidden = false;
},
hideControls: function(event) {
event.currentTarget.querySelector(".av-value-controls").hidden = true;
},
addSetting: function(event) {
const name = prompt("<% gettext "Please enter the name of the new setting:" %>");
if (!name) return;
const key = "av-value " + name;
const valueRow = document.querySelector(".av-value-row:last-child");
const clone = valueRow.cloneNode(true);
clone.querySelector(".av-value-title").innerHTML = name;
const clipboard = clone.querySelector(".av-clipboard-copy");
if (clipboard) clipboard.remove();
const input = clone.querySelector(".uk-form-controls input");
input.id = key.replace(/\s/g, "-");
input.name = key;
input.value = "";
input.type = this.getType(key);
valueRow.insertAdjacentElement("afterend", clone);
clone.querySelector("input").focus();
},
removeSetting: function(event) {
event.currentTarget.closest(".av-value-row").remove();
},
getType: function(name) {
const type = name.split(" ").pop();
const types = { color: "color" };
return types[type] || "text";
}
}'>
<fieldset class='avvalues'>
<legend>
<% gettext Settings %>
</legend>
<div class='uk-grid'>
<% layout.values %>
</div>
<div class='uk-form-controls'>
<input id='sandbox' name='sandbox' type='checkbox' <% if <% layout.sandbox %> is true then checked %>>
<label for='sandbox'><% gettext enabled %></label>
<div id='av-add-value' class='uk-margin-bottom uk-margin-top' hidden :hidden='false'>
<a href='javascript:' class='uk-icon-button uk-icon-plus uk-text-middle' @click='addSetting'></a>
</div>
</div>
<div class='uk-form-row uk-margin-top'>
<fieldset class='av-values'>
<legend>
<% gettext Settings %>
</legend>
<div class='uk-grid'>
<% layout.values %>
</div>
<div id='av-add-value' class='uk-margin-bottom uk-hidden'>
<div class='uk-form-label'>&#160;</div>
<a href='javascript:' class='uk-icon-button uk-icon-plus uk-text-middle'></a>
</div>
</fieldset>
</div>
<div class='uk-margin-top'>
<button class='uk-button uk-button-primary' type='submit' id='submit' name='save' value='1'>
<% gettext Save %>
</button>
<% layout.link reset <% gettext Reset %> class='uk-button' %>
<a href='..' class='uk-button uk-button-link'><% gettext Cancel %></a>
</div>
</fieldset>
</div>
<div class='uk-margin-top'>
<button class='uk-button uk-button-primary' type='submit' id='submit' name='save' value='1'>
<% gettext Save %>
</button>
<% layout.link reset <% gettext Reset %> class='uk-button' %>
<a href='..' class='uk-button uk-button-link'><% gettext Cancel %></a>
</div>
</form>
<script type='text/javascript'>
$('.av-values').on('mouseover', '.av-value-row', function () {
$(this).find('.av-value-controls').removeClass('uk-hidden');
}).on('mouseout', '.av-value-row', function () {
$(this).find('.av-value-controls').addClass('uk-hidden');
}).on('click', '.av-value-remove', function () {
$(this).parents('.av-value-row').remove();
});
$('#av-add-value').removeClass('uk-hidden')
.find('a')
.on('click', function (event) {
event.preventDefault();
var name = prompt('<% gettext "Please enter the name of the new setting:" %>');
if (name) {
var key = 'av-value ' + name;
var valueRow = $('.av-value-row').eq(0).clone()
.removeClass('uk-hidden')
valueRow.find('.av-value-title').html(name);
valueRow.find('.uk-form-controls input').attr({
id: key.replace(new RegExp(' ', 'g'), '-'),
name: key,
value: '',
type: getType(key)
});
$('.av-value-row:last').after(valueRow);
$(valueRow).find('.av-clipboard-copy').remove();
$(valueRow).find('input').focus();
}
});
function getType(name) {
var parts = name.split(' ');
var typePart = parts.pop();
var types = {
color: 'color'
};
return types[typePart] || 'text';
}
</script>
<% #value %>
<div class='uk-width-1-2 uk-margin-bottom av-value-row <% param.class %>'>
<div class='uk-width-1-2 uk-margin-bottom av-value-row <% param.class %>' @mouseover='showControls($event)' @mouseout='hideControls($event)'>
<div class='uk-form-label'>
<span class='av-value-title'><% param.title %></span>
<span class='av-value-controls uk-hidden'>
<a href='javascript:' class='av-value-remove'><i class='uk-icon-trash-o'></i></a>
<span class='av-value-controls' hidden>
<a href='javascript:' class='av-value-remove' @click='removeSetting($event)'><i class='uk-icon-trash-o'></i></a>
<a href='javascript:' class='av-clipboard-copy' data-text='<% gettext 'Press CTRL & C to copy to clipboard.' %>' data-value="<% param.macro %>"><i class='uk-icon-clipboard'></i></a>
</span>
</div>
@ -97,7 +106,7 @@
<% #import %>
<h1><% response.title %></h1>
<form class='uk-form' method="post" enctype="multipart/form-data">
<form class='uk-form' method="post" enctype="multipart/form-data" x-data='{ name: "<% file.name %>" }'>
<% layout.upload upload %>
<div class='uk-margin-top'>
<button class='uk-button uk-button-primary' type="submit" id="submit" name="submit" value="1">

View file

@ -250,6 +250,7 @@ Layout.prototype.reset_action = function() {
}
}
session.data.location = this.href();
res.data.action = this.href(req.action);
res.data.title = gettext('Confirm Reset');
res.data.body = this.renderSkinAsString('$HopObject#confirm', {

View file

@ -26,14 +26,29 @@
<% #login %>
<h1><% response.title %></h1>
<form class='uk-form uk-form-stacked' id="login" method="post" action="<% response.action %>">
<input type="hidden" name="digest" id="digest" />
<form class='uk-form uk-form-stacked' id="login" method="post" action="<% response.action %>" @submit='submit($refs)' x-data='{
submit: function($refs) {
const options = {
data: { user: $refs.username.value },
callback: function(salt, error) {
if (error) return console.error(error);
$refs.digest.value = Antville.hash(Antville.hash($refs.password.value + salt) + "<% session.token %>");
$refs.password.value = "";
}
};
Antville.http("get", "<% members.href salt.txt %>", options);
}
}'>
<input type="hidden" name="digest" id="digest" x-ref='digest'/>
<div class='uk-form-row'>
<label class='uk-form-label' for='name'>
<% gettext Account %>
</label>
<div class='uk-form-controls'>
<input name="name" id="name" tabindex=1 value="<% request.name encoding="form" %>" class='uk-width-1-2' required>
<input name="name" id="name" tabindex=1 value="<% request.name encoding="form" %>" class='uk-width-1-2' required x-ref='username'>
<% members.link register <% gettext "Not registered yet\?" %> class='uk-button uk-button-link' tabindex=6 %>
</div>
</div>
@ -42,7 +57,7 @@
<% gettext Password %>
</label>
<div class='uk-form-controls uk-form-password uk-width-1-2'>
<input type="password" name="password" id="password" class='uk-width-1-1' tabindex=2 required>
<input type="password" name="password" id="password" class='uk-width-1-1' tabindex=2 required x-ref='password'>
<a href='javascript:' class='uk-form-password-toggle' data-uk-form-password="{
lblHide: '<% gettext Hide %>',
lblShow: '<% gettext Show %>'
@ -64,35 +79,14 @@
<a href='<% site.href %>' class="uk-button uk-button-link" tabindex=5><% gettext Cancel %></a>
</div>
</form>
<script type="text/javascript">
$("form#login").on('submit', function (event) {
if ($('#digest').val()) {
return true;
}
var form = $(this);
event.preventDefault();
var name = $("#name").val();
$.ajax({
url: '<% members.href salt.txt %>',
data: "user=" + encodeURIComponent(name),
dataType: "text",
cache: false,
error: function() { /* ... */ },
success: function(salt, status, xhr) {
var password = $("#password").val();
var token = "<% session.token %>";
$("input:password").val("");
$("#digest").val($.md5($.md5(password + salt) + token));
form.submit();
}
});
});
</script>
<% story <% root.termsStory %> link text=<% gettext "Terms and Conditions" %> prefix='<div class="uk-margin-top"><i class="uk-icon-legal"></i> ' suffix=</div> %>
<% story <% root.privacyStory %> link text=<% gettext "Data Privacy Statement" %> prefix='<div><i class="uk-icon-cloud-upload"></i> ' suffix=</div> %>
<% #register %>
<h1><% response.title %></h1>
<form class='uk-form uk-form-stacked' id="register" method="post" action="<% response.action %>">
<input type="hidden" name="hash" id="hash" />
<form class='uk-form uk-form-stacked' method="post" action="<% response.action %>" x-data='{ hash: "" }' @submit='$refs.hash.value = Antville.hash($refs.password.value + "<% session.token %>"); $refs.password.value = "";'>
<input type="hidden" name="hash" id="hash" x-ref='hash' />
<div class='uk-form-row'>
<label class='uk-form-label' for='name'>
<% gettext Account %>
@ -114,29 +108,53 @@
<% gettext Password %>
</label>
<div class='uk-form-controls uk-form-password uk-width-1-2'>
<input type="password" name="password" id="password" class='uk-width-1-1' required tabindex=3>
<input type="password" name="password" id="password" class='uk-width-1-1' required tabindex=3 x-ref='password'>
<a href='javascript:' class='uk-form-password-toggle' data-uk-form-password="{
lblHide: '<% gettext Hide %>',
lblShow: '<% gettext Show %>'
}"><% gettext Show %></a>
</div>
</div>
<% if <% root.termsStory %> is null then '' else <% members.skin $Members#terms %> %>
<% if <% root.privacyStory %> is null then '' then <% members.skin $Members#privacy %> %>
<% param.captcha prefix="<div class='uk-form-row'>" suffix="</div>" %>
<div class='uk-form-row uk-margin-top'>
<button class='uk-button uk-button-primary' type="submit" id="submit" name="register" value="1" tabindex=3>
<button class='uk-button uk-button-primary' type="submit" id="submit" name="register" value="1" tabindex=6>
<% gettext Register %>
</button>
<a href='<% members.href login %>' class="uk-button uk-button-link" tabindex=4><% gettext Cancel %></a>
<a href='<% members.href login %>' class="uk-button uk-button-link" tabindex=7><% gettext Cancel %></a>
</div>
</form>
<% #terms %>
<div class='uk-form-row'>
<label>
<input type="checkbox" name="terms" tabindex="4" required>
<% gettext "I understand and accept the {0}terms and conditions{1}" <% story <% root.termsStory %> url prefix='<a href="' suffix='">' %> '</a>' %>
</label>
</div>
<% #privacy %>
<div class='uk-form-row'>
<label>
<input type="checkbox" name="privacy" tabindex="5" required>
<% gettext "I understand and accept the {0}data privacy statement{1}" <% story <% root.privacyStory %> url prefix='<a href="' suffix='">' %> '</a>' %>
</label>
</div>
<% #accept %>
<h1><% response.title %></h1>
<% gettext "We have updated our terms and conditions. Please reaffirm you understand and accept the following:" %>
<form class='uk-margin-top uk-form uk-form-stacked' method="post" action="<% response.action %>">
<% if <% root.termsStory %> is null then '' else <% members.skin $Members#terms %> %>
<% if <% root.privacyStory %> is null then '' then <% members.skin $Members#privacy %> %>
<div class='uk-form-row uk-margin-top'>
<button class='uk-button uk-button-primary' type="submit" name="accept" value="1" tabindex=6>
<% gettext Accept %>
</button>
<a href='<% site.href %>' class="uk-button uk-button-link" tabindex=7><% gettext Cancel %></a>
</div>
</form>
<script type="text/javascript">
$('form#register').submit(function() {
var token = '<% session.token %>';
var password = $('#password').val();
$('input:password').val('');
var hash = $.md5(password + token);
$('#hash').val(hash);
});
</script>
<% #reset %>
<h1><% response.title %></h1>
@ -223,3 +241,7 @@
<a href='?name=<% param.name encoding=form %>'><i class='uk-icon-plus'></i></a>
</td>
</tr>
<% #captcha %>
<div class='uk-margin-top h-captcha' data-sitekey='<% property captcha.sitekey %>'></div>
<script src='https://hcaptcha.com/1/api.js?hl=<% site.locale %>' async defer></script>

View file

@ -40,19 +40,27 @@ markgettext('members');
*/
Members.prototype.getPermission = function(action) {
switch (action) {
case 'accept':
case 'login':
case 'logout':
case 'register':
case 'reset':
case 'salt.txt':
return true;
case 'register':
return !root.creator || root.loginScope === Admin.NONE || User.require(root.loginScope);
}
var sitePermission = this._parent.getPermission('main');
switch (action) {
case 'delete':
return session.user && session.user.getPermission(action);
case 'edit':
case 'export':
case 'subscriptions':
case 'timeline':
case 'updates':
return !!session.user;
@ -80,23 +88,37 @@ Members.prototype.main_action = function() {
Members.prototype.register_action = function() {
if (req.postParams.register) {
try {
var title = res.handlers.site.title;
var user = User.register(req.postParams);
var membership = Membership.add(user, Membership.SUBSCRIBER, this._parent);
Captcha.verify(req.postParams);
if (root.termsStory && !req.postParams.terms) throw Error('Please accept the terms and conditions.');
if (root.privacyStory && !req.postParams.privacy) throw Error('Please accept the data privacy statement.');
const title = res.handlers.site.title;
const user = User.register(req.postParams);
const membership = Membership.add(user, Membership.SUBSCRIBER, this._parent);
user.accepted = Date.now();
membership.notify(req.action, user.email,
gettext('[{0}] Welcome to {1}!', root.title, title));
res.message = gettext('Welcome to “{0}”, {1}. Have fun!',
title, user.name);
res.redirect(User.getLocation() || this._parent.href());
} catch (ex) {
res.message = ex;
}
}
const param = { captcha: Captcha.render(this) };
session.data.token = User.getSalt();
res.data.action = this.href(req.action);
res.data.title = gettext('Register');
res.data.body = this.renderSkinAsString('$Members#register');
res.data.body = this.renderSkinAsString('$Members#register', param);
this._parent.renderSkin('Site#page');
return;
}
@ -105,11 +127,11 @@ Members.prototype.reset_action = function() {
if (req.postParams.reset) {
try {
if (!req.postParams.name || !req.postParams.email) {
throw Error(gettext('Please enter a user name and e-mail address.'));
throw Error(gettext('Please enter a username and e-mail address.'));
}
var user = User.getByName(req.postParams.name);
if (!user || user.email !== req.postParams.email) {
throw Error(gettext('User name and e-mail address do not match.'))
throw Error(gettext('Username and e-mail address do not match.'))
}
var token = User.getSalt();
user.setMetadata('resetToken', token);
@ -160,6 +182,25 @@ Members.prototype.login_action = function() {
if (req.postParams.login) {
try {
var user = User.login(req.postParams);
if (!User.require(root.loginScope, user)) {
throw Error(gettext('Sorry, logging in is currently not possible.'));
}
// Check if terms and conditions have been updated
var accepted = user.accepted || 0;
if ([root.termsStory, root.privacyStory].some(story => {
if (story) {
story = HopObject.getFromPath(story, 'stories');
return story && story.modified - accepted > 0;
}
})) {
User.logout();
session.data.login = req.postParams;
res.redirect(this.href('accept'));
}
res.message = gettext('Welcome to {0}, {1}. Have fun!', res.handlers.site.getTitle(), user.name);
res.redirect(User.getLocation() || this._parent.href());
} catch (ex) {
@ -186,29 +227,29 @@ Members.prototype.logout_action = function() {
}
Members.prototype.edit_action = function() {
if (req.postParams.save) {
try {
session.user.update(req.postParams);
res.message = gettext('The changes were saved successfully.');
res.redirect(this.href(req.action));
} catch (err) {
res.message = err.toString();
}
}
session.data.token = User.getSalt();
session.data.salt = session.user.salt;
res.data.title = gettext('Account');
res.data.body = session.user.renderSkinAsString('$User#edit');
this._parent.renderSkin('Site#page');
return;
}
res.handlers.context = this;
return void User.prototype.edit_action.call(session.user);
};
Members.prototype.export_action = function() {
res.handlers.context = this;
return void User.prototype.export_action.call(session.user);
};
Members.prototype.timeline_action = function() {
res.handlers.context = this;
return void User.prototype.timeline_action.call(session.user);
};
Members.prototype.delete_action = function() {
res.handlers.context = this;
return void User.prototype.delete_action.call(session.user);
};
Members.prototype.salt_txt_action = function() {
res.contentType = 'text/plain';
var user;
if (user = User.getByName(req.queryParams.user)) {
res.write(user.salt || String.EMPTY);
}
const user = User.getByName(req.queryParams.user);
if (user) res.write(user.salt || String.EMPTY);
return;
}
@ -314,6 +355,33 @@ Members.prototype.add_action = function() {
return;
}
Members.prototype.accept_action = function() {
if (!session.data.login) { res.redirect(this._parent.href()); }
if (req.postParams.accept) {
try {
if (root.termsStory && !req.postParams.terms) {
throw Error(gettext('Please accept the terms and conditions.'));
}
if (root.privacyStory && !req.postParams.privacy) {
throw Error(gettext('Please accept the data privacy statement.'));
}
User.login(session.data.login);
session.data.login = null;
session.user.accepted = Date.now();
res.message = gettext('Welcome to {0}, {1}. Have fun!', res.handlers.site.getTitle(), session.user.name);
res.redirect(User.getLocation() || this._parent.href());
} catch (err) {
res.message = err.toString();
}
}
res.data.title = gettext('Updated Terms &amp; Conditions');
res.data.body = this.renderSkinAsString('$Members#accept');
res.handlers.site.renderSkin('Site#page');
};
/**
*
* @param {String} searchString
@ -355,7 +423,7 @@ Members.prototype.search = function(searchString, limit) {
Members.prototype.addMembership = function(data) {
var user = root.users.get(data.name);
if (!user) {
throw Error(gettext('Sorry, your input did not match any registered user.'));
throw Error(gettext('Sorry, your input did not match any registered account.'));
/*} else if (this.get(data.name)) {
throw Error(gettext('This user is already a member of this site.'));*/
}

View file

@ -70,6 +70,7 @@
<textarea class='uk-width-1-1' rows="15" class="formText" wrap="virtual" name="text"><% request.text encoding="form" %></textarea>
</div>
</div>
<% param.captcha prefix="<div class='uk-form-row'>" suffix='</div>' %>
<div class='uk-form-row'>
<button class='uk-button uk-button-primary' type="submit" id="submit" name="send" value="1" tabindex=4>
<% gettext Send %>

View file

@ -192,21 +192,30 @@ Membership.prototype.contact_action = function() {
if (!req.postParams.text) {
throw Error(gettext('Please enter the message text.'));
}
Captcha.verify(req.postParams);
this.notify(req.action, this.creator.email, session.user ?
gettext('[{0}] Message from user {1}', root.title, session.user.name) :
gettext('[{0}] Message from anonymous user', root.title));
gettext('[{0}] Message from {1}', root.title, session.user.name) :
gettext('[{0}] Message from anonymous', root.title));
res.message = gettext('Your message was sent successfully.');
res.redirect(this._parent.getPermission() ?
this._parent.href() : this.site.href());
this._parent.href() :
this.site.href());
} catch(ex) {
res.message = ex;
app.log(ex);
}
}
const param = { captcha: Captcha.render(res.handlers.members) };
res.data.action = this.href(req.action);
res.data.title = gettext('Contact {0}', this.name);
res.data.body = this.renderSkinAsString('$Membership#contact');
res.data.body = this.renderSkinAsString('$Membership#contact', param);
this.site.renderSkin('Site#page');
return;
}
@ -272,7 +281,7 @@ Membership.prototype.notify = function(action, recipient, subject) {
* @returns {String}
*/
Membership.prototype.getConfirmText = function() {
return gettext('You are about to delete the membership of user {0}.',
return gettext('You are about to delete the membership of {0}.',
this.creator.name);
}

View file

@ -12,7 +12,7 @@
<% #login %>
<div class='uk-margin-left uk-text-small uk-text-muted'>
<% gettext "You are not logged in" %>
<% if <% site.members.link login %> is null then '' else <% gettext "You are not logged in" %> %>
</div>
<ul class='uk-nav uk-nav-side'>
<li><% site.members.link login <% gettext Login context=verb prefix="<i class='uk-icon-sign-in'></i> " %> %></li>

View file

@ -1,221 +0,0 @@
// The Antville Project
// http://code.google.com/p/antville
//
// Copyright 20012014 by the Workers of Antville.
//
// Licensed under the Apache License, Version 2.0 (the ``License'');
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an ``AS IS'' BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Defines a Metadata prototype.
* @requires Object.js module
*/
// Resolve dependencies
app.addRepository("modules/core/Object.js");
Metadata.PREFIX = Metadata().__name__.toLowerCase() + "_";
/**
* This prototype provides dynamic database records by storing data as
* JavaScript object source (similar to JSON) in a dedicated database column.
* @name Metadata
* @constructor
*/
// Save internal methods for good
/** @ignore */
Metadata.prototype._get = Metadata.prototype.get;
/** @ignore */
Metadata.prototype._set = Metadata.prototype.set;
/**
* Retrieves the name of the property that contains the data for the
* Metadata instance. The name is constructed out of the instances's mountpoint
* and the suffix "_data".
* @returns {String} The resulting value
*/
Metadata.prototype.getDataSourceName = function() {
return Metadata.PREFIX + "source";
}
/**
* Retrieves the properties and values of a Metadata instance from the parent
* node.
* @returns {Object}
*/
Metadata.prototype.load = function() {
return eval(this._parent[this.getDataSourceName()]);
}
/**
* Copies the properties and values of a Metadata instance to the parent
* node.
*/
Metadata.prototype.save = function() {
var ref = this.cache.data || {};
this._parent[this.getDataSourceName()] = ref.toSource();
return;
}
/**
* Retrieves the value of a property of a Metadata instance. If no argument
* is given the complete metadata structure is returned.
* @param {String} key The name of the desired property
* @returns {Object} The resulting value
*/
Metadata.prototype.get = function(key) {
if (this.cache.data == null) {
this.cache.data = this.load() || {};
}
if (arguments.length < 1) {
return this.cache.data;
}
var value = this.cache.data[key];
if (value !== undefined) {
return value;
}
return null;
}
/**
* Copies a value into a property of a Metadata instance. If the first
* argument is omitted the complete metadata is replaced with the second
* argument.
* @param {String} key The name of the desired property
* @param {Object} value The future value of the property
*/
Metadata.prototype.set = function(key, value) {
if (arguments.length > 1) {
// Coerce Java classes into String prototypes
if (value && !value.constructor) {
value = String(value);
}
this.get()[key] = value;
} else if (arguments.length > 0) {
value = arguments[0];
if (value instanceof Object === false) {
value = value.clone({});
}
this.cache.data = value;
}
this.save();
return;
}
/**
* Removes a property from a Metadata instance.
* @param {String} key The name of the desired property
*/
Metadata.prototype.remove = function(key) {
delete this.cache.data[key];
this.save();
return;
}
/**
* Removes all properties and values from a Metadata instance.
*/
Metadata.prototype.destroy = function() {
delete this.cache.data;
this.save();
return;
}
/**
* Get all valid keys of a Metadata instance.
* @returns {String[]} The list of valid keys
*/
Metadata.prototype.keys = function() {
var cache = this.get();
var keys = [];
for (var i in cache) {
keys.push(i);
}
return keys;
}
/**
* Retrieves the number of properties contained in a Metadata instance.
* @returns {Number} The size of a Metadata instance
*/
Metadata.prototype.size = function() {
return this.keys().length;
}
/**
* Concatenates a string representation of a Metadata instance.
* @returns {String} A string representing a Metadata object
*/
Metadata.prototype.toString = function() {
res.push();
var keys = this.keys();
res.write("[Metadata (");
if (keys.length < 1) {
res.write("empty");
} else {
res.write(keys.length);
res.write(" element");
if (keys.length > 1) {
res.write("s");
}
}
res.write(")]");
return res.pop();
}
/**
* Concatenates the source of the underlying HopObject of a Metadata
* instance. Useful for debugging purposes.
* @returns {String} The source of the underlying HopObject
*/
Metadata.prototype.toSource = function() {
return this.get().toSource();
}
/**
* Retrieves all properties and values of a Metadata instance.
* @returns {Object} The property map of a Metadata instance
* @deprecated Use get() with no arguments instead
*/
Metadata.prototype.getData = function() {
return this.get();
}
/**
* Replaces all properties and values of a Metadata instance with those of
* another object.
* @param {Object} obj The replacing data
* @deprecated Use set() with a single argument instead
*/
Metadata.prototype.setData = function(obj) {
obj && this.set(obj);
return;
}
// FIXME: This is Antville-specific code and should be removed from here
Metadata.prototype.getFormValue = function(name) {
if (req.isPost()) {
return req.postParams[name];
} else {
return this.get(name) || req.queryParams[name] || String.EMPTY;
}
}
/**
*
* @param {String} name
* @returns {HopObject}
*/
Metadata.prototype.onUnhandledMacro = function(name) {
return this.get(name);
}

View file

@ -84,7 +84,7 @@
<% poll.link . ' ' class='uk-icon-button uk-icon-link uk-text-middle' %>
</h1>
<div class='uk-article-meta'><% poll.skin $HopObject#meta %></div>
<form class='uk-margin-top uk-form uk-form-stacked' method="post" action="<% response.action %>">
<form class='uk-margin-top uk-form uk-form-stacked' method="post" action="<% response.action %>" x-data='{ counter: 2 }'>
<div class='uk-form-row'>
<div class='uk-form-label'><% gettext Question %></div>
<div class='uk-form-controls'>
@ -94,8 +94,8 @@
<fieldset class='uk-margin-top'>
<legend><% gettext Choices %></legend>
<% poll.input choices %>
<div class='uk-text-small uk-form-row uk-hidden' id='av-add-choice'>
<a href='javascript:'>
<div class='uk-text-small uk-form-row' id='av-add-choice' hidden :hidden='false'>
<a href='javascript:' @click='const choice = document.querySelectorAll(".av-choice")[counter - 1]; const clone = choice.cloneNode(true); counter += 1; clone.querySelector(".uk-form-label").innerText = "#" + counter; const input = clone.querySelector("input"); input.value = ""; choice.insertAdjacentElement("afterEnd", clone); input.focus();'>
<i class='uk-icon-plus'></i>
<% gettext "Add Choice" %>
</a>
@ -120,15 +120,3 @@
<a href='.' class='uk-button uk-button-link'><% gettext Cancel %></a>
</div>
</form>
<script type="text/javascript">
var index = $(".av-choice").length + 1;
$("#av-add-choice").removeClass('uk-hidden').find('a').on('click', function (event) {
event.preventDefault();
var choice = $(".av-choice:last").clone();
choice.find(".uk-form-label").text('#' + index);
choice.find("input").attr("value", '');
$(".av-choice:last").after(choice);
$(".av-choice:last").find("input").focus();
index += 1;
});
</script>

View file

@ -5,8 +5,8 @@
<label class='uk-form-label' for='name'>
<% gettext Name %> <i class='uk-icon uk-icon-info-circle uk-text-muted' data-uk-tooltip title="<% gettext "Please note that you cannot change the name after the site was created." %>"></i>
</label>
<div class='uk-form-controls'>
<% newSite.input name class=uk-form-width-medium maxlength=25 tabindex=1 %>
<div class='uk-form-controls' x-data="{ name: '' }">
<% newSite.input name class=uk-form-width-medium maxlength=25 tabindex=1 x-model="name" %>
<div class='uk-form-help-inline'>
<% gettext 'The name will be part of the URL of your site.' %>
</div>
@ -60,13 +60,15 @@
<% #error %>
<h1><% gettext Sorry! %></h1>
<p><% gettext "An error occurred while processing your request." %></p>
<pre class='uk-text-break'><% session.error default=<% param.error %> %></pre>
<div class='uk-alert uk-alert-danger'>
<p class='uk-text-break'><% response.error %></p>
</div>
<% #health %>
<h1><% response.title %></h1>
<div class='uk-panel uk-panel-header'>
<h3 class='uk-panel-title'><% gettext Status %></h3>
<% site.skin Root#status %>
<p><% site.skin Root#status %></p>
</div>
<div class='uk-panel uk-panel-header'>
<h3 class='uk-panel-title'><% gettext Details %></h3>
@ -116,7 +118,9 @@
<dd><% version %></dd>
<dt><% gettext Build %></dt>
<dd>
<% link <% version hash prefix='https://github.com/antville/antville/commit/' %> <% version hash %> %> (<% version date | format date medium %>)
<% link <% version hash prefix='https://github.com/antville/antville/commit/' %> <% version hash %> %> (<% version date %>)
</dd>
<dt><% gettext 'Helma Version' %></dt>
<dd><% param.helma %></dd>
</dl>
</div>

View file

@ -20,7 +20,7 @@
*/
/** @constant */
Root.VERSION = (function (versionString, buildDate) {
Root.VERSION = (function(versionString, buildDate) {
// A valid version string is e.g. '1.2.3alpha.c0ffee'.
// Repositories could add something like '-compatible' to it,
// FIXME: This should be refactored for modular extension.
@ -32,7 +32,7 @@ Root.VERSION = (function (versionString, buildDate) {
toString: function() {return parts[0]},
major: parseInt(parts[1]),
hash: parts[5],
date: new Date(buildDate)
date: new Date(buildDate).toLocaleDateString()
};
result.minor = result.major + parseInt(parts[2] || 0) / 10;
result.bugfix = result.minor + '.' + (parts[3] || 0);
@ -42,17 +42,20 @@ Root.VERSION = (function (versionString, buildDate) {
return result;
}
return versionString;
})('<v>0</v>.<h>0</h>', '<d/>');
})(getProperty('version', '0.0.0'), getProperty('buildDate', '18 Oct 1971'));
this.handleMetadata('creationDelay');
this.handleMetadata('creationScope');
this.handleMetadata('loginScope');
this.handleMetadata('notificationScope');
this.handleMetadata('phaseOutGracePeriod');
this.handleMetadata('phaseOutNotificationPeriod');
this.handleMetadata('phaseOutMode');
this.handleMetadata('privacyStory');
this.handleMetadata('probationPeriod');
this.handleMetadata('quota');
this.handleMetadata('replyTo');
this.handleMetadata('termsStory');
/**
* Antvilles Root prototype is an extent of the Site prototype.
@ -87,7 +90,10 @@ Root.prototype.getPermission = function(action) {
if (action && action.contains('admin')) {
return User.require(User.PRIVILEGED);
}
switch (action) {
case '.':
case 'main':
case 'debug':
case 'default.hook':
case 'favicon.ico':
@ -98,19 +104,26 @@ Root.prototype.getPermission = function(action) {
case 'sites':
case 'updates.xml':
return true;
case 'create':
return this.getCreationPermission();
}
return Site.prototype.getPermission.apply(this, arguments);
}
Root.prototype.main_action = function() {
if (this.users.size() < 1) {
this.title = 'Antville';
// Be sure all site properties are up-to-date
this.update(this);
this.created = this.modified = new Date;
this.replyTo = 'root@localhost';
this.creationScope = Admin.PRIVILEGED;
this.locale = java.util.Locale.getDefault().getLanguage();
this.loginScope = Admin.PRIVILEGED;
this.phaseOutMode = Admin.DISABLED;
this.replyTo = 'root@localhost';
this.timeZone = java.util.TimeZone.getDefault().getID();
this.title = 'Antville';
this.layout.reset();
res.redirect(this.members.href('register'));
} else if (session.user && this.members.owners.size() < 1) {
@ -124,10 +137,9 @@ Root.prototype.main_action = function() {
Root.prototype.error_action = function() {
res.message = String.EMPTY;
var param = res.error ? res : session.data;
res.status = param.status || 500;
res.data.title = gettext('{0} {1} Error', root.getTitle(), param.status);
res.data.body = root.renderSkinAsString('$Root#error', param);
res.status = res.status || 500;
res.data.title = gettext('{0} {1} Error', root.getTitle(), res.status);
res.data.body = root.renderSkinAsString('$Root#error');
res.handlers.site.renderSkin('Site#page');
return;
}
@ -136,7 +148,9 @@ Root.prototype.notfound_action = function() {
res.status = 404;
res.data.title = gettext('{0} {1} Error', root.getTitle(), res.status);
res.data.body = root.renderSkinAsString('$Root#notfound', req);
res.handlers.site.renderSkin('Site#page');
let site = res.handlers.site;
if (site.status === Site.DELETED) site = root;
site.renderSkin('Site#page');
return;
}
@ -210,7 +224,7 @@ Root.prototype.updates_xml_action = function() {
entry.setPublishedDate(story.modified);
description = new rome.SyndContentImpl();
description.setType('text/plain');
description.setValue(story.format_filter(story.text, {}));
description.setValue(story.format_filter(story.text, {}, 'markdown'));
entry.setDescription(description);
entries.add(entry);
}
@ -251,7 +265,8 @@ Root.prototype.health_action = function() {
totalMemory: formatNumber(totalMemory),
usedMemory: formatNumber(totalMemory - freeMemory),
sessions: formatNumber(app.countSessions()),
cacheSize: formatNumber(getProperty('cacheSize'))
cacheSize: formatNumber(getProperty('cacheSize')),
helma: Packages.helma.main.Server.getServer().version
};
for each (key in ['activeThreads', 'freeThreads', 'requestCount',
@ -356,6 +371,8 @@ Root.prototype.getFormOptions = function(name) {
switch (name) {
case 'creationScope':
return Admin.getCreationScopes();
case 'loginScope':
return Admin.getLoginScopes();
case 'notificationScope':
return Admin.getNotificationScopes();
case 'phaseOutMode':

View file

@ -2,16 +2,7 @@
<% gettext 'System is up and running.' %>
<% #urlPreview %>
<a id='av-site-url-preview'></a>
<script type='text/javascript'>
$('#name').on('keyup', function (event) {
var name = $(this).val();
if (name) {
var url = '<% root.href %>' + name;
var html = '<% root.href %>' + '<b>' + name + '</b>';
$('#av-site-url-preview').html(html).attr('href', url);
} else {
$('#av-site-url-preview').html(name);
}
});
</script>
<% // This snippet contains additional markup to be rendered client-side by Alpine %>
<a :href='"<% root.href %>" + name'>
<strong x-show='name' x-text='"<% root.href %>" + name'></strong>
</a>

View file

@ -22,13 +22,15 @@
<% #navigation %>
<li><% root.link main <% gettext Start prefix="<i class='uk-icon-home'></i> " %> %></li>
<li><% root.link sites <% gettext Sites %> %></li>
<li><% root.link sites <% gettext 'Public Sites' %> %></li>
<% story <% root.termsStory %> link text=<% gettext "Terms and Conditions" %> prefix=<li> suffix=</li> %>
<% story <% root.privacyStory %> link text=<% gettext "Data Privacy Statement" %> prefix=<li> suffix=</li> %>
<li><% root.link contact <% gettext Contact %> %></li>
<li class='uk-nav-divider'></li>
<% root.admin.skin $Admin#navigation suffix="<li class='uk-nav-divider'></li>" %>
<li><% root.link health <% gettext Health prefix="<i class='uk-icon-stethoscope'></i> " %> %></li>
<li><% root.api.link main <% gettext API %> %></li>
<li><% link //project.antville.org <% gettext Development %> %></li>
<li><% link https://project.antville.org <% gettext Development %> %></li>
<li class='uk-nav-divider'></li>
<% root.link edit <% gettext Settings prefix="<i class='uk-icon-cog'></i> " %> prefix=<li> suffix=</li> %>
<% root.layout.link main <% gettext Layout %> prefix=<li> suffix=</li> %>

View file

@ -12,6 +12,7 @@
<% #edit %>
<h1><% response.title %></h1>
<div class='uk-article-meta'>
<% if <% this.creator %> is null then '' else
<% gettext 'Created by {0} on {1}' <% this.creator %> <% this.created short %> %>
@ -20,46 +21,60 @@
<% gettext 'Last modified by {0} on {1}' <% this.modifier %> <% this.configured | format short date %> prefix=<br> %>
%>
</div>
<div class='uk-margin-top uk-margin-bottom'>
<% site.link export <% gettext Export %> %>
</div>
<form class='uk-form uk-form-stacked' id="edit" method="post" action="<% response.action %>">
<fieldset>
<div class='uk-form-row uk-margin-top'>
<div class='uk-form-row'>
<label class='uk-form-label' for='mode'>
<% gettext Mode %>
</label>
<div class='uk-form-controls'>
<% site.select mode %>
</div>
</div>
<div class='uk-form-row'>
<label class='uk-form-label' for='title'>
<% gettext Title %>
</label>
<div class='uk-form-controls'>
<% site.input title class='uk-width-1-1' %>
</div>
</div>
<div class='uk-form-row'>
<label class='uk-form-label' for='tagline'>
<% gettext Description %>
</label>
<div class='uk-form-controls'>
<% site.input tagline class='uk-width-1-1' %>
</div>
</div>
<div class='uk-form-row'>
<label class='uk-form-label' for='pageSize'>
<% gettext Pagination %>
</label>
<div class='uk-form-controls'>
<% site.input pageSize class='uk-width-1-6' type=number min=1 max=25 %>
<% gettext "{0} per page" <% gettext "stories" %> %>
<% // site.select pageMode %>
</div>
</div>
<div class='uk-form-row'>
<label class='uk-form-label' for='commentMode'>
<% gettext Comments %>
</label>
<div class='uk-form-controls'>
<label>
<% site.checkbox commentMode %>
@ -67,10 +82,12 @@
</label>
</div>
</div>
<div class='uk-form-row'>
<label class='uk-form-label' for='archiveMode'>
<% gettext Archive %>
</label>
<div class='uk-form-controls'>
<label>
<% site.checkbox archiveMode %>
@ -78,56 +95,69 @@
</label>
</div>
</div>
<div class='uk-form-row'>
<label class='uk-form-label' for='locale'>
<% gettext Language %>
</label>
<div class='uk-form-controls'>
<% site.select locale %>
</div>
</div>
<div class='uk-form-row'>
<label class='uk-form-label' for='timeZone'>
<% gettext 'Time Zone' %>
</label>
<div class='uk-form-controls'>
<% site.select timeZone %>
</div>
</div>
<div class='uk-form-row'>
<label class='uk-form-label' for='notificationMode'>
<% gettext Notifications %>
</label>
<div class='uk-form-controls'>
<% site.select notificationMode %>
</div>
</div>
</fieldset>
<fieldset class='uk-margin-top'>
<legend><% gettext Advanced %></legend>
<div class='uk-form-row'>
<label class='uk-form-label' for='maxImageWidth'>
<% gettext 'Image Dimension Limits' %>
<i class='uk-icon-info-circle uk-text-muted' title='<% gettext "If you want to resize the image please specify your desired maximum width and/or maximum height in pixels. If you specify both the image will be resized to match both criterias, but the image ratio will be preserved. If the width or height of your image exceeds 100 pixels Antville automatically creates a thumbnail of it, too." %> ' data-uk-tooltip='{pos: "right"}'></i>
</label>
<div class='uk-form-controls'>
<% site.input maxImageWidth type='number' min=1 class='uk-form-width-small' %>
&times;
<% site.input maxImageHeight type='number' min=1 class='uk-form-width-small' %> <% gettext Pixels %>
</div>
</div>
<div class='uk-form-row'>
<label class='uk-form-label' for='trollFilter'>
<% gettext 'Troll Filter' %>
</label>
<div class='uk-form-controls'>
<% site.textarea trollFilter rows=5 class='uk-width-1-1' %>
</div>
</div>
<div class='uk-form-row'>
<label class='uk-form-label' for='spamfilter' >
<% gettext 'Referrer Filter' %>
</label>
<div class='uk-form-controls'>
<% site.textarea spamfilter rows=5 class='uk-width-1-1' %>
<p class="uk-form-help-block">
@ -135,86 +165,100 @@
</p>
</div>
</div>
<div class='uk-form-row'>
<label class='uk-form-label' for='callbackUrl'>
<% gettext 'Callback URL' %>
</label>
<div class='uk-form-controls'>
<% site.input callbackUrl type=url class='uk-width-1-1' %>
<div class='uk-form-controls' x-data='{ callbackMode: false }'>
<% site.input callbackUrl type=url class='uk-width-1-1' :disabled='!callbackMode' %>
<label>
<% site.checkbox callbackMode %>
<% site.checkbox callbackMode x-model='callbackMode' %>
<% gettext enabled %>
</label>
</div>
</div>
<div class='uk-form-row'>
<label class='uk-form-label'>
<% gettext Bookmarklet %>
</label>
<div class='uk-form-controls'>
<a class='uk-button' data-uk-tooltip='{pos: "right"}' href="javascript: var siteUrl = '<% site.href %>'; var selection = (window.getSelection) ? window.getSelection() : document.selection.createRange(); selection = selection.text || selection; selection = selection + ''; var url='<% root.static %>../../formica.html?s=' + encodeURIComponent(siteUrl) + '&amp;l=' + encodeURIComponent(location.href) + '&amp;r=' + encodeURIComponent(document.referrer) + '&amp;w=400&amp;h=400&amp;c=' + encodeURIComponent(selection || document.title); window.open(url, 'formica', 'width=630, height=350'); void 0;" title="<% gettext 'Drag to Bookmarks Bar' %>"><% gettext "Post to {0}" <% site.title %> %></a>
<a class='uk-button' data-uk-tooltip='{ pos: "right" }' href="javascript: void (() => { const F = { '🍪': '', '🐜': '<% root.static %>../../formica.html', '🎯': '<% site.href %>', '🌐': '<% root.href %>', '📝': window.getSelection ? window.getSelection() : document.selection.createRange() }; F['📝'] = '' + (F['📝'].text || F['📝']); F['🐜'] += '?s=' + encodeURIComponent(F['🎯']) + '&amp;l=' + encodeURIComponent(location.href) + '&amp;r=' + encodeURIComponent(document.referrer) + '&amp;k=' + encodeURIComponent(F['🍪']) + '&c=' + encodeURIComponent(F['📝']) + '&b=' + encodeURIComponent(F['🌐']); window.open(F['🐜'], '🐜', 'width=650, height=350'); })()" title="<% gettext 'Drag to Bookmarks Bar' %>"><% gettext "Post to {0}" <% site.title %> %></a>
</div>
</div>
<div class='uk-form-row'>
<label class='uk-form-label'>
<% gettext 'Disk Space' %>
</label>
<div class='uk-form-controls'>
<% site.diskspace %>
</div>
</div>
</fieldset>
<% site.skin $Site#admin restricted=true %>
<div class='uk-margin-top'>
<button class='uk-button uk-button-primary' type="submit" id="submit" name="save" value="1">
<% gettext Save %>
</button>
<% site.link delete <% gettext Delete %> class='uk-button' %>
<a href='<% site.href %>' class="uk-button uk-button-link"><% gettext Cancel %></a>
</div>
</form>
<script>
$('input#callbackMode').on('click', function(event) {
$('input#callbackUrl').prop('disabled', !this.checked);
});
$('input#callbackUrl').prop('disabled', !$('input#callbackMode').prop('checked'));
// Group related <option> elements by inserting additional <optgroup> elements.
var groups = [];
var element = $('form#edit #timeZone');
element.find('option').each(function(index, item) {
var zone = $(item);
var parts = zone.html().split('/'); // E.g. Europe/Vienna
var group = parts[0];
if ($.inArray(group, groups) < 0) {
groups.push(group);
<script>
(function() {
// Group related <option> elements by inserting additional <optgroup> elements.
const dom = window;
const groups = [];
dom.timeZone.querySelectorAll('option').forEach(function(item, index) {
const parts = item.innerHTML.split('/'); // E.g. Europe/Vienna
const group = parts[0];
if (groups.indexOf(group) < 0) {
groups.push(group);
}
});
groups.sort();
$.each(groups, function(index, group) {
var key = group + '/'; // E.g. Europe/
element.find('option:contains(' + key + ')')
.wrapAll($('<optgroup>').attr('label', group))
.each(function(index, item) {
$(item).html($(item).html().replace(key, ''));
});
});
groups.sort();
groups.forEach(function(group, index) {
const key = group + '/'; // E.g. Europe/
const optgroup = document.createElement('optgroup');
optgroup.setAttribute('label', group);
dom.timeZone.querySelectorAll('option[value^="' + key + '"]').forEach(function(option) {
option.innerHTML = option.innerHTML.replace(key, '');
optgroup.appendChild(option);
});
dom.timeZone.appendChild(optgroup);
// Correct the selected index
timeZone.selectedIndex = Array.from(timeZone.options).indexOf(timeZone.querySelector('option[selected]'));
});
})();
</script>
<% #meta %>
<meta name='description' content='<% response.description %>'>
<meta name='twitter:card' content='summary_large_image'>
<meta name='twitter:title' property='og:title' itemprop='name' content='<% response.title %>'>
<meta name='twitter:description' property='og:description' itemprop='description' content='<% response.description default=<% response.title %> %>'>
<meta property='og:type' content='<% response.type %>'>
<% // Facebook is very picky with locales (e.g. complains about 'de' and 'en_AU') %>
<% //site.locale prefix="<meta property='og:locale' content='" suffix="'>" %>
<% response.title prefix="<meta property='og:title' content='" suffix="'>" %>
<% response.description prefix="<meta property='og:description' content='" suffix="'>" %>
<meta property='og:site_name' content='<% site.title %>'>
<meta property='og:url' content='<% href %>'>
<meta name='twitter:card' content='summary'>
<% response.title prefix="<meta name='twitter:title' content='" suffix="'>" %>
<% response.description prefix="<meta name='twitter:description' content='" suffix="'>" %>
<% response.title prefix="<meta itemprop='name' content='" suffix="'>" %>
<% response.description prefix="<meta itemprop='description' content='" suffix="'>" %>
<% // Facebook is very picky with locales (e.g. complains about 'de' and 'en_AU') %>
<% //site.locale prefix="<meta property='og:locale' content='" suffix="'>" %>
<% response.images %>
<% response.videos %>
@ -225,6 +269,10 @@
<link rel='alternate' type='application/rss+xml' title='Sites of <% root.title %>' href='<% root.href updates.xml %>'>
<link rel='search' type='application/opensearchdescription+xml' href='<% site.href search.xml %>' title='<% site.title %>'>
<% #menuButton %>
<input type='checkbox' class='av-menu-toggle'>
<i class='av-menu-toggle'></i>
<% #admin %>
<a name='admin' id='admin'></a>
<fieldset class='uk-margin-top'>
@ -285,6 +333,13 @@
<dl class='uk-description-list-line'>
<% response.result %>
</dl>
<% if <% property search.provider %> is null then '' else <% site.skin $Site#moreResults %> %>
<% #moreResults %>
<a href='<% property search.provider %>?q=<% request.q %>+site:<% site.href %>' class='uk-button uk-align-right'>
<% gettext 'Search with {0}' <% property search.provider | replace 'https?://([^/]+).*' '$1' %> %>
<i class='uk-icon uk-icon-arrow-circle-right'></i>
</a>
<% #opensearchdescription %>
<?xml version="1.0" encoding="UTF-8"?>
@ -297,52 +352,6 @@
<Query role="example" searchTerms="cat" />
</OpenSearchDescription>
<% #page %>
<!DOCTYPE html>
<html <% site.locale prefix='lang=' %>>
<head>
<meta charset='utf-8'>
<title><% response.title %></title>
<link rel='icon' type='image/x-icon' href='<% image /favicon.png url %>'>
<link rel='shortcut icon' type='image/x-icon' href='<% image /favicon.png url %>'>
<link rel='search' type='application/opensearchdescription+xml' href='<% site.href search.xml %>' title='<% site.title %>'>
<link rel='alternate' type='application/rss+xml' title='Stories and comments of <% site.title %>' href='<% site.href rss.xml %>'>
<link rel='alternate' type='application/rss+xml' title='Stories of <% site.title %>' href='<% site.href stories.xml %>'>
<link rel='alternate' type='application/rss+xml' title='Comments of <% site.title %>' href='<% site.href comments.xml %>'>
<link rel='alternate' type='application/rss+xml' title='Sites of <% root.title %>' href='<% root.href updates.xml %>'>
<link rel='stylesheet' type='text/css' href='<% root.href main.css %>'>
<script type='text/javascript' src='<% root.href main.js %>'></script>
</head>
<body class='uk-container-center av-page'>
<body class='uk-container-center av-page'>
<% site.skin $Site#header %>
<div class='uk-grid'>
<div class='uk-width-7-10'>
<% response.message prefix="<div class='uk-alert' data-uk-alert>" suffix=</div> %>
<% response.body %>
</div>
<div class='uk-width-3-10'>
<div class='uk-margin-large-left av-border-left'>
<% membership.status %>
<ul class='uk-nav uk-nav-side'>
<li class='uk-nav-divider'/>
<% site.skin Site#navigation %>
<li class='uk-nav-divider'/>
<li class='uk-margin-left'>
<% site.skin Site#search %>
</li>
<li class='uk-nav-header'/>
<li class='uk-margin-left uk-text-small'>
<% site.calendar %>
</li>
</ul>
</div>
</div>
</div>
<% site.skin $Site#footer %>
</body>
</html>
<% #header %>
<header class='av-header <% if <% site.id %> is <% root.id %> then 'av-root-site' %>'>
<div class='av-header-bg-chaos'></div>
@ -360,36 +369,30 @@
<footer>
<hr class='uk-margin-large-top'>
<div class='uk-text-small uk-margin-bottom uk-float-left'>
<div><% gettext 'Created {0}' <% site.created text %> %>.</div>
<div><% gettext 'Last modified {0}' <% site.modified text %> %>.</div>
<div><% if <% site.created %> then <% gettext 'Created {0}' <% site.created text %> %> suffix=. %></div>
<div><% if <% site.modified %> then <% gettext 'Last modified {0}' <% site.modified text %> %> suffix=. %></div>
</div>
<div class='uk-text-right'>
<% image /smallchaos.gif | link http://antville.org %> &
<% image /smallchaos.gif | link https://antville.org %> &
<% image /helma.png | link http://helma.org %>
</div>
</footer>
<% #javascript %>
$(function () {
// Unhide hidden links triggering JavaScript
$('a[href="javascript:"]:hidden').css('display', 'inline-block');
// Injecting main.css if necessary for compatibility reasons
if (!document.querySelector('link[href="<% site.href main.css %>"]')) {
var link = document.createElement('link');
link.href = '<% site.href main.css %>';
link.rel = 'stylesheet';
link.type = 'text/css';
document.head.appendChild(link);
}
});
// Injecting main.css if necessary for compatibility reasons
if (!document.querySelector('link[href="<% site.href main.css %>"]')) {
const link = document.createElement('link');
link.href = '<% site.href main.css %>';
link.rel = 'stylesheet';
document.head.appendChild(link);
}
<% site.skin Site#javascript | script %>
<% #include %>
(function (url) {
var script = document.createElement('script');
script.type = 'text/javascript';
// The void operator is necessary or we get some wicked error from browserify(?)
void (function(url) {
const script = document.createElement('script');
script.src = url;
document.head.appendChild(script);
})('<% param.href %>');
@ -400,7 +403,7 @@ $(function () {
// FIXME: compatibility
@base-font: <% value 'base font' default='Helvetica Neue, Helvetica, Arial, sans-serif' %>;
@base-font-size: <% value 'base font size' default="'14px / 20px'" %>;
@base-font-size: <% value 'base font size' default="14px e('/') 20px" %>;
@base-font-color: <% value 'base font color' default=#444 %>;
@big-font: <% value 'big font' default=@base-font %>;
@ -435,6 +438,11 @@ html, html.uk-notouch, body {
font-family: @text-font;
}
body.av-16, body.av-page {
max-width: 900px;
margin: auto 5%;
}
h1, h2, h3, h4, h5, h6 {
color: @title-color;
font-family: @title-font;
@ -442,9 +450,11 @@ h1, h2, h3, h4, h5, h6 {
a {
color: @link-color;
&:hover {
color: @hover-color;
}
&[href='javascript:'] {
display: none;
}
@ -458,7 +468,10 @@ em {
}
img {
max-width: initial; // FIXME: compatibility
body:not(.av-16) &, table & {
max-width: initial; // FIXME: compatibility
}
&[src$='pixel.gif'] {
width: initial;
height: initial;
@ -477,8 +490,12 @@ hr {
color: @muted-color !important;
}
.uk-table-striped tbody tr:hover, .uk-table-striped tbody tr:nth-of-type(odd) {
background: inherit;
.uk-table-striped tbody tr:nth-of-type(odd) {
background: darken(@background, 2%);
}
.uk-table-striped tbody tr:hover {
background: fadeout(@link-color, 88%);
}
.uk-button-group.av-link-group a {
@ -518,6 +535,7 @@ hr {
border-color: @link-color;
text-shadow: initial;
}
&:hover {
background-color: @background;
color: @hover-color;
@ -526,7 +544,7 @@ hr {
}
}
.uk-button:not(.uk-button-success) {
.uk-button:not(.uk-button-success):not([disabled]) {
text-shadow: initial !important;
&, &:link, &:visited {
@ -534,26 +552,32 @@ hr {
color: @text-color;
border-color: @text-color;
}
&:hover {
background-color: @background;
color: @hover-color;
border-color: @hover-color;
}
&.uk-button-link {
border: initial;
&:link, &:visited {
color: @link-color;
}
&:hover {
color: @hover-color;
}
}
&.uk-button-primary {
background-color: @background;
border-style: double;
border-color: @link-color;
color: @link-color;
font-weight: bold;
&:hover {
background: inherit;
border-color: @hover-color;
@ -562,24 +586,31 @@ hr {
}
}
&.uk-button-primary[disabled] {
font-weight: bold;
}
.uk-pagination {
& > li > a {
background: @background;
color: @link-color;
border-color: @link-color;
text-shadow: initial;
&:hover {
background: @background;
color: @hover-color;
border-color: @hover-color;
}
}
& > .uk-active > span {
background: @background;
border-color: @text-color;
color: @text-color;
font-weight: bold;
}
& > .uk-disabled > span {
background: @muted-background;
color: @muted-color;
@ -592,6 +623,7 @@ hr {
&:link, &:visited {
color: @link-color;
}
&:hover {
color: @hover-color;
}
@ -605,13 +637,16 @@ hr {
}
.uk-thumbnail img {
max-width: 100%;
body:not(.av-16) & {
max-width: 100%;
}
}
h1 a, .uk-table a {
&:visited {
color: @link-color;
}
&:hover {
color: @hover-color;
}
@ -628,7 +663,23 @@ h1 a, .uk-table a {
width: 100%;
}
.uk-form select, .uk-form textarea, .uk-form input:not([type]), .uk-form input[type="text"], .uk-form input[type="password"], .uk-form input[type="datetime"], .uk-form input[type="datetime-local"], .uk-form input[type="date"], .uk-form input[type="month"], .uk-form input[type="time"], .uk-form input[type="week"], .uk-form input[type="number"], .uk-form input[type="email"], .uk-form input[type="url"], .uk-form input[type="search"], .uk-form input[type="tel"], .uk-form input[type="color"] {
.uk-form select,
.uk-form textarea,
.uk-form input:not([type]),
.uk-form input[type="text"],
.uk-form input[type="password"],
.uk-form input[type="datetime"],
.uk-form input[type="datetime-local"],
.uk-form input[type="date"],
.uk-form input[type="month"],
.uk-form input[type="time"],
.uk-form input[type="week"],
.uk-form input[type="number"],
.uk-form input[type="email"],
.uk-form input[type="url"],
.uk-form input[type="search"],
.uk-form input[type="tel"],
.uk-form input[type="color"] {
border-color: @border-color;
}
@ -638,7 +689,7 @@ h4 + .uk-comment-meta li:first-child {
}
.av-page {
width: 900px; // FIXME: Could we use the `vw` unit already?
overflow: auto;
}
.av-sprite {
@ -651,8 +702,9 @@ h4 + .uk-comment-meta li:first-child {
margin: 0 0 -2px -2px;
width: 15px;
height: 15px;
background: url(/static/img/ant.svg);
background-image: url(/static/img/ant.svg);
background-size: 15px 15px;
background-repeat: no-repeat;
}
.av-border-left {
@ -740,8 +792,10 @@ h4 + .uk-comment-meta li:first-child {
.av-collage {
padding: 0;
.av-tagged-image {
opacity: 0;
img {
max-width: 100%;
display: inline-block;
@ -750,6 +804,7 @@ h4 + .uk-comment-meta li:first-child {
vertical-align: bottom;
opacity: 1;
}
.Caption_Content {
color: #fff;
padding: 10px;
@ -780,10 +835,10 @@ h4 + .uk-comment-meta li:first-child {
}
.av-header-bg-dots {
margin-left: 222px;
position: relative;
top: -46px;
width: 900px - 274px + 54px;
margin-left: 222px;
margin-right: -5.6%;
height: 38px;
background: url('<% image /dot.gif url %>');
}
@ -791,11 +846,17 @@ h4 + .uk-comment-meta li:first-child {
.av-title {
position: absolute;
top: 13px;
overflow: visible;
width: 100%;
height: 100%;
overflow-x: hidden;
white-space: nowrap;
font-family: Verdana, Helvetica, Arial, sans-serif;
font-size: 25px;
font-weight: bold;
img {
max-width: initial;
}
}
// The root site gets the beautiful logo with ant animation
@ -807,6 +868,68 @@ h4 + .uk-comment-meta li:first-child {
}
}
.av-menu {
& .av-menu-toggle {
display: none;
}
}
@media (max-width: 767px) {
.av-menu {
@top: 14px;
@right: 5%;
@size: 30px;
i.av-menu-toggle {
.av-ant;
padding: 2px;
border-radius: 100%;
background-color: fadeout(@background, 20%);
background-size: @size @size;
background-position: 2px 2px;
}
i.av-menu-toggle,
input.av-menu-toggle {
display: initial;
position: absolute;
top: @top;
right: @right;
width: @size;
height: @size;
margin-right: 2px;
}
input.av-menu-toggle {
z-index: 9;
opacity: 0;
&:checked {
position: fixed;
width: 100%;
height: 100%;
& ~ .av-navigation {
display: initial;
}
}
}
.av-navigation {
display: none;
position: fixed;
top: 0;
right: 0;
bottom: 0;
z-index: 10;
padding: 10pt 10pt 10pt 0;
background-color: fadeout(@background, 10%);
box-shadow: -5px 0 5px 0 @border-color;
overflow: auto;
}
}
}
.av-skin-active {
background: #fff;
opacity: .25;
@ -841,6 +964,11 @@ h4 + .uk-comment-meta li:first-child {
text-decoration: none !important;
}
.av-rtl {
unicode-bidi: bidi-override;
direction: rtl;
}
// Overwriting some Helma and Jala classes for debugging and calendar integration
.helma-debug-line /*:has(script)*/ {
@ -849,6 +977,7 @@ h4 + .uk-comment-meta li:first-child {
.jala-calendar {
width: 100%;
max-width: 200px;
text-align: center;
tbody th {
@ -1000,15 +1129,14 @@ a.gs-title:hover {
<% response.list %>
</tbody>
</table>
<script type="text/javascript">
$('.av-referrers').addClass('uk-hidden');
$('.av-referrer-control a').removeClass('uk-hidden');
var query = new Antville.Query();
var spamFilter = new Antville.Filter([<% site.spamfilter %>]);
var searchFilter = new Antville.Filter(query.filter);
<script>
(function() {
const query = new Antville.Query();
const spamFilter = new Antville.Filter(JSON.parse('<% site.spamfilter %>'));
const searchFilter = new Antville.Filter(query.filter);
var searchEngineFilters = [
const searchEngineFilters = [
new Antville.Filter('//.*altavista.*/\\?', 'q'),
new Antville.Filter('//.*baidu.com/s\\?', 'wd'),
new Antville.Filter('//.*bing\\..*/search\\?', 'q'),
@ -1019,10 +1147,9 @@ a.gs-title:hover {
new Antville.Filter('//.*search\\.yahoo\\..*/\\?', 'p'),
new Antville.Filter('//.*search\\.ask\\.com/web\\?', '1'),
new Antville.Filter('//.*yandex\\..*/\\?', 'text')
];
];
var urlShortenerCounter = 0;
var urlShortenerFilters = [
const urlShortenerFilters = [
new Antville.Filter('//.*baidu.com/link'),
new Antville.Filter('//bit\\.ly/'),
new Antville.Filter('//.*duckduckgo.com/l/\\?'),
@ -1035,94 +1162,90 @@ a.gs-title:hover {
new Antville.Filter('//tinyurl\\.com/'),
new Antville.Filter('//.*stumbleupon\\.com/refer\\.php\\?'),
new Antville.Filter('//.*search\\.yahoo\\..*/.+/RU=')
];
];
$('.av-referrer-row').each(function (index) {
var row = $(this);
var ref = row.find('.av-referrer a');
var url = ref.attr('href');
var count = row.find('.av-referrer-count').html();
var control = row.find('.av-referrer-control a');
let urlShortenerCounter = 0;
control.on('click', function (event) {
event.preventDefault();
var input = prompt("<% gettext 'Are you sure you want to add this URL to the referrer filter? Edit it below to filter a pattern only.' %>", url);
if (input) {
location.href = '<% site.href referrers %>?submit=1&permanent=' + encodeURIComponent(input);
}
document.querySelectorAll('.av-referrer-row').forEach(function(row) {
const ref = row.querySelector('.av-referrer a');
const url = ref.getAttribute('href');
const count = row.querySelector('.av-referrer-count').innerText;
const control = row.querySelector('.av-referrer-control a');
const referrer = new Antville.Referrer(url, url, count);
ref.innerHTML = referrer.text;
control.addEventListener('click', function(event) {
event.preventDefault();
const input = prompt("<% gettext 'Are you sure you want to add this URL to the referrer filter? Edit it below to filter a pattern only.' %>", url);
if (!input) return;
location.href = '<% site.href referrers %>?submit=1&permanent=' + encodeURIComponent(input);
});
var referrer = new Antville.Referrer(url, url, count);
ref.html(referrer.text);
if (spamFilter.test(url)) {
if (query.includeSpam) {
ref.addClass('uk-text-muted');
control.remove();
} else {
row.remove();
}
if (query.includeSpam) {
ref.classList.add('uk-text-muted');
control.remove();
} else {
row.remove();
}
}
if (query.filter && !searchFilter.test(url)) {
row.remove();
row.remove();
}
var re = new RegExp('[:/].*$');
const re = new RegExp('[:/].*$');
for (var i = 0, filter; i < searchEngineFilters.length; i += 1) {
filter = searchEngineFilters[i];
if (filter.test(url)) {
var host = referrer.text.replace(re, '');
ref.html(referrer.compose('<i><% gettext Search %>:</i>', filter.key));
return;
}
}
for (var i = 0, filter; i < urlShortenerFilters.length; i += 1) {
filter = urlShortenerFilters[i];
if (filter.test(url)) {
urlShortenerCounter += parseInt(count, 10);
var host = referrer.text.replace(re, '');
var url = referrer.url.replace(new RegExp('^(.+//[^/]+).*'), '$1');
ref.attr('href', url).html(host);
return;
}
}
});
$('.av-referrer a').each(function (index) {
var html = $(this).html();
var countElement = $('.av-referrer-count').eq(index);
var count = 0;
$('.av-referrer a').each(function (index2) {
if (index2 <= index) return;
if ($(this).html() === html) {
count += parseInt($('.av-referrer-count').eq(index2).html(), 10);
$(this).parents('.av-referrer-row').addClass('av-delete');
}
searchEngineFilters.forEach(function(filter) {
if (filter.test(url)) {
const host = referrer.text.replace(re, '');
ref.innerHTML = referrer.compose('<i><% gettext Search %>:</i>', filter.key);
}
});
if (count) {
countElement.html(parseInt(countElement.html(), 10) + count);
}
});
$('.av-referrer-row.av-delete').remove();
urlShortenerFilters.forEach(function(filter) {
if (filter.test(url)) {
urlShortenerCounter += parseInt(count, 10);
const host = referrer.text.replace(re, '');
const url = referrer.url.replace(new RegExp('^(.+//[^/]+).*'), '$1');
ref.setAttribute('href', url);
ref.innerHTML = host;
}
});
});
var table = $('.av-referrers');
var rows = $('tbody > tr', table);
rows.sort(function (a, b) {
var countA = parseInt($('.av-referrer-count', a).text(), 10);
var countB = parseInt($('.av-referrer-count', b).text(), 10);
return countB - countA;
});
rows.each(function () {
table.append(this);
});
document.querySelectorAll('.av-referrer a').forEach(function(element, index) {
const html = element.innerHTML;
const countElement = document.querySelectorAll('.av-referrer-count')[index];
let count = 0;
if ($('.av-referrers tbody').children().length > 0) {
$('.av-referrers').removeClass('uk-hidden');
}
document.querySelectorAll('.av-referrer a').forEach(function(element2, index2) {
if (index2 <= index) return;
if (element2.innerHTML === html) {
count += parseInt(document.querySelector('.av-referrer-count')[index2].innerText, 10);
element2.closest('.av-referrer-row').classList.add('av-delete');
}
});
if (count) countElement.innerHTML = parseInt(countElement.html(), 10) + count;
});
document.querySelectorAll('.av-referrer-row.av-delete').forEach(function(element) {
element.remove();
});
const table = document.querySelector('.av-referrers tbody');
const rows = table.querySelectorAll('tr');
const sortedRows = Array.prototype.slice.call(rows).sort(function(a, b) {
return parseInt(b.querySelector('.av-referrer-count').innerText, 10) -
parseInt(a.querySelector('.av-referrer-count').innerText, 10);
});
sortedRows.forEach(function(row) { table.appendChild(row); });
})();
</script>
<% #referrer %>
@ -1132,23 +1255,20 @@ a.gs-title:hover {
<% param.referrer | link %>
</td>
<td class='av-referrer-control uk-text-right'>
<a href='javascript:' class='uk-hidden'><i class='uk-icon uk-icon-filter'></i></a>
<a href='javascript:'><i class='uk-icon uk-icon-filter'></i></a>
</td>
</tr>
<% #deleted %>
<p><% gettext "This site is going to be deleted completely and irreversibly after {0}." <% site.deleted | format long %> %></p>
<% #export %>
<h1><% gettext "Export Site Data" %></h1>
<p>
<% if <% param.status %> is null then <% if <% file.self %> is null then '' else <% gettext "Download the file {0} or klick “Start” to create a new one." <% file.skin File#main %> '<small>' <% file.created | format short %> '</small>' %> %> else <% param.status %> %>
<% if <% param.status %> is null then <% if <% site.export %> is null then '' else <% gettext "{0}Download the archive{1} or click “Export” to create a new one." <% site.export prefix="<a href='" suffix="'>" %> "</a>" %> %> else <% param.status %> %>
</p>
<form action="" method="post">
<button type="submit" name="submit" value="<% if <% param.status %> is null then start else stop %>" class='uk-button uk-button-primary'>
<% if <% param.status %> is null then <% gettext Start %> else <% gettext Stop %> %>
<form action="<% site.href export %>" method="post">
<button type="submit" name="submit" value="<% if <% param.status %> is null then export else cancel %>" class='uk-button uk-button-primary'>
<% if <% param.status %> is null then <% gettext Export %> else <% gettext Cancel %> %>
</button>
<a href='<% site.href %>' class='uk-button uk-link-button'><% gettext Cancel %></a>
<a href='<% site.href edit %>' class='uk-button uk-button-link'><% gettext Settings %></a>
</form>
<% #import %>
@ -1201,12 +1321,11 @@ a.gs-title:hover {
</noscript>
<% #menuExt %>
<script type="text/javascript" defer="defer">
var win = external.menuArguments;
var url = "<% site.url %>stories/create?text=";
var link = escape('<a href="' + win.location.href + '">' +
win.document.title + "</a>: ");
var text = escape(win.document.selection.createRange().text);
<script defer='defer'>
const win = external.menuArguments;
const url = '<% site.url %>stories/create?text=';
const link = escape('<a href="' + win.location.href + '">' + win.document.title + '</a>: ');
const text = escape(win.document.selection.createRange().text);
win.location.href = url + link + text;
</script>

Some files were not shown because too many files have changed in this diff Show more