Compare commits

...

316 Commits
v1.0.8 ... main

Author SHA1 Message Date
ee76c41a2b Fixed resolution problems. 2024-05-27 13:52:15 +02:00
3092eb53cb Removed another console log. 2024-05-27 09:36:32 +02:00
3c7b220dd7 Removed console log. 2024-05-27 09:19:20 +02:00
81f18ea2e9 Fixed memory problems of deepzoom images. 2024-05-24 10:29:24 +02:00
13ea23186f Fixed flippable scaling problem. 2024-02-12 15:05:12 +01:00
57d6e8b461 Merge branch 'main' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib into main
* 'main' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib:
  Removed console.logs
  Fixed timestamp name mismatch.
  Updated iwmlib and removed log statement.
  Added pluggable throw behavior.
  Replaced requestAnimationFrame with setInterval
  Moved throws to a single loop.
  Added cancelAnimationFrame
  update code block to reflect current state
  Fixed html double code
  Fixed problem with scrolling text in card drawers.
  added fix for viewBox rotation bug
  fixed rollup
  documented/ solved svg rotation bug

# Conflicts:
#	package.json
2024-02-12 14:15:58 +01:00
8d8090cdde Added doctest for flippable images with different sizes. 2024-02-12 14:08:24 +01:00
80355ea636 Removed console.logs 2023-07-28 14:03:39 +02:00
45d081c225 Fixed timestamp name mismatch. 2023-07-21 12:44:03 +02:00
07f50974f9 Updated iwmlib and removed log statement. 2023-07-21 09:48:00 +02:00
8b33bc0536 Added pluggable throw behavior. 2023-07-21 08:36:14 +02:00
47992755e2 Replaced requestAnimationFrame with setInterval 2023-07-20 14:50:48 +02:00
97fb30d741 Moved throws to a single loop. 2023-07-20 14:38:23 +02:00
52ccb49fa8 Added cancelAnimationFrame 2023-07-20 11:44:13 +02:00
1a0b9d55c1 update code block to reflect current state 2023-06-06 17:31:58 +02:00
4b80702b10 Merge branch 'main' of https://gitea.iwm-tuebingen.de/IWMBrowser/iwmlib 2023-06-06 14:26:17 +02:00
1e6bee007e Fixed html double code 2023-06-06 14:24:58 +02:00
98085006bb Merge branch 'main' of https://gitea.iwm-tuebingen.de/IWMBrowser/iwmlib 2023-06-02 14:24:51 +02:00
a748d05c38 Fixed problem with scrolling text in card drawers. 2023-06-01 18:19:30 +02:00
43e69365e0 Merge branch 'main' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib 2023-05-12 12:33:56 +02:00
12eb712fce added fix for viewBox rotation bug 2023-05-12 12:30:17 +02:00
03fda7e79e Merge branch 'main' of https://gitea.iwm-tuebingen.de/IWMBrowser/iwmlib 2023-05-10 15:25:13 +02:00
c8f7e39235 Added electron browser to allow snapshots of doctests that are stored in lib thumbnail subfolders. 2023-05-09 15:40:18 +02:00
9501264f08 Added minimal navigation breadcrumbs to doctests. 2023-05-09 13:25:39 +02:00
13e0473328 Added support for static doctest files generated by the iwmsite static site generator. 2023-05-09 09:52:39 +02:00
d818ef9737 Merge branch 'main' of https://gitea.iwm-tuebingen.de/IWMBrowser/iwmlib 2023-05-04 13:33:02 +02:00
d45b3e68dd fixed rollup 2023-05-04 13:32:47 +02:00
7a5bc222fd documented/ solved svg rotation bug 2023-05-04 13:28:58 +02:00
0cff31e65b Added pixi-compressed-textures plugin again. In Pixi v6 the plugin ist included, but cannot be activated if the browser don't use JavaScript Modules 2023-05-02 15:09:38 +02:00
dc40b4cffa Fixed bug in nearestActive. 2023-04-28 09:17:03 +02:00
4da99ef04b Added new configuration flag and default behavior that prevents pointer click events which might lead to conflicts in touch applications. 2023-02-15 15:11:12 +01:00
7f1a3aae8e Removed compressed textures Pixi.js plugin from 3rdpartylib 2023-02-15 15:05:11 +01:00
20d209cbe1 Changed order of tap handler and simulated clicks. 2023-02-09 16:02:09 +01:00
Sebastian Kupke
5af350182d Fixed touch event bug 2022-11-09 16:09:22 +01:00
2987b820a9 Moved polyfill from utils to own file 2022-11-09 14:11:34 +01:00
34792f20d6 Fixed popup bug 2022-11-08 15:44:20 +01:00
8275dad36c Removed alerts 2022-11-08 13:58:10 +01:00
7965c8459b Added more logging 2022-11-08 13:42:50 +01:00
89de46b0e6 Added more logging 2022-11-08 12:31:21 +01:00
d8dc158be0 Added more logging 2022-11-08 12:07:37 +01:00
68e46e81c1 Fixed hyphenate bug 2022-11-08 11:11:39 +01:00
3856e59093 Removed hyphenation 2022-11-03 16:06:14 +01:00
bbae811b50 Removed hyphenate 2022-11-03 15:28:01 +01:00
6767064ea7 Moved convertPointFromPageToNode polyfill to utils 2022-11-03 15:27:47 +01:00
3b1ab1f392 Removed pixelDeviceRatio 2022-10-04 15:26:17 +02:00
c5c2759ebd Initial commit 2.0 beta 0 2022-10-04 10:51:35 +02:00
f87b19140b Removed header from test images. 2022-05-05 12:31:58 +02:00
63ebbba42b Added second resolution test. 2022-05-05 12:29:27 +02:00
72c6abf031 Resolution tests. 2022-05-04 15:18:11 +02:00
9db52a004a Added scatter resolution test. 2022-05-04 13:27:31 +02:00
527fcb993c Removed videos from resolution test. 2022-05-04 09:53:55 +02:00
c41209d0fc Added description to resolution. 2022-05-04 09:10:01 +02:00
7e9f0159e8 Added resolution test. 2022-05-03 16:50:19 +02:00
074fb67906 Fixed problem with outdated loader and error handler.s 2022-05-02 16:41:22 +02:00
51b0ef4b1b Added VSCode workspace file. 2022-05-02 11:13:03 +02:00
Sebastian Kupke
1efe94ef97 Bump version number. 2022-04-29 10:30:05 +02:00
Sebastian Kupke
7f068c5d94 Fixed resize fullscreen bug. 2022-04-29 10:28:59 +02:00
eff934e8b5 Moved the addVelocity method after the transform to allow a modification of the delta within the transform method. To make this destructive side effect more explicit transform could return a modified value. But that could effect several projects. 2021-04-28 17:02:54 +02:00
266a770c8e Merge branch 'master' into obersalzberg
# Conflicts:
#	dist/iwmlib.js
#	dist/iwmlib.pixi.js
2021-03-15 17:02:08 +01:00
a5f94e0a5f Reverted changes from commit fa0256d782dd498c6d3e51321260ca375ca9f855 and moved addVelocity from _move back to old locations. 2021-03-15 15:39:07 +01:00
fff7a4f685 Fixed import order. 2021-03-01 08:58:44 +01:00
d0ae8893cc Version 1.1.1. 2021-02-24 16:15:20 +01:00
1b4eee6498 Merge branch 'master' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib 2021-02-24 16:14:26 +01:00
ac779af339 Popup close buttons can take a URL. 2021-02-24 16:13:50 +01:00
1316a727f3 Fixed offset error. 2021-02-01 13:54:40 +01:00
be950ec8c1 Tried fix scatter. 2021-02-01 13:40:57 +01:00
ca5a39d661 Changed wrapper and events to allow other EventListeners. 2021-01-26 08:01:51 +01:00
fa0256d782 Moved addVelocity to _move. 2021-01-05 16:25:55 +01:00
114c217ffa Improved logging and adjusted card's click handler
+ Logging now also works when ipcRenderer is appended to the window element.
+ Card's callback replacement method was changed from click to pointerdown.
2020-09-15 11:36:59 +02:00
28cfdc180c Fixt highlight order on creation. 2020-09-01 13:38:22 +02:00
116058ba77 Fixed a problem with clicking transformed rects in card wrappers. 2020-08-27 07:38:35 +02:00
4211548b8b Removed console logs. 2020-08-04 18:13:24 +02:00
12b17fd7af Fixed call of popup menu commands with parameters.s 2020-08-04 18:07:48 +02:00
47b178fbc1 Added event parameter to PopupMenu perform. 2020-08-04 17:35:15 +02:00
6ab63eb32c Now calling 'this' to allow overloading of methods. 2020-04-21 12:43:55 +02:00
6445ab3f57 CardLoader.load now checks for ready state. 2020-04-19 13:30:35 +02:00
129672eb0f Added options object to toggle function. 2020-04-14 12:14:40 +02:00
70031d3bfa Removed comment since border case appeared in Edge. 2020-02-25 15:19:01 +01:00
9db5723746 Updated dist 2020-02-17 16:20:16 +01:00
d4ab5c7e9c Merge branch 'master' of https://gitea.iwm-tuebingen.de/IWMBrowser/iwmlib
* 'master' of https://gitea.iwm-tuebingen.de/IWMBrowser/iwmlib:
  Changed scale
  Updated to PixiJS 5.2.1.
2020-02-17 16:19:33 +01:00
b068fd176f Added lineWidth support. 2020-02-17 16:18:55 +01:00
f70968fe01 Changed scale 2020-02-07 20:08:44 +01:00
1c70433b86 Updated to PixiJS 5.2.1. 2020-02-04 16:48:36 +01:00
54b685ab42 Changed calling order 2020-02-03 10:06:27 +01:00
e6f6f6b185 Changed calling order 2020-02-03 10:06:01 +01:00
7bb3b696f7 Created new build. 2020-01-31 10:26:41 +01:00
6cdf5310ba Added graphics alpha workaround. 2020-01-30 15:41:31 +01:00
1967b791e0 Updated dependencies. 2020-01-22 13:50:40 +01:00
ebb4b9154e Updated pixi-compressed-textures. 2020-01-20 11:33:53 +01:00
Sebastian Kupke
b32132c71f Removed stopEvents from RigidContainer. 2020-01-10 14:18:28 +01:00
f398fe4824 Fixed reference bug. 2020-01-09 15:14:27 +01:00
d5b87f23cf Updated generated content (Docs & dist). 2019-12-12 19:04:11 +01:00
7f2fc93fa3 Reworked overlay itself and doctest. 2019-12-12 19:02:58 +01:00
32e913c629 Fixed wrongly assigned parameters 2019-12-12 17:23:39 +01:00
87c966062c Map's cover state now updates every time cover is requested. 2019-12-12 17:01:51 +01:00
d7f867f1a6 Added maps graphics. 2019-12-11 17:30:11 +01:00
e188f3474f Reverted index.css to previous version. 2019-12-11 16:52:23 +01:00
1e80845aa6 Fixed cover bug. Renamed mapdata to mapprojection. 2019-12-11 16:45:26 +01:00
a85569e54d commited for presentation. 2019-12-11 15:29:59 +01:00
65fac2f406 Renamed 'MapView' to 'MapViewport'. Added documentation to the maps module. 2019-12-09 18:15:28 +01:00
60e28f8fe5 Improved doctest css. 2019-12-09 14:29:26 +01:00
792892cb82 Removed PIXIUtils from geographics. 2019-12-09 14:27:32 +01:00
9159073483 Fixed GeoGraphics doctest. 2019-12-05 17:06:50 +01:00
8745554cee Implemented a mapChangeLock variable to prevent mapChanges. 2019-12-02 16:51:20 +01:00
096e374997 Added mouse wheel event to submap scatter. 2019-11-28 16:25:38 +01:00
f3fed535d8 Modified scatter to get access to the Resize event. 2019-11-28 13:36:00 +01:00
5305561619 Ongoing cleanup and refactoring of maps. 2019-11-25 18:04:11 +01:00
88048f14ec Removed overdoscaling from SubmapScatter. 2019-11-21 09:48:14 +01:00
4d6d2f1df0 Merge branch 'master' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib 2019-11-20 16:06:01 +01:00
6dcf6d38da Added functionality and dark mode to doctests. And other changes in maps. 2019-11-20 15:59:10 +01:00
38e84ab9fe Updated dependencies. 2019-11-13 14:36:48 +01:00
89395ba641 Updated mapapp. 2019-11-13 14:33:24 +01:00
46b80c3e2a Added missing dependency to the iwmlib. 2019-11-13 14:30:15 +01:00
285e41434a Continued refactoring of the maps library. 2019-11-13 12:42:06 +01:00
58cbd44a7b Fixed map doctest. 2019-11-11 12:34:43 +01:00
ef16f2b12b Improved doctests. 2019-11-05 16:02:27 +01:00
0a30712e31 Fixed overlay example to work with restructured GeoLayers. 2019-11-05 11:23:18 +01:00
87727d28b9 Geographics placements working again. 2019-11-05 11:07:36 +01:00
ff0606d0a7 Removing layer dependency from geolayers and refactoring maps. 2019-11-04 18:20:32 +01:00
938b3e2f3c Merge branch 'master' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib 2019-11-04 11:00:55 +01:00
86b23f4e6f Added the maps-module to the iwmlib.
Migrated a  ot of the content from the tuesch to the iwmlib.
This is before the decoupeling of the layers.
2019-11-04 10:59:08 +01:00
06f8949159 Updated dependencies. 2019-11-04 09:45:10 +01:00
e2ea89cc0b Added textAlpha and textActiveAlpha to Button and ButtonGroup. 2019-10-15 14:56:24 +02:00
e50ea6af31 Cleaned up card.js 2019-10-15 10:07:29 +02:00
66da13aed6 Tried fixing closing error. 2019-10-15 09:12:12 +02:00
122493df19 Updated iwmlib. 2019-10-11 10:06:09 +02:00
6af487e5fd Updated dependencies. 2019-10-11 09:19:48 +02:00
99c128d7ca Added comments. 2019-10-10 09:16:39 +02:00
901621da95 Added PixiJS UI Text class. 2019-10-09 15:41:16 +02:00
125a418e79 Updated eslint. 2019-10-07 14:42:53 +02:00
680d0610b1 Removed console.log statements. 2019-10-02 15:05:18 +02:00
ce25b1dbae Fixed flipeffect bug. 2019-10-02 15:00:08 +02:00
7dd7142455 Fixed flippable doctest. 2019-10-02 14:09:09 +02:00
b4bc200fbd Styling. 2019-10-02 11:51:23 +02:00
8960923514 Merge branch 'master' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib 2019-10-02 10:34:01 +02:00
cd140a73f6 Fixed taphandler problems. 2019-10-02 10:33:57 +02:00
980adbe595 Fixed clipping issue for PixiJS v5. 2019-10-02 09:27:12 +02:00
ba54969990 Fixed clipping issue for PIXI v5. 2019-10-01 15:40:55 +02:00
cbe6613c56 Updated to PixiJS 5.1.5. 2019-09-30 10:10:03 +02:00
e7c05a8387 Updated to PixiJS 5.1.4. 2019-09-23 14:00:31 +02:00
9dac52c0e4 Fixed DropShadowFilter. 2019-09-20 09:54:32 +02:00
b09eb63785 Merge branch 'master' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib
# Conflicts:
#	dist/iwmlib.pixi.js
2019-09-19 16:47:44 +02:00
5556cc720c Revert. 2019-09-19 16:45:47 +02:00
735d947126 Fixed loader.js bug. 2019-09-19 13:53:12 +02:00
b69472640f Reset line width. 2019-09-19 13:43:38 +02:00
efbdffc6fc Fixed conflict. 2019-09-19 13:41:50 +02:00
5407f66aae Merge branch 'master' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib
# Conflicts:
#	dist/iwmlib.js
2019-09-19 13:40:42 +02:00
0e1b49675a Fixed loader bug. 2019-09-19 13:38:24 +02:00
0e5be56dfe Fixed stylus line width problem. 2019-09-18 16:43:01 +02:00
71e5ce8b8e Fixed button bug with area interaction. 2019-09-17 15:14:57 +02:00
42afa3e7ab Added the option "capturePointerEvents" to InteractionDelegate. 2019-09-17 10:39:30 +02:00
d3c8d9c1af Fixed README.md. 2019-09-11 09:51:14 +02:00
8fbd95ab77 Bump version to 1.1.0. 2019-09-11 09:44:55 +02:00
8034d3018a Generated JSDoc. 2019-09-11 09:42:00 +02:00
ebe0b1253f Updated to PixiJS v5. 2019-09-10 16:34:59 +02:00
a775126f9c Fixed problem of popups showing up directly centered on highlights instead of over it. 2019-08-19 16:09:47 +02:00
28a7a0b6a2 Fixed closing issue with cards. 2019-08-14 17:46:12 +02:00
30c7113713 Updated cards from tuesch changes. Incorporated InteractionMapper memory leak fix. 2019-08-13 14:31:03 +02:00
03be6673c5 Merge branch 'master' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib 2019-08-13 12:46:32 +02:00
6e9ec938fc Implemented InteractionMapper.off 2019-08-13 12:46:24 +02:00
6841a52024 Merge branch 'master' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib 2019-08-12 16:35:26 +02:00
1d94455c1a Cleanup transform listeners properly now. 2019-08-12 16:35:10 +02:00
e7bda6af17 Added memory test with Hammerjs destroy. 2019-08-12 15:57:21 +02:00
98b3b44ed5 Merge branch 'master' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib 2019-08-12 15:57:14 +02:00
7f5e0e8e79 Added Hammerjs memory test. 2019-08-12 15:38:03 +02:00
74b5d69389 Added EventListener test. 2019-08-12 12:16:05 +02:00
4f4215ced5 Close callbacks on Scatter are now removed on close. 2019-08-12 10:04:03 +02:00
Sebastian Kupke
53654349b5 Changed prettier printWidth in build script. 2019-08-09 10:27:08 +02:00
3cb389aabd Merge branch 'master' of https://gitea.iwm-tuebingen.de/IWMBrowser/iwmlib 2019-08-08 14:33:03 +02:00
d48139c40f Fixed positioning bug in button. 2019-08-08 14:32:55 +02:00
05e3c89ca1 Fixed eslint problems 2019-08-08 14:30:42 +02:00
f5cf8115af Fixed conflict. 2019-08-08 13:47:00 +02:00
97d33cf177 Fixed theming bug in button and button group. 2019-08-08 13:46:02 +02:00
7e7b37f524 Merge branch 'master' of https://gitea.iwm-tuebingen.de/IWMBrowser/iwmlib 2019-08-08 12:06:27 +02:00
9aef7bb460 Timeline is now draggable 2019-08-08 12:06:16 +02:00
cdc6461064 Prevent dragging of button group if buttons are not wider than maxWidth. 2019-08-07 15:24:18 +02:00
56910a8c58 Fixed vertical button group bug. 2019-08-07 15:03:58 +02:00
caffee4b15 Fixed button group bug. 2019-08-07 14:57:07 +02:00
141d27d4f1 Added path to gulpfile. 2019-08-06 15:34:57 +02:00
a42427f987 Improved button doctest. 2019-08-06 14:24:50 +02:00
05c952fbe1 Added badge content example to button doctest. 2019-08-06 12:01:32 +02:00
ca16516073 Merge branch 'master' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib 2019-08-05 11:45:09 +02:00
03f927d1d5 Set window.app as default value for button group option "app". 2019-08-05 11:44:59 +02:00
e502c97de5 Added prepare method 2019-08-03 09:02:58 +02:00
a44fd6c469 Removed d3 from globals. 2019-08-02 11:39:56 +02:00
e8a64fb014 Added getter and setter for maxWidth and maxHeight for button groups. 2019-08-02 10:15:49 +02:00
81e21736b7 Merge branch 'master' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib 2019-08-01 19:34:49 +02:00
488c1807d6 Improved card API. 2019-08-01 19:34:32 +02:00
0182e9663e Merge branch 'master' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib 2019-08-01 19:31:22 +02:00
db2badfc0d Added event parameter, 2019-08-01 19:30:07 +02:00
1e3f66bb19 Fixed button hover bug. 2019-08-01 14:27:04 +02:00
32087608cc Improved button group stack sorting. 2019-08-01 11:26:22 +02:00
b1f0f173e7 Fixed bug with stacked buttons in a button group with badges. 2019-08-01 10:31:05 +02:00
e9f1246e0a Improved button group stacking behaviour if ThrowPropsPlugin is not loaded. 2019-08-01 10:19:34 +02:00
56407539aa Updated docs. 2019-08-01 09:51:32 +02:00
a6f0341fe4 Added huge button group example. 2019-08-01 09:44:03 +02:00
afa1c71a0a Added badge examples for buttons and button groups. 2019-08-01 09:42:04 +02:00
dafc820466 Fixed html bug. 2019-07-31 16:12:15 +02:00
614b4d8350 Implemented stacked button groups. 2019-07-31 16:12:00 +02:00
73342a0506 Merged conflicts. 2019-07-30 17:12:17 +02:00
c55644558a Merge branch 'master' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib
# Conflicts:
#	lib/scatter.js
2019-07-30 17:02:58 +02:00
5f46b4feae Working on stacked buttons. 2019-07-30 16:56:29 +02:00
ca2ce289aa Improved scatter closing. Added module to eslint. 2019-07-30 13:21:17 +02:00
0bcf931465 Added remove capability to scatter.(Merged local branch 'scatter') 2019-07-29 16:18:20 +02:00
5e98640ded Added a remove function for the DOMScatterContainer. Is automatically called onClose. 2019-07-29 14:36:00 +02:00
e72836e0f7 Fixed highlight problems 2019-07-24 12:45:55 +02:00
ed40ffc43f Improved wrapper event handling. 2019-07-24 11:45:03 +02:00
cc6ef8de46 Tested new way to compute interaction delta. 2019-07-24 08:54:09 +02:00
ef4267e926 Improved click handling 2019-07-21 21:42:03 +02:00
e32ee93e7a Improved zoom behavior. 2019-07-19 15:30:13 +02:00
51dd0ef4ba Disable zoom correction. 2019-07-19 15:25:47 +02:00
dcd5acb4d1 Generalized the min rotation to min interaction distance. 2019-07-19 15:21:47 +02:00
bb0dcf2d9d Improved handling of min rotation distance. 2019-07-19 15:19:03 +02:00
dfe7c0a011 Rebuild dist. 2019-07-19 15:13:31 +02:00
68c98d1293 Added check for rotation by narrow distance between touch points. 2019-07-19 15:05:46 +02:00
ff2c15a505 Added material icons. 2019-07-19 10:18:15 +02:00
4e9aa716bd Added images 2019-07-19 09:41:02 +02:00
8d8e764956 Added default css for cards. 2019-07-19 09:31:25 +02:00
bb660b0e04 Merge branch 'master' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib 2019-07-19 08:39:08 +02:00
a4de98a0e7 Centered image. 2019-07-19 08:39:01 +02:00
2d400a18ec Prettified all files. 2019-07-18 12:26:39 +02:00
7744b92771 Prettified badge.js. 2019-07-18 08:59:39 +02:00
5704beaad4 Fixed build problem. 2019-07-18 08:52:46 +02:00
0f4949b0ae Fixed order of gulp imports. 2019-07-18 08:40:48 +02:00
774f5989ec Added support for hyphenation including jquery dependency. 2019-07-18 08:36:25 +02:00
9abea054b7 Minor changes. 2019-07-17 11:54:10 +02:00
3c607200be Added popup example. 2019-07-17 11:41:33 +02:00
d506eed827 Fixed bundle problems 2019-07-17 11:03:26 +02:00
7f00898767 Merge branch 'master' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib
# Bitte geben Sie eine Commit-Beschreibung ein, um zu erklären, warum dieser
# Merge erforderlich ist, insbesondere wenn es einen aktualisierten
# Upstream-Branch mit einem Thema-Branch zusammenführt.
#
# Zeilen, die mit '#' beginnen, werden ignoriert,
# und eine leere Beschreibung bricht den Commit ab.
Merged.
2019-07-17 10:06:26 +02:00
7f909c9f59 Added htmlhint. 2019-07-17 10:04:59 +02:00
ab835d6fc3 Removed TweenMax dependency 2019-07-17 10:04:16 +02:00
17bbe1a90e Added files to make classes better accessible. 2019-07-17 09:56:20 +02:00
78108c4090 Linted gulpfile. 2019-07-16 15:10:15 +02:00
3c8f0bac1b Added stylelint. 2019-07-16 14:07:16 +02:00
87b63c2142 Added ESLint and Prettier. 2019-07-16 13:54:04 +02:00
1f5df65c48 Added tests for jQuery. 2019-07-16 10:04:25 +02:00
09b50d3b81 Bundled card classes. 2019-07-16 09:27:48 +02:00
54912ad37e Moved files from src/htmlcards to iwmlib. 2019-07-16 09:21:28 +02:00
9a399ecfe9 Fixed highlight doctest. 2019-07-15 14:42:01 +02:00
c3477244b9 Working on cards. 2019-07-15 13:32:45 +02:00
0e8c62eb4b Minor updates to Doctests. 2019-07-12 14:50:30 +02:00
e1b5c45b52 Added support for DOM cards. 2019-07-12 14:33:15 +02:00
d04f92ee7f Added smoothing parameter to DOMScatter 2019-07-11 16:08:49 +02:00
cd76ae22a4 Added LowPassFilter and support for smooth scatter rotation and zoom. 2019-07-11 15:41:03 +02:00
2a11f02bd2 Added missing update of dist script. 2019-07-10 14:29:44 +02:00
42539c9d95 Merge branch 'master' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib 2019-07-10 14:21:07 +02:00
6e77f0ec58 Added test for null in Timeline.onMove 2019-07-10 14:20:58 +02:00
1c7651f0d5 Generated JSDoc. 2019-07-10 11:55:35 +02:00
44a5b3385c Fixed #17. 2019-07-08 15:44:06 +02:00
1e17184194 Fixed wording 2019-07-08 09:58:27 +02:00
808106262e Removed setup from constructor to simplify specializations 2019-07-08 09:07:26 +02:00
b36d75af46 Removed setup from constructor to simplify specializations 2019-07-08 09:05:54 +02:00
d0c89a78c2 Added flag to enable tap clicks for SVG in tested circumstances. 2019-07-05 16:29:50 +02:00
f68d8b53a3 Using original click events for SVG elements. Must be checked for taps on touch devices. 2019-07-05 16:11:23 +02:00
84ea33f029 Added click handler to avoid double calls of click event handler. 2019-07-05 15:03:22 +02:00
6392e4b13a Improved click behavior 2019-07-05 14:40:35 +02:00
14f2c2fbe6 Improved tab behavior of scatter 2019-07-05 14:40:15 +02:00
a77226e42b Working on scatter doctest 2019-07-05 14:12:49 +02:00
8b4c6c2014 Fixed doctest problems. 2019-07-05 14:11:43 +02:00
4009ddd422 Merge branch 'master' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib
# Conflicts:
#	dist/iwmlib.js
2019-07-05 13:58:20 +02:00
6794c5eedd Fixed conflict. 2019-07-05 13:57:52 +02:00
20ac5c387e Working on tap behavior of scatter and flippables. 2019-07-05 13:43:39 +02:00
30e998e386 Merge branch 'master' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib 2019-07-05 09:39:17 +02:00
e87c8c9e1e Renamed simulateClick to clickOnTap 2019-07-05 09:39:01 +02:00
92d3c0c861 Merge branch 'master' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib
# Conflicts:
#	dist/iwmlib.js
2019-07-05 09:36:57 +02:00
0c190f1f76 Fixed flippable doctest. 2019-07-05 09:34:22 +02:00
a3f7eb0b3c Merge branch 'master' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib 2019-07-05 09:18:13 +02:00
4f35bfd51f Fixed eslint problems and cleaned DOMScatter.onTap code 2019-07-05 09:17:52 +02:00
fc6b30f03c Fixed some linter problems. 2019-07-05 08:43:23 +02:00
22b0ceaff7 Improved gitignore. 2019-07-05 08:36:40 +02:00
357153b978 Added lint files. 2019-07-05 08:35:32 +02:00
5d1408ad9a Fixed minor bug. 2019-07-04 16:15:12 +02:00
9b9988569f Added limit to scatter rotation to avoid flicker. 2019-07-04 16:08:23 +02:00
dda6262601 Added maxRotation parameter. 2019-07-04 16:00:56 +02:00
6e4e847be1 Merge branch 'master' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib 2019-07-04 11:02:33 +02:00
03d8eef5ae Merge branch 'master' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib 2019-07-04 09:19:13 +02:00
4e9dd2fa02 Fixed worker path problems. 2019-07-04 09:17:43 +02:00
dcf40822e3 Added links 2019-07-04 09:16:50 +02:00
b6fc04a411 Uups, forgot to remove files. 2019-07-04 09:09:58 +02:00
af932a9911 Removed the stylus folder and added stylus.js with doctest to lib/pixi 2019-07-04 09:09:19 +02:00
da212ac188 Changed README. 2019-07-03 13:49:59 +02:00
Sebastian Kupke
3436b9edbf Fixed version number. 2019-07-03 13:46:52 +02:00
8a4f64f545 Fixed eslint problems 2019-07-02 10:06:23 +02:00
1480ad8145 Logging handlers can now be adapted to special needs 2019-07-02 09:38:19 +02:00
9042579518 Removed unused import 2019-06-24 10:50:51 +02:00
11bc20fad5 Improved ticks. 2019-06-21 12:28:52 +02:00
8b9ed733dd Added missing variables. 2019-06-18 16:07:07 +02:00
5c95128dfc Bump version number. 2019-06-18 16:02:24 +02:00
beca78d7a7 Improved handling of textures that arrive too late. 2019-06-18 16:01:20 +02:00
54a1e74e27 Added message cache to prevent error overflows. 2019-06-18 09:00:05 +02:00
909ef9d242 Added persistent logging methods 2019-06-17 17:21:47 +02:00
6ec0e9631a Merge branch 'master' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib 2019-06-06 16:18:05 +02:00
6f7a18d6b8 Fixed line endings 2019-06-06 16:17:58 +02:00
mhalfmann
322fdf8deb Revert "highlightColor for popup now being set correctly"
This reverts commit 012fe4bc4ae1dad7e75b6038a831ff9dfc13f45d.
2019-06-06 15:14:24 +02:00
mhalfmann
012fe4bc4a highlightColor for popup now being set correctly 2019-06-06 15:13:55 +02:00
mhalfmann
502bdf47a3 Revert "highlightColor now set correctly"
This reverts commit 437320b4ad24708db273fe3324da08ee5557f91c.
2019-06-06 15:09:56 +02:00
mhalfmann
437320b4ad highlightColor now set correctly 2019-06-06 14:47:41 +02:00
3b6402a682 Removed pending state since it seems no longer necessary. 2019-06-04 13:09:38 +02:00
fa25d13469 Merge branch 'master' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib 2019-06-04 09:35:00 +02:00
4c08359394 Added active flag to avoid transform of inactive deepzoom images. 2019-06-04 09:34:50 +02:00
mhalfmann
b5400c8223 fixed resize function 2019-06-04 08:43:07 +02:00
5a336e8d40 regenerated pngs 2019-06-03 11:41:18 +02:00
2d1a6b1b7f Merge branch 'master' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib 2019-06-03 11:39:54 +02:00
636e2e439c typo fixed 2019-06-03 11:39:33 +02:00
b208592e3a Version 1.0.12. 2019-06-03 10:53:33 +02:00
95d1941545 Disabled debug flag. 2019-06-03 10:49:56 +02:00
086dfff19e Merge branch 'master' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib 2019-06-03 10:24:36 +02:00
0442df4287 Reverting getBounds to bound to avoid excessive loading of tiles. 2019-06-03 10:24:10 +02:00
e3d167bd7f concluded merge 2019-06-03 09:46:24 +02:00
da5ed78558 added fs-extra to have ensure-dir for non existing dirs 2019-06-03 09:42:45 +02:00
0c46c4e656 Fixed minor problems. 2019-06-03 08:55:33 +02:00
304818dc13 Fixed typos. 2019-06-01 12:40:01 +02:00
05ecd0b048 Fixed minor bugs 2019-06-01 12:31:38 +02:00
895ec55a46 Added support for keeping a limited set of tile textures. 2019-06-01 09:56:29 +02:00
67c6a6c95c Correct version number 2019-05-31 16:21:50 +02:00
107529f844 Added warning to Tile.destroy 2019-05-31 16:10:46 +02:00
742 changed files with 339284 additions and 116513 deletions

2
.eslintignore Normal file
View File

@ -0,0 +1,2 @@
dist/*
doc/out/*

35
.eslintrc.json Normal file
View File

@ -0,0 +1,35 @@
{
"parserOptions": {
"ecmaVersion": 10,
"sourceType": "module",
"ecmaFeatures": {
"impliedStrict": true,
"modules": true
}
},
"env": {
"browser": true,
"es6": true,
"node": true,
"jquery": true,
"worker": true,
"mocha": true,
"serviceworker": true
},
"globals": {
"PIXI": false,
"TweenLite": false,
"TweenMax": false,
"TimelineLite": false,
"TimelineMax": false,
"SystemJS": false,
"app": true
},
"plugins": [
"prettier"
],
"extends": ["eslint:recommended", "plugin:prettier/recommended"],
"rules": {
"comma-dangle": ["error", "never"]
}
}

9
.gitignore vendored
View File

@ -77,5 +77,12 @@ typings/
.fusebox/
# own
*.code-workspace
.history/
.vscode/
# ignore generated contents-
/doc/out/*
**/thumbnails
**/thumbnail.png
/site/dist
/site/__pycache__

3
.htmlhintrc Normal file
View File

@ -0,0 +1,3 @@
{
}

8
.prettierrc Normal file
View File

@ -0,0 +1,8 @@
{
"singleQuote": true,
"jsxSingleQuote": true,
"tabWidth": 4,
"semi": false,
"printWidth": 120,
"trailingComma": "none"
}

3
.stylelintignore Normal file
View File

@ -0,0 +1,3 @@
dist/*
doc/*
lib/*

11
.stylelintrc.json Normal file
View File

@ -0,0 +1,11 @@
{
"extends": "stylelint-config-standard",
"rules": {
"indentation": 4,
"selector-list-comma-newline-after": "never-multi-line",
"no-eol-whitespace": [true, {
"ignore": ["empty-lines"]
}]
},
"ignoreFiles": []
}

View File

@ -40,6 +40,8 @@ Afterwards you can view the documentation here:
## Useful PixiJS Resources
Currently using PixiJS version 5
- The PixiJS [JavaScript API Docs](http://pixijs.download/dev/docs/index.html)
- The PixiJS [Examples](http://pixijs.github.io/examples/#/basics/basic.js)
- The PixiJS [GitHub Repository](https://github.com/pixijs/pixi.js)

10
assets/images/close.svg Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8" ?>
<!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" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid meet">
<rect x="0" y="0" width="100" height="100" style="fill:#6699FF; stroke:rgba(0,0,0,0)" />
<g stroke-width="10" stroke="white">
<line x1="25" y1="25" x2="75" y2="75" />
<line x1="25" y1="75" x2="75" y2="25" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 478 B

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<!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" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid meet">
<line x1="20" y1="20" x2="80" y2="80" stroke="black" stroke-width="8" />
<line x1="80" y1="20" x2="20" y2="80" stroke="black" stroke-width="8" />
</svg>

After

Width:  |  Height:  |  Size: 402 B

8
assets/images/info.svg Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<!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" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid meet" >
<rect x="0" y="0" width="100" height="100" style="fill:#6699FF; stroke:rgba(0,0,0,0)" />
<circle cx="50" cy="33" r="8" fill="rgb(235, 230, 220)" />
<line x1="50" y1="44" x2="50" y2="75" stroke="rgb(235, 230, 220)" stroke-width="14" />
</svg>

After

Width:  |  Height:  |  Size: 497 B

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<!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" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid meet">
<line x1="20" y1="80" x2="80" y2="20" stroke="lightgray" stroke-width="8" />
<line x1="40" y1="80" x2="80" y2="40" stroke="lightgray" stroke-width="8" />
</svg>

After

Width:  |  Height:  |  Size: 410 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

13
bin/browser.sh Normal file
View File

@ -0,0 +1,13 @@
#!/bin/bash
if [ "$1" = "dist" ]
then
if [ -z "$2" ]
then
npm run package-all
else
npm run package-app-$2
fi
else
electron . ./lib/index.html
fi

View File

@ -1,13 +1,14 @@
/**
*
* make screenshots and log errors to
*
* make screenshots and log errors to
* console
* (c) 2019 - Leibniz-Insitut für Wissensmedien
*
*
*/
const puppeteer = require('puppeteer');
const fs = require("fs")
const fs_bare = require("fs") // required for fs-extra
const fs = require("fs-extra")
const path = require("path")
const start_dir = process.cwd()
const start_file = path.join(start_dir,"lib","index.html")
@ -23,13 +24,13 @@ function logPageEvent(event){
}
async function makeScreenshot(href){
const browser = await puppeteer.launch({args: [
'allow-file-access-from-files',
],});
const page = await browser.newPage();
await page.setViewport({width: 1024,height : 624})
// register events
@ -39,27 +40,33 @@ async function makeScreenshot(href){
page.once("load",logPageEvent)
await page.goto(href)
href = href.replace("file:///","")
const fname = path.parse(href).name
let fpath
if (fname != "index"){
image_url = href.replace(fname + ".html" ,"thumbnails/" + fname + ".png")
fpath = href.replace(fname + ".html", "thumbnails")
}
else{
image_url = href.replace(fname + ".html" ,"thumbnail.png")
fpath = href.replace(fname + ".html", "")
}
image_url = image_url.replace("file:///","")
// image_url = image_url.replace("file:///","")
// fpath = fpath.replace("file:///","")
page.removeAllListeners()
fs.ensureDir(fpath)
await page.screenshot({path: image_url});
await browser.close();
}
/**
*
*
* collect all navigational links in all documents
*
* */
*
* */
async function collectLinks(href,reflist)
{
@ -69,12 +76,12 @@ async function collectLinks(href,reflist)
await page.goto(href)
let hrefs = await page.$$('a.wrapper')
for (var i=0; i < hrefs.length; i++) {
let hrefValue = await hrefs[i].getProperty('href')
let linkText = await hrefValue.jsonValue();
if (!linkText.startsWith("file:"))
{
{
continue;
}
if(linkText.endsWith("#")) continue;
@ -106,4 +113,4 @@ async function collectLinks(href,reflist)
await makeScreenshot(reflist[i])
console.log(i,reflist[i])
}
})()
})()

289
browser/browser.html Normal file
View File

@ -0,0 +1,289 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
html {
height: 100%;
width: 100%;
margin: 0px;
}
::-webkit-scrollbar { display: none; }
body {
margin: 0px;
padding: 0px;
width: 100%;
height: 100%;
font-family: sans-serif;
font-size: 22pt;
-webkit-tap-highlight-color: #ccc;
background-color: #DDD;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-hyphens: auto;
hyphens: auto;
/* https://davidwalsh.name/font-smoothing */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-app-region: drag;
}
header {
position: absolute;
width: 100%;
height: 24px;
}
#progressBar {
position: absolute;
background-color: rgb(165, 165, 196);
width: 0%;
height: 24px;
}
#info {
width: 100%;
margin: 3px;
font-size: 16px;
position: absolute;
text-align:center;
}
</style>
<title>
Browser
</title>
</head>
<body style="width: 100%; height: 100%; -webkit-app-region: no-drag">
<header id="header" style="-webkit-app-region: drag">
<div id="progressBar"></div>
<span id="info">Minimal Header</span>
</header>
<main></main>
</body>
<script>
const { ipcRenderer } = require("electron")
let urls = new Set()
let favicons = new Set()
let progress = 0
info.innerHTML = window.location.href
function notify(url) {
if (urls.has(url)) return
console.log(url)
//header.innerHTML += `<p>${url}</p>`
urls.add(url)
}
let colorExtractorCanvas = document.createElement('canvas')
let colorExtractorContext = colorExtractorCanvas.getContext('2d')
let colorExtractorImage = document.createElement('img')
function getColor(url, callback) {
colorExtractorImage.onload = function (e) {
let w = colorExtractorImage.width
let h = colorExtractorImage.height
colorExtractorCanvas.width = w
colorExtractorCanvas.height = h
let offset = Math.max(1, Math.round(0.00032 * w * h))
colorExtractorContext.drawImage(colorExtractorImage, 0, 0, w, h)
let data = colorExtractorContext.getImageData(0, 0, w, h).data
let pixels = {}
let d, add, sum
for (let i = 0; i < data.length; i += 4 * offset) {
d = Math.round(data[i] / 5) * 5 + ',' + Math.round(data[i + 1] / 5) * 5 + ',' + Math.round(data[i + 2] / 5) * 5
add = 1
sum = data[i] + data[i + 1] + data[i + 2]
// very dark or light pixels shouldn't be counted as heavily
if (sum < 310) {
add = 0.35
}
if (sum < 50) {
add = 0.01
}
if (data[i] > 210 || data[i + 1] > 210 || data[i + 2] > 210) {
add = 0.5 - (0.0001 * sum)
}
if (pixels[d]) {
pixels[d] = pixels[d] + add
} else {
pixels[d] = add
}
}
// find the largest pixel set
let largestPixelSet = null
let ct = 0
for (let k in pixels) {
if (k === '255,255,255' || k === '0,0,0') {
pixels[k] *= 0.05
}
if (pixels[k] > ct) {
largestPixelSet = k
ct = pixels[k]
}
}
let res = largestPixelSet.split(',')
for (let i = 0; i < res.length; i++) {
res[i] = parseInt(res[i])
}
callback(res)
}
colorExtractorImage.src = url
}
function getTextColor(bgColor) {
let output = runNetwork(bgColor)
if (output.black > 0.5) {
return 'black'
}
return 'white'
}
var runNetwork = function anonymous(input) {
var net = {
'layers': [{
'r': {},
'g': {},
'b': {}
}, {
'0': {
'bias': 14.176907520571566,
'weights': {
'r': -3.2764240497480652,
'g': -16.90247884718719,
'b': -2.9976364179397814
}
},
'1': {
'bias': 9.086071102351246,
'weights': {
'r': -4.327474143397604,
'g': -15.780660155750773,
'b': 2.879230202567851
}
},
'2': {
'bias': 22.274487339773476,
'weights': {
'r': -3.5830205067960965,
'g': -25.498384261673618,
'b': -6.998329189107962
}
}
}, {
'black': {
'bias': 17.873962570788997,
'weights': {
'0': -15.542217788633987,
'1': -13.377152708685674,
'2': -24.52215186113144
}
}
}],
'outputLookup': true,
'inputLookup': true
}
for (var i = 1; i < net.layers.length; i++) {
var layer = net.layers[i]
var output = {}
for (var id in layer) {
var node = layer[id]
var sum = node.bias
for (var iid in node.weights) {
sum += node.weights[iid] * input[iid]
}
output[id] = (1 / (1 + Math.exp(-sum)))
}
input = output
}
return output
}
function applyColors(backgroundColor, foregroundColor) {
console.log("applyColors", backgroundColor, foregroundColor)
progressBar.style.backgroundColor = backgroundColor
info.style.color = foregroundColor
}
ipcRenderer.on('title', (sender, title) => {
info.innerHTML = title
})
ipcRenderer.on('favicons', (sender, urls) => {
console.log("favicons event", urls)
for (let url of urls) {
if (!favicons.has(url)) {
getColor(url, c => {
let cr = 'rgb(' + c[0] + ',' + c[1] + ',' + c[2] + ')'
let obj = {
r: c[0] / 255,
g: c[1] / 255,
b: c[2] / 255
}
let textclr = getTextColor(obj)
applyColors(cr, textclr)
})
}
favicons.add(url)
}
})
ipcRenderer.on('progress', (sender, amount) => {
console.log("progress event", amount)
if (amount > progress) {
progress = Math.min(amount, 1)
}
progressBar.style.width = Math.round(progress * 100) + '%'
})
ipcRenderer.on('did-start-loading', (sender, url) => {
console.log('did-start-loading', url)
})
ipcRenderer.on('did-get-response-details', (sender, info) => {
let {
status, newURL, originalURL,
httpResponseCode,
requestMethod,
referrer,
headers,
resourceType
} = info
notify(newURL)
notify(originalURL)
//console.log('did-get-response-details', info)
})
ipcRenderer.on('did-get-redirect-request', (sender, info) => {
let { oldURL,
newURL,
isMainFrame,
httpResponseCode,
requestMethod,
referrer,
headers
} = info
notify(newURL)
notify(oldURL)
//console.log('did-get-response-details', info)
})
ipcRenderer.on('did-stop-loading', (sender, info) => {
//console.log('did-stop-loading', info)
})
</script>
</html>

49
browser/carlo.js Normal file
View File

@ -0,0 +1,49 @@
const carlo = require('carlo');
const fse = require('fs-extra');
const urlExists = require('url-exists');
// command line arguments
let path = 'index.html'
process.argv.forEach((value, index, array) => {
if (index === 2) {
path = value
}
});
(async () => {
// Launch the browser.
const opts = {}
// Set path to custom chrome
const chrome = `${__dirname}/../chrome/chrome.exe`
if (fse.pathExistsSync(chrome)) {
opts.executablePath = chrome
}
// Launch app
const app = await carlo.launch(opts)
// Terminate Node.js process on app window closing.
app.on('exit', () => process.exit())
// Tell carlo where your web files are located.
app.serveFolder(`${__dirname}/../`)
// Check if URL exists
urlExists('https://localhost:8443', async (error, exists) => {
if (exists) {
console.info('Serve files via server')
app.serveOrigin('https://localhost:8443') // Optional
} else {
console.info('Serve files from file system')
}
// Expose 'env' function in the web environment.
await app.exposeFunction('env', _ => process.env)
// Navigate to the main page of your app.
console.info('Starting carlo with', path)
await app.load(path)
})
})()

24
browser/i18n.js Normal file
View File

@ -0,0 +1,24 @@
const path = require('path')
const electron = require('electron')
const fs = require('fs')
let loadedLanguage
let app = electron.app ? electron.app : electron.remote.app
module.exports = i18n
function i18n() {
if (fs.existsSync(path.join(__dirname, 'i18n', app.getLocale() + '.js'))) {
loadedLanguage = JSON.parse(fs.readFileSync(path.join(__dirname, 'i18n', app.getLocale() + '.js'), 'utf8'))
}
else {
loadedLanguage = JSON.parse(fs.readFileSync(path.join(__dirname, 'i18n', 'en.js'), 'utf8'))
}
}
i18n.prototype.__ = function(phrase) {
let translation = loadedLanguage[phrase]
if (translation === undefined) {
translation = phrase
}
return translation
}

61
browser/i18n/de.js Normal file
View File

@ -0,0 +1,61 @@
{
"edit": "Bearbeiten",
"undo": "Widerrufen",
"redo": "Wiederholen",
"cut": "Ausschneiden",
"copy": "Kopieren",
"paste": "Einsetzen",
"pasteandmatchstyle": "Einsetzen und Stil anpassen",
"delete": "Löschen",
"selectall": "Alles auswählen",
"view": "Darstellung",
"reload": "Seite neu laden",
"forcereload": "Cache löschen und Seite neu laden",
"resetzoom": "Originalgröße",
"zoomin": "Vergrößern",
"zoomout": "Verkleinern",
"togglefullscreen": "Vollbildmodus umschalten",
"minimalpad": "Minimal-Pad",
"multiuserbrowser": "Mehrbenutzer-Browser",
"history": "Verlauf",
"back": "Zurück",
"forward": "Vorwärts",
"home": "Startseite",
"recentlyvisited": "Kürzlich besucht",
"bookmarks": "Lesezeichen",
"localfilesystem": "Lokales Dateisystem",
"testframes": "Testseiten",
"develop": "Entwickler",
"toggledevelopertools": "Webinformationen umschalten",
"openprocessmonitor": "Prozessmonitor öffnen",
"selectfolder": "Datenverzeichnis auswählen...",
"selectfolder.noadmin.ok": "OK",
"selectfolder.noadmin.message": "Keine ausreichenden Berechtigungen",
"selectfolder.noadmin.detail": "Um das Datenverzeichnis zu ändern, muss der IWM Browser mit Administrator-Berechtigungen gestartet werden.",
"selectfolder.warning.next": "Weiter",
"selectfolder.warning.cancel": "Abbrechen",
"selectfolder.warning.message": "Datenverzeichnis vorhanden",
"selectfolder.warning.detail": "Ihr IWM Browser besitzt bereits ein (verlinktes) Datenverzeichnis. Wenn Sie fortfahren, wird das alte Verzeichnis gesichert und ein neues wird erstellt.",
"selectfolder.select.title": "Datenverzeichnis wählen",
"selectfolder.select.buttonLabel": "Auswählen",
"selectfolder.samefolder.ok": "OK",
"selectfolder.samefolder.message": "Ungültiges Datenverzeichnis",
"selectfolder.samefolder.detail.same": "Das alte Datenverzeichnis darf nicht als neues Verzeichnis ausgewählt werden.",
"selectfolder.samefolder.detail.within": "Das neue Datenverzeichnis darf sich nicht innerhalb des alten Verzeichnisses befinden.",
"selectfolder.info.ok": "OK",
"selectfolder.info.message": "Link auf Datenverzeichnis erstellt",
"selectfolder.info.detail": "Der IWM Browser verwendet nun den Ordner \"${0}\" als neues Datenverzeichnis.",
"startserver": "Starte Server",
"stopserver": "Stoppe Server",
"runloadtests": "Starte Ladetests",
"window": "Fenster",
"close": "Fenster schließen",
"minimize": "Im Dock ablegen",
"zoom": "Zoomen",
"front": "Alle nach vorne bringen",
"screenshot": "Bildschirmfoto erstellen",
"help": "Hilfe",
"iwm": "Leibniz-Institut für Wissensmedien",
"about": "Über IWM Browser",
"quit": "IWM Browser beenden"
}

61
browser/i18n/en.js Normal file
View File

@ -0,0 +1,61 @@
{
"edit": "Edit",
"undo": "Undo",
"redo": "Redo",
"cut": "Cut",
"copy": "Copy",
"paste": "Paste",
"pasteandmatchstyle": "Paste and Match Style",
"delete": "Delete",
"selectall": "Select all",
"view": "View",
"reload": "Reload",
"forcereload": "Force Reload",
"resetzoom": "Actual size",
"zoomin": "Zoom in",
"zoomout": "Zoom out",
"togglefullscreen": "Toggle Full Screen",
"minimalpad": "Minimal Pad",
"multiuserbrowser": "Multi-User Browser",
"history": "History",
"back": "Back",
"forward": "Forward",
"home": "Home",
"recentlyvisited": "Recently Visited",
"bookmarks": "Bookmarks",
"localfilesystem": "Local Filesystem",
"testframes": "Test Frames",
"develop": "Develop",
"toggledevelopertools": "Toggle Developer Tools",
"openprocessmonitor": "Open Process Monitor",
"selectfolder": "Select data folder...",
"selectfolder.noadmin.ok": "OK",
"selectfolder.noadmin.message": "Insufficient permissions",
"selectfolder.noadmin.detail": "To change the data directory, the IWM Browser must be started with administrator privileges.",
"selectfolder.warning.next": "Next",
"selectfolder.warning.cancel": "Cancel",
"selectfolder.warning.message": "Data folder exists",
"selectfolder.warning.detail": "Your IWM Browser already has a (linked) data directory. If you continue, the old directory is backed up and a new one is created.",
"selectfolder.select.title": "Select data folder",
"selectfolder.select.buttonLabel": "Select",
"selectfolder.samefolder.ok": "OK",
"selectfolder.samefolder.message": "Invalid data folder",
"selectfolder.samefolder.detail.same": "The old data directory cannot be selected as the new directory.",
"selectfolder.samefolder.detail.within": "The new data directory cannot be inside the old directory.",
"selectfolder.info.ok": "OK",
"selectfolder.info.message": "Created link to data folder",
"selectfolder.info.detail": "The IWM Browser now uses the folder \"${0}\" as the new data folder.",
"startserver": "Start Server",
"stopserver": "Stop Server",
"runloadtests": "Run Load Tests",
"window": "Window",
"close": "Close",
"minimize": "Minimize",
"zoom": "Zoom",
"front": "Bring All to Front",
"screenshot": "Make Screenshot",
"help": "Help",
"iwm": "Leibniz-Institut für Wissensmedien",
"about": "About IWM Browser",
"quit": "Quit IWM Browser"
}

578
browser/main.js Normal file
View File

@ -0,0 +1,578 @@
/* globals require, __dirname, process */
/*eslint no-console: ["error", { allow: ["log"] }]*/
const { app, BrowserWindow, BrowserView, ipcMain, dialog, shell } = require('electron')
const electronLocalshortcut = require('electron-localshortcut')
//const electron = require('electron')
const os = require('os')
const fs = require('fs')
const path = require('path')
const { URL } = require('url')
const Store = require('./store.js')
const { prettyPrint } = require('html')
// Use this constant to start the application in kiosk-mode or in development mode
const DEVELOPMENT = true
// true: Dev-Tools are open
// false (KIOSK-Mode): No application switcher, no menu, no taskbar (or dock on a mac), shortcuts are working
global.multiUserMode = true
global.errorCount = 0
global.stopTestsOnError = false
global.jsonData = { value: null }
// UO: Experimental feature using Native Windows
global.useBrowserView = false
global.useMinimalPad = true
global.menu = null
global.observeTraffic = false
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win
let browsers = new Map() // url: BrowserWindow
const store = new Store({
// We'll call our data file 'user-preferences'
configName: 'user-preferences',
defaults: {
url: `file://${__dirname}/index.html`,
devTools: DEVELOPMENT,
multiUserBrowser: true
}
})
function createWindow() {
if (global.observeTraffic) {
const {session} = require('electron')
session.defaultSession.webRequest.onCompleted((details) => {
console.log("onCompleted", details.url)
})
}
let { screen } = require('electron')
let bounds = store.get('storedBounds')
? store.get('storedBounds')
: screen.getPrimaryDisplay().bounds
// let displays = screen.getAllDisplays()
// let externalDisplay = null
// externalDisplay = displays[displays.length-1]
// const {width, height} =displays[displays.length-1].workAreaSize
// externalDisplay = displays[0]
// const {width, height} =displays[0].workAreaSize
win = new BrowserWindow({
x: bounds.x,
y: bounds.y,
width: bounds.width,
height: bounds.height,
fullscreenable: true,
fullscreen: !DEVELOPMENT,
title: 'IWM Browser',
show: false,
kiosk: !DEVELOPMENT,
acceptFirstMouse: true,
webPreferences: {
webSecurity: false,
allowRunningInsecureContent: true,
nodeIntegration: true,
webviewTag: true,
nativeWindowOpen: true,
devTools: true,
preload: path.join(__dirname, './preload.js')
},
icon: path.join(__dirname, 'assets/icons/png/64x64.png')
})
module.exports.win = win
let url = store.get('url')
if (process.argv.length > 2) {
let path = process.argv[2]
url = `file://${__dirname}/../${path}`
console.log('Using process.argv[2]', url)
}
console.log('Using', url)
win.maximize()
// BAD: All other methods don't work (like ensureFileSync, fileExists...)
try {
let settings = require('./settings.json')
console.log('Using settings', `file://${__dirname}/${settings.url}`)
win.loadURL(`file://${__dirname}/${settings.url}`)
} catch (ex) {
win.loadURL(url)
}
const { webContents } = win
//
// if (process.platform === 'win32' && win.isKiosk()) {
// webContents.on('did-finish-load', function() {
// webContents.executeJavaScript('document.body.style.cursor = "none";')
// })
// }
// Add the app menu
let menu = require('./menu.js')
global.menu = menu
// Add global shortcuts
// Esc quits the app
electronLocalshortcut.register('Esc', () => {
app.quit()
})
// Command (Mac) or Control (Win) + K toggles the Kiosk mode
electronLocalshortcut.register('CommandOrControl+K', () => {
if (win) {
win.setKiosk(!win.isKiosk())
}
})
// Show if its ready.
win.once('ready-to-show', () => {
webContents.send('preparePads')
win.show()
})
// Clear cache
webContents.session.clearCache(() => console.log('Cache cleared'))
// Open dev tools when in development mode
if (store.get('devTools')) {
webContents.openDevTools({ mode: 'right' })
} else {
webContents.closeDevTools()
}
webContents.on('devtools-opened', () => {
store.set('devTools', true)
})
webContents.on('devtools-closed', () => {
store.set('devTools', false)
})
webContents.on('did-navigate', (event, url) => {
menu.setHistoryStatus()
})
/* UO: At this point we have no access to the event or link position*/
webContents.on('new-window', (event, url, frameName, disposition, options, additionalFeatures) => {
console.log('new-window', global.multiUserMode)
if (global.multiUserMode) {
event.preventDefault()
webContents.send('newPad', url, options.x, options.y)
}
})
// WORKAROUND: On windows, if the app was set to fullscreen, the menubar is not hidden
if (win.isKiosk()) {
win.setMenuBarVisibility(false)
}
win.on('focus', event => {
menu.focus()
})
win.on('blur', event => {
menu.blur()
})
win.on('enter-full-screen', () => {
win.setMenuBarVisibility(false)
})
win.on('leave-full-screen', () => {
win.setMenuBarVisibility(true)
})
win.on('enter-html-full-screen', () => {
win.setMenuBarVisibility(false)
})
win.on('leave-html-full-screen', () => {
win.setMenuBarVisibility(true)
})
win.on('close', () => {
store.set('storedBounds', win.getBounds())
})
// Emitted when the window is closed.
win.on('closed', () => {
app.quit()
})
}
// When work makes progress, show the progress bar
function onProgress(progress) {
// Use values 0 to 1, or -1 to hide the progress bar
try {
win.setProgressBar(progress || -1) // Progress bar works on all platforms
} catch (e) {
if (DEVELOPMENT) console.log(e.message)
}
}
function trySend(target, ...args) {
try {
target.send(...args)
} catch (e) {
if (DEVELOPMENT) console.log(e.message)
}
}
function openBrowserView(url, x, y) {
const useMinBrowser = false // Change this to switch between Min and a custom browser
const minURL = 'file:///Users/uo/devel/min/index.html'
const browserURL = `file://${__dirname}/browser.html`
let width = 640
let height = 1200
let [winWidth, winHeight] = win.getSize()
if (x + width > winWidth) {
x = winWidth - width
}
if (y + height > winHeight) {
y = winHeight - height
}
console.log('open browser view')
let browser = new BrowserWindow({
x,
y,
width,
height,
minWidth: 320,
minHeight: 350,
titleBarStyle: useMinBrowser ? 'hidden-inset' : 'hidden',
frame: process.platform !== 'win32'
})
let browserContents = browser.webContents
browser.setAlwaysOnTop(true)
if (useMinBrowser) {
browserContents.on('did-finish-load', event => {
console.log('did-finish-load', browserContents.getURL())
browserContents.executeJavaScript(
'Object.values(window.webviews.elementMap).map(obj => obj.src)',
result => {
console.log(
'window.webviews',
result,
url,
result.indexOf(url)
)
if (result.indexOf(url) == -1) {
console.log('Adding tab')
browserContents.send('addTab', { url })
}
}
)
})
browser.loadURL(minURL)
} else {
console.log('Loading', browserURL)
browser.loadURL(browserURL)
let view = new BrowserView({
webPreferences: {
nodeIntegration: false,
devTools: true
}
})
//browserContents.openDevTools({mode: 'right'})
browser.setBrowserView(view)
view.setBounds({ x: 0, y: 24, width: width, height: height - 24 })
view.setAutoResize({ width: true, height: true })
let viewContents = view.webContents
let progress = 0
viewContents.on('page-title-set', event => {
console.log('page-title-set', event)
})
viewContents.on('page-favicon-updated', (event, favicons) => {
//console.log("page-favicon-updated", event, favicons)
trySend(browserContents, 'favicons', favicons)
})
viewContents.on('did-start-loading', event => {
onProgress(0)
trySend(browserContents, 'progress', 0)
trySend(browserContents, 'did-start-loading')
//let senderURL = event.sender.getURL() || url
//console.log('did-start-loading', senderURL)
})
viewContents.on(
'did-get-response-details',
(
event,
status,
newURL,
originalURL,
httpResponseCode,
requestMethod,
referrer,
headers,
resourceType
) => {
trySend(browserContents, 'did-get-response-details', {
status,
newURL,
originalURL,
httpResponseCode,
requestMethod,
referrer,
headers,
resourceType
})
progress += 0.01
onProgress(progress)
trySend(browserContents, 'progress', progress)
//console.log('did-get-response-details', newURL)
}
)
viewContents.on(
'did-get-redirect-request',
(
event,
oldURL,
newURL,
isMainFrame,
httpResponseCode,
requestMethod,
referrer,
headers
) => {
trySend(browserContents, 'did-get-redirect-request', {
oldURL,
newURL,
isMainFrame,
httpResponseCode,
requestMethod,
referrer,
headers
})
//console.log('did-get-redirect-request', newURL)
}
)
viewContents.on('did-stop-loading', event => {
//console.log('did-stop-loading', event.sender.getURL())
trySend(browserContents, 'did-stop-loading')
})
viewContents.on('did-finish-load', event => {
//console.log('did-finish-load', event.sender.getURL())
progress = 1
onProgress(progress)
trySend(browserContents, 'progress', progress)
})
viewContents.on('dom-ready', event => {
if (progress < 0.5) {
progress = 0.5
onProgress(progress)
trySend(browserContents, 'progress', progress)
}
viewContents.executeJavaScript('document.title', result => {
trySend(browserContents, 'title', result)
})
//console.log('dom-ready', event.sender.getURL())
})
viewContents.on('new-window', function (event, url) {
event.preventDefault()
console.log('new-window')
openBrowserView(url, x, y)
})
viewContents.loadURL(url)
}
browsers.set(url, browser)
browser.on('closed', e => {
for (let [url, browser] of browsers.entries()) {
if (browser == e.sender) {
browsers.delete(url)
console.log('removed browser view', url)
}
}
})
}
// UO: Experimental call. Opens a Min Browser window or a limited window with a browser view
ipcMain.on('loadBrowserView', (e, opts = {}) => {
let { url, x, y } = opts
openBrowserView(url, x, y)
})
ipcMain.on('multiUserMode', (e, opts = {}) => {
global.multiUserMode = opts
})
ipcMain.on('padContainerLoaded', e => {
win.webContents.send('padContainerAvailable')
})
ipcMain.on('createScreenshot', (e, opts = {}) => {
opts = Object.assign(
{},
{
name: `iwmbrowser-${new Date()
.toISOString()
.replace(/:/g, '-')}.png`,
path: os.tmpdir()
},
opts
)
win.webContents.capturePage(image => {
if (image) {
let file = path.join(opts.path, opts.name)
fs.writeFile(file, image.toPNG(), err => {
if (err) {
//throw err
} else {
console.log(`Screenshot saved: ${file}`)
}
})
}
})
})
ipcMain.on('directoryListing', (e, opts = {}) => {
let { directory, files, folders } = opts
console.log("directoryListing", opts)
try {
let listing = fs.readdirSync(directory)
let result = { directory, files: [], folders: [] }
for (let name of listing) {
if (name.startsWith('.'))
continue
let fullPath = path.join(directory, name)
let stat = fs.lstatSync(fullPath)
if (files && stat.isFile()) {
if (typeof files == 'string' && !files.endsWith(files))
continue
result.files.push(name)
}
if (folders && stat.isDirectory())
result.folders.push(name)
}
e.sender.send('directoryListing', result)
} catch (err) {
let args = { directory, errorMessage: err.message}
e.sender.send('directoryListingError', args)
}
})
ipcMain.on('createTextfile', (e, opts = {}) => {
opts = Object.assign(
{},
{
name: `iwmbrowser-${new Date()
.toISOString()
.replace(/:/g, '-')}.txt`,
path: os.tmpdir(),
text: ''
},
opts
)
let file = path.join(opts.path, opts.name)
fs.writeFile(file, opts.text, err => {
if (err) {
//throw err
} else {
console.log(`Textfile saved: ${file}`)
}
})
})
ipcMain.on('error', e => {
console.log('Received error notification')
global.errorCount += 1
})
ipcMain.on('openExternal', (e, url=null) => {
console.log('Received openExternal', url)
if (url) {
shell.openExternal(url)
}
})
ipcMain.on('save', (e, opts = {}) => {
let { url, html, saveAs, action } = opts
// url must absolute URL
let urlObj = new URL(url)
let pathname = urlObj.pathname
if (saveAs) {
pathname = dialog.showSaveDialog(win, { title: 'Save as:', defaultPath: pathname })
if (typeof pathname == 'undefined')
return
}
try {
console.log("Saving", pathname, action)
html = prettyPrint(html, { indent_size: 4 });
fs.writeFileSync(pathname, html, 'utf-8')
if (saveAs) {
let normalized = pathname.replace(/\\/g, '/')
e.sender.send('savedAs', {url: `file://${normalized}`, action})
}
}
catch (e) {
console.warn('Failed to save the file', pathname)
e.sender.send('saveFailed', pathname)
}
})
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', () => {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on(
'select-client-certificate',
(event, webContents, url, list, callback) => {
console.log('select-client-certificate', url, list)
event.preventDefault()
ipc.once('client-certificate-selected', (event, item) => {
console.log('selected:', item)
callback(item)
})
mainWindow.webContents.send('select-client-certificate', list)
}
)
app.on(
'certificate-error',
(event, webContents, url, error, certificate, callback) => {
console.log('certificate-error', url)
event.preventDefault()
const result = true // TODO: do real validation here
callback(result)
}
)
app.on('activate', () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (win === null) {
createWindow()
}
})
module.exports = {
store: store
}

629
browser/menu.js Normal file
View File

@ -0,0 +1,629 @@
/* globals require, process */
/*eslint no-console: ["error", { allow: ["log", "error"] }] */
const { Menu, app, shell, dialog } = require('electron')
const fs = require('fs')
const fse = require('fs-extra')
const os = require('os')
const path = require('path')
const { openProcessManager } = require('electron-process-manager')
const main = require('./main.js')
let { thumbnail } = require('./utils.js')
const loadTests = require('./test.js')
const i18n = new (require('./i18n.js'))()
function selectURL(url) {
url = url.replace(/\\/g, '/')
console.log('selectURL', url)
main.win.loadURL(url)
main.store.set('url', url)
}
function findItems(key, value) {
let items = []
for (let i = 0; i < menu.items.length; i++) {
for (let j = 0; j < menu.items[i].submenu.items.length; j++) {
let item = menu.items[i].submenu.items[j]
if (item[key] === value) {
items.push(item)
}
}
}
return items
}
function findItem(key, value) {
return findItems(key, value)[0]
}
function toggleBookmarks(bookmark) {
let items = findItems('class', 'bookmark')
for (let i = 0; i < items.length; i++) {
items[i].checked = false
}
bookmark.checked = true
}
function checkBookmark(url) {
let items = findItems('url', url)
if (items.length === 1) {
toggleBookmarks(items[0])
}
}
function setHistoryStatus() {
const historyBack = findItem('id', 'history-back')
historyBack.enabled = main.win.webContents.canGoBack()
const historyForward = findItem('id', 'history-forward')
historyForward.enabled = main.win.webContents.canGoForward()
}
function showSelectDataFolderDialog(focusedWindow) {
dialog.showOpenDialog(
{
title: i18n.__('selectfolder.select.title'),
buttonLabel: i18n.__('selectfolder.select.buttonLabel'),
properties: ['openDirectory', 'createDirectory', 'noResolveAliases', 'treatPackageAsDirectory']
},
(filePaths) => {
if (filePaths && filePaths.length === 1) {
const varPath = path.join(__dirname, '../var')
// Check if the same folder was used
if (filePaths[0].startsWith(varPath)) {
const same = filePaths[0] === varPath
dialog.showMessageBox(
{
type: 'error',
icon: path.join(__dirname, '../assets/icons/png/512x512-empty.png'),
buttons: [i18n.__('selectfolder.samefolder.ok')],
defaultId: 0,
message: i18n.__('selectfolder.samefolder.message'),
detail: same
? i18n.__('selectfolder.samefolder.detail.same')
: i18n.__('selectfolder.samefolder.detail.within'),
cancelId: 0
},
(response) => {
showSelectDataFolderDialog(focusedWindow)
}
)
} else {
// Backup
if (fse.pathExistsSync(varPath)) {
const varPathBackup = findNextVarFolder()
// Rename old var folder or link
fse.renameSync(varPath, varPathBackup)
} else {
// BUG: Workaround because pathExistsSync return false on existing symbolic links with a missing target
fse.removeSync(varPath)
}
// Add new symlink
main.store.set('dataFolder', filePaths[0])
fs.symlinkSync(filePaths[0], varPath, 'dir')
dialog.showMessageBox(
{
type: 'info',
icon: path.join(__dirname, '../assets/icons/png/link.png'),
buttons: [i18n.__('selectfolder.info.ok')],
defaultId: 0,
message: i18n.__('selectfolder.info.message'),
detail: i18n.__('selectfolder.info.detail').replace(/\$\{0\}/, filePaths[0]),
cancelId: 0
},
(response) => {
if (focusedWindow) focusedWindow.reload()
}
)
}
}
}
)
}
function findNextVarFolder() {
let exists = true
let counter = 0
while (exists) {
counter++
exists = fse.pathExistsSync(path.join(__dirname, `../var${counter}`))
}
return path.join(__dirname, `../var${counter}`)
}
function showFolderBrowser(focusedWindow) {
const varPath = path.join(__dirname, '../var')
const varPathExists = fse.pathExistsSync(varPath)
if (varPathExists) {
dialog.showMessageBox(
{
type: 'warning',
icon: path.join(__dirname, '../assets/icons/png/512x512-empty.png'),
buttons: [i18n.__('selectfolder.warning.next'), i18n.__('selectfolder.warning.cancel')],
defaultId: 1,
message: i18n.__('selectfolder.warning.message'),
detail: i18n.__('selectfolder.warning.detail'),
cancelId: 1
},
(response) => {
if (response === 0) {
showSelectDataFolderDialog(focusedWindow)
}
}
)
} else {
showSelectDataFolderDialog(focusedWindow)
}
}
const template = [
{
label: i18n.__('edit'),
submenu: [
{
role: 'undo',
label: i18n.__('undo')
},
{
role: 'redo',
label: i18n.__('redo')
},
{
type: 'separator'
},
{
role: 'cut',
label: i18n.__('cut')
},
{
role: 'copy',
label: i18n.__('copy')
},
{
role: 'paste',
label: i18n.__('paste')
},
{
role: 'pasteandmatchstyle',
label: i18n.__('pasteandmatchstyle')
},
{
role: 'delete',
label: i18n.__('delete')
},
{
role: 'selectall',
label: i18n.__('selectall')
}
]
},
{
label: i18n.__('view'),
submenu: [
{
label: i18n.__('reload'),
accelerator: 'CmdOrCtrl+R',
click(item, focusedWindow) {
if (focusedWindow) {
focusedWindow.webContents.setVisualZoomLevelLimits(1, 1)
focusedWindow.reload()
}
}
},
{
id: 'forcereload',
label: i18n.__('forcereload'),
accelerator: 'CmdOrCtrl+Shift+R',
click(item, focusedWindow) {
if (focusedWindow) {
focusedWindow.webContents.session.clearCache(() => console.log('Cache cleared'))
focusedWindow.webContents.setVisualZoomLevelLimits(1, 1)
focusedWindow.reload()
}
}
},
{
type: 'separator'
},
{
role: 'resetzoom',
label: i18n.__('resetzoom')
},
{
role: 'zoomin',
label: i18n.__('zoomin')
},
{
role: 'zoomout',
label: i18n.__('zoomout')
},
{
type: 'separator'
},
{
id: 'togglefullscreen',
label: i18n.__('togglefullscreen'),
accelerator: process.platform === 'darwin' ? 'Cmd+Ctrl+F' : 'F11',
click(item, focusedWindow) {
if (focusedWindow) {
focusedWindow.setFullScreen(!focusedWindow.isFullScreen())
}
}
},
{
type: 'separator'
},
{
label: i18n.__('multiuserbrowser'),
accelerator: 'CmdOrCtrl+M',
type: 'checkbox',
checked: true,
click(item, focusedWindow) {
if (focusedWindow) {
main.store.set('multiUserBrowser', item.checked)
global.multiUserMode = item.checked
}
}
},
{
label: i18n.__('minimalpad'),
accelerator: 'CmdOrCtrl+p',
type: 'checkbox',
checked: true,
click(item, focusedWindow) {
if (focusedWindow) {
main.store.set('minimalPad', item.checked)
global.useMinimalPad = item.checked
}
}
}
]
},
{
label: i18n.__('history'),
submenu: [
{
id: 'history-back',
label: i18n.__('back'),
accelerator: 'CmdOrCtrl+Left',
click(item, focusedWindow) {
main.win.webContents.goBack()
}
},
{
id: 'history-forward',
label: i18n.__('forward'),
accelerator: 'CmdOrCtrl+Right',
click(item, focusedWindow) {
main.win.webContents.goForward()
}
},
{
label: i18n.__('home'),
accelerator: 'CmdOrCtrl+Up',
click(item, focusedWindow) {
main.win.webContents.goToIndex(0)
}
},
{
type: 'separator'
},
{
label: i18n.__('recentlyvisited'),
enabled: false
}
]
},
{
label: i18n.__('bookmarks'),
submenu: [
{
label: i18n.__('localfilesystem'),
class: 'bookmark',
type: 'checkbox',
url: `file://${__dirname}/../index.html`,
accelerator: 'CmdOrCtrl+L',
click(item, focusedWindow) {
selectURL(item.url)
toggleBookmarks(item)
}
},
{
label: i18n.__('testframes'),
class: 'bookmark',
type: 'checkbox',
url: `file://${__dirname}/../index.html?test`,
accelerator: 'CmdOrCtrl+T',
click(item, focusedWindow) {
selectURL(item.url)
toggleBookmarks(item)
}
},
{
type: 'separator'
},
{
id: 'localhost',
label: 'https://localhost:8443',
class: 'bookmark',
type: 'checkbox',
enabled: false,
url: 'https://localhost:8443/index.html',
click(item, focusedWindow) {
selectURL(item.url)
toggleBookmarks(item)
}
},
{
id: 'localhost',
label: 'https://localhost:3000',
class: 'bookmark',
type: 'checkbox',
enabled: true,
url: 'https://localhost:3000/index.html',
click(item, focusedWindow) {
selectURL(item.url)
toggleBookmarks(item)
}
},
// {
// label: 'http://tornado.iwm-kmrc.de:8000',
// class: 'bookmark',
// type: 'checkbox',
// url: 'http://tornado.iwm-kmrc.de:8000/index.html',
// click(item, focusedWindow) {
// selectURL(item.url)
// toggleBookmarks(item)
// }
// },
{
label: 'http://rousseau.iwm-kmrc.de/index.html',
class: 'bookmark',
type: 'checkbox',
url: 'http://rousseau.iwm-kmrc.de/index.html',
click(item, focusedWindow) {
selectURL(item.url)
toggleBookmarks(item)
}
}
]
},
{
label: i18n.__('develop'),
submenu: [
{
id: 'toggledevelopertools',
label: i18n.__('toggledevelopertools'),
accelerator: process.platform === 'darwin' ? 'Alt+Command+I' : 'Ctrl+Shift+I',
click(item, focusedWindow) {
if (focusedWindow) focusedWindow.webContents.toggleDevTools()
}
},
{
label: i18n.__('openprocessmonitor'),
accelerator: process.platform === 'darwin' ? 'Alt+Command+P' : 'Ctrl+Shift+P',
click(item, focusedWindow) {
openProcessManager()
}
},
{
type: 'separator'
},
{
label: i18n.__('selectfolder'),
accelerator: process.platform === 'darwin' ? 'Alt+Command+D' : 'Ctrl+Shift+D',
click(item, focusedWindow) {
if (process.platform === 'win32') {
var exec = require('child_process').exec
exec('NET SESSION', function (err, so, se) {
const admin = se.length === 0 ? true : false
if (admin) {
showFolderBrowser(focusedWindow)
} else {
dialog.showMessageBox({
type: 'error',
icon: path.join(__dirname, '../assets/icons/png/512x512-empty.png'),
buttons: [i18n.__('selectfolder.noadmin.ok')],
message: i18n.__('selectfolder.noadmin.message'),
detail: i18n.__('selectfolder.noadmin.detail')
})
}
})
} else {
showFolderBrowser(focusedWindow)
}
}
},
{
type: 'separator'
},
{
id: 'startserver',
label: i18n.__('startserver'),
accelerator: process.platform === 'darwin' ? 'Alt+Command+S' : 'Ctrl+Shift+S',
click(item, focusedWindow) {
const { server } = require('../server/main.js')
server.start()
item.visible = false
findItem('id', 'stopserver').visible = true
findItem('id', 'localhost').enabled = true
}
},
{
id: 'stopserver',
label: i18n.__('stopserver'),
accelerator: process.platform === 'darwin' ? 'Alt+Command+S' : 'Ctrl+Shift+S',
visible: false,
click(item, focusedWindow) {
const { server } = require('../server/main.js')
server.stop()
item.visible = false
findItem('id', 'startserver').visible = true
findItem('id', 'localhost').enabled = false
}
},
{
type: 'separator'
},
{
label: i18n.__('runloadtests'),
accelerator: process.platform === 'darwin' ? 'Alt+Command+L' : 'Ctrl+Shift+L',
click(item, focusedWindow) {
loadTests(focusedWindow)
}
},
{
type: 'separator'
},
{
label: 'Aktualisiere Tüsch POIs',
click(item, focusedWindow) {
const UpdatePOI = require('../dev/tuesch/bin/menu/update-pois.js')
UpdatePOI.update('./dev/tuesch')
}
}
]
},
{
role: 'window',
label: i18n.__('window'),
submenu: [
{
role: 'close',
label: i18n.__('close')
},
{
role: 'minimize',
label: i18n.__('minimize')
},
{
role: 'zoom',
label: i18n.__('zoom')
},
{
type: 'separator'
},
{
role: 'front',
label: i18n.__('front')
},
{
type: 'separator'
},
{
label: i18n.__('screenshot'),
accelerator: 'CmdOrCtrl+S',
async click(item, focusedWindow) {
if (focusedWindow) {
await focusedWindow.webContents.capturePage().then((image) => {
let screenshotFile = path.join(os.tmpdir(), 'screenshot.png')
console.log('image captured', screenshotFile)
let url = focusedWindow.webContents.getURL()
if (url.startsWith('file://')) {
let normalized = path.normalize(url).replace('.html', '.png')
screenshotFile = normalized.replace('file:', '')
let thumbnailFile = screenshotFile.replace('index.png', 'thumbnail.png')
if (url.endsWith('index.html')) {
thumbnailFile = screenshotFile.replace('index.png', 'thumbnail.png')
} else {
let folderName = path.dirname(screenshotFile)
let baseName = path.basename(screenshotFile)
thumbnailFile = path.join(folderName, 'thumbnails', baseName)
}
fs.writeFile(thumbnailFile, thumbnail(image), (err) => {
if (err) {
throw err
} else {
console.log(`Thumbnail written to ${thumbnailFile}`)
}
})
}
fs.writeFile(screenshotFile, image.toPNG(), (err) => {
if (err) {
throw err
} else {
console.log(`Screenshot written to ${screenshotFile}`)
}
})
})
}
}
},
{
type: 'separator'
}
]
},
{
role: 'help',
label: i18n.__('help'),
submenu: [
{
label: i18n.__('iwm'),
click() {
shell.openExternal('https://www.iwm-tuebingen.de')
}
}
]
}
]
if (process.platform === 'darwin') {
const name = app.getName()
template.unshift({
label: name,
submenu: [
{
role: 'about',
label: i18n.__('about')
},
{
type: 'separator'
},
{
role: 'quit',
label: i18n.__('quit')
}
]
})
}
const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)
checkBookmark(main.store.get('url'))
setHistoryStatus()
function focus() {
findItem('id', 'forcereload').enabled = true
findItem('id', 'togglefullscreen').enabled = true
findItem('id', 'toggledevelopertools').enabled = true
}
function blur() {
findItem('id', 'forcereload').enabled = false
findItem('id', 'togglefullscreen').enabled = false
findItem('id', 'toggledevelopertools').enabled = false
}
module.exports = {
menu,
setHistoryStatus,
focus,
blur
}

171
browser/package.js Normal file
View File

@ -0,0 +1,171 @@
/* globals require, __dirname, process */
/*eslint no-console: ["error", { allow: ["log", "info", "warn", "error"] }]*/
const fse = require('fs-extra')
const path = require('path')
const packager = require('electron-packager')
const rebuild = require('electron-rebuild')
// Arguments
//----------------------
let folder = null
if (process.argv.length < 3) {
console.error('Missing command line parameter "folder"!')
process.exit(1)
} else {
folder = process.argv[2]
}
// Settings
//----------------------
let settings = null
const root = path.join(__dirname, '../')
try {
settings = require(`../${folder}/settings.json`)
} catch (e) {
console.error('Cannot read settings.json in folder, does it exist?')
process.exit(1)
}
// Read settings
//----------------------
const title = `--- Build "${settings.name || settings.id}" ---`
const line = Array(title.length + 1).join('-')
console.info(line)
console.info(title)
console.info(line)
// Using folder
//----------------------
const tempFolder = path.join(root, 'temp', settings.id)
console.log(`Using folder ${tempFolder}`)
// Delete temp folder (when last run aborted)
fse.removeSync(tempFolder)
console.log(`Folder ${tempFolder} deleted`)
// Create folder
fse.ensureDirSync(tempFolder)
console.log(`Folder ${tempFolder} created`)
// Create subfolders
const defaultFolders = ['assets', 'browser', 'css', 'lib', 'node_modules', 'server']
console.log(`The folders ${defaultFolders.join(', ')} are included by default`)
const folders = new Set(settings.browser.folders.concat(defaultFolders))
for (let folder of folders) {
console.log(`Copy folder ${folder}`)
const folderOld = path.join(root, folder)
const folderNew = path.join(root, 'temp', settings.id, folder)
fse.copySync(folderOld, folderNew)
}
// Write package.json
//----------------------
let json = {
name: settings.id,
productName: settings.name || settings.id,
version: settings.version,
main: 'browser/main.js',
dependencies: {}
}
// Read and write dependencies
const packageJson = fse.readJsonSync(path.join(root, 'package.json'))
Object.assign(json.dependencies, packageJson.dependencies)
// Add browser dependencies
if (settings.browser.dependencies) {
let dependencies = {}
for (let dependency of settings.browser.dependencies) {
dependencies[dependency] = '*'
}
Object.assign(json.dependencies, dependencies)
}
console.log('Create package.json')
fse.writeJsonSync(path.join(tempFolder, 'package.json'), json, {spaces: 4})
// Write URL to settings.json
//----------------------
console.log('Write URL to browser/settings.json')
fse.writeJsonSync(path.join(tempFolder, 'browser/settings.json'), {url: `../${folder}/index.html`}, {spaces: 4})
// Build with electron-packager
//----------------------
console.log('Start electron-packager')
packager({
dir: `./temp/${settings.id}`,
arch: 'x64',
asar: false,
overwrite: true,
out: './dist/electron',
icon: './assets/icons/icon',
platform: settings.browser.platform || ['darwin', 'win32'],
prune: false,
afterCopy: [(buildPath, electronVersion, platform, arch, callback) => {
console.log(`Rebuild Node.js modules for ${platform}...`)
rebuild.rebuild({buildPath, electronVersion, arch})
.then(() => {
console.log(`...Node.js modules for ${platform} rebuilded`)
callback()
})
.catch(error => {
console.error(`Error: ${error}`)
callback(error)
});
}]
})
.then(appPaths => {
console.log('electron-packager finished')
// Delete temp folder
//----------------------
fse.removeSync(tempFolder)
console.log(`Folder ${tempFolder} deleted`)
// Write data folders
//----------------------
if (settings.browser.data) {
console.log('Copy data folders')
for (let folder of settings.browser.data) {
for (let appPath of appPaths) {
console.log(`Copy folder ${folder} to ${appPath}`)
const source = path.join(root, folder)
const target = path.join(getResourcesPath(root, appPath), folder)
fse.copySync(source, target, {
dereference: true,
filter: item => {
if (settings.browser.dataExtensions && fse.lstatSync(item).isFile() && !settings.browser.dataExtensions.includes(path.extname(item).substring(1).toLowerCase())) {
return false
} else {
return true
}
}
})
}
}
}
// Finished
//----------------------
console.info('Finished')
})
.catch(error => {
console.error(error)
})
function getResourcesPath(root, appPath) {
let resourcesPath = ""
if (/darwin/.test(appPath) || /mas/.test(appPath)) {
resourcesPath = path.join(root, appPath, `${json.productName}.app/Contents/Resources/app`)
} else if (/win32/.test(appPath) || /linux/.test(appPath)) {
resourcesPath = path.join(root, appPath, 'resources/app')
}
return resourcesPath
}

570
browser/pad.js Normal file
View File

@ -0,0 +1,570 @@
const {fileURL} = require('./utils.js')
const path = require('path')
/* A specialization that ignores webview events and thus allows
* webviews to get touch, mouse and wheel events.
*/
class DOMPadContainer extends DOMScatterContainer {
capture(event) {
if (event.target.tagName === 'WEBVIEW' || event.target.classList.contains('interactiveElement'))
return false
return super.capture(event)
}
}
/* A wrapper for a webview that behaves like a virtual tablet browser.
* Uses a DOMScatter to zoom and rotate the virtual browser window.
* The position of buttons and the border size remain constant.
*/
class Pad {
constructor(scatterContainer, {
startScale=1.0, minScale=0.25, maxScale=10.5,
autoBringToFront=true,
url="https://www.iwm-tuebingen.de/www/index.html",
hideOnStart=false,
translatable=true, scalable=true, rotatable=true,
movableX=true,
movableY=true,
rotationDegrees=null,
rotation=null,
onTransform=null,
transformOrigin = 'center center',
// extras which are in part needed
x=0,
y=0,
width=null,
height=null,
resizable=false,
} ={}) {
this.x = x
this.y = y
this.url = url
this.hideOnStart = hideOnStart
this.width = width
this.height = height
this.minScale = minScale
this.maxScale = maxScale
this.scatterContainer = scatterContainer
this.startScale = startScale
this.scale = startScale
this.scalable = scalable
this.rotatable = rotatable
this.rotationDegrees = this.startRotationDegrees
this.transformOrigin = transformOrigin
this.frame = document.createElement('div')
this.frame.classList.add("pad")
this.border = 50 / startScale
Elements.setStyle(this.frame, {
backgroundColor: "#333",
position: "absolute",
display: 'flex',
width: this.width+"px",
height: this.height+"px",
top: 0,
left: 0,
// boxShadow: `10px 10px 10px rgba(0, 0, 0, 0.5)`,
// borderRadius: '10px',
overflow: "visible"})
document.body.appendChild( this.frame)
this.web=document.createElement("webview")
this.webBackground=document.createElement("div")
this.webViewSnapshot=document.createElement("img")
this.overlay = document.createElement('div')
this.loadAnim = document.createElement("div")
this.loadAnim.style.webkitAnimation= "spin 2s linear infinite"
this.loadAnim.style.animation= "spin 2s linear infinite"
this.loadAnim.style.position = "absolute"
document.styleSheets[0].insertRule('\
@keyframes spin {\
from { transform: rotateZ(0deg); }\
to { transform: rotateZ(360deg); }\
}'
)
this.overlay.appendChild(this.loadAnim)
Elements.setStyle(this.web, {
position: "absolute",
overflow: "auto",
border: "1px solid #fff"
})
// this.web.classList.add("interactiveElement")
// this.web.style.pointerEvents="none"
Elements.setStyle(this.webBackground, {
position: "absolute",
overflow: "auto",
background: "white"
})
Elements.setStyle(this.overlay, {
position: "absolute",
overflow: "auto",
background: "white",
opacity: "0.8"
})
Elements.setStyle(this.webViewSnapshot, {
position: "absolute",
overflow: "auto"
})
let timeTouchStart = 0
this.overlayCaptureEvents = document.createElement('div')
// overlay.style.background="white"
this.overlayCaptureEvents.classList.add("interactiveElement")
this.overlayCaptureEvents.addEventListener('touchmove',(e)=>{
e.preventDefault()
e.stopPropagation()
})
this.overlayCaptureEvents.addEventListener('pointerup',(e)=>{
e.preventDefault()
e.stopPropagation()
let p = {x:e.clientX, y:e.clientY}
let webviewPosition = Points.fromPageToNode(this.web,p)
let d = new Date()
if(d.getTime()-timeTouchStart<150)this.web.sendInputEvent({type:'mouseUp', x: webviewPosition.x, y: webviewPosition.y, button:'left', clickCount: 1})
})
this.overlayCaptureEvents.addEventListener('pointerdown',(e)=>{
e.preventDefault()
e.stopPropagation()
this.scatter.bringToFront()
let p = {x:e.clientX, y:e.clientY}
let webviewPosition = Points.fromPageToNode(this.web,p)
let d = new Date()
timeTouchStart = d.getTime()
this.web.sendInputEvent({type:'mouseDown', x: webviewPosition.x, y: webviewPosition.y, button:'left', clickCount: 1})
})
this.overlayCaptureEvents.addEventListener('pointermove',(e)=>{
if(e.pointerType!='mouse'){
let rotation = Angle.radian2degree(this.scatter.rotation);
rotation = (rotation + 360) % 360;
let r = Math.sqrt(Math.pow(e.movementX, 2) + Math.pow(e.movementY, 2));
let phi = Angle.radian2degree(Math.atan2(e.movementX, e.movementY));
phi = ((phi) + 630) % 360;
let rot = ((rotation + 90) + 630) % 360;
let diffAngle = ((0 + rot) + 360) % 360;
let phiCorrected = (phi + diffAngle + 360) % 360;
let deltaX = r * Math.cos(Angle.degree2radian(phiCorrected));
let deltaY = -r * Math.sin(Angle.degree2radian(phiCorrected));
this.web.executeJavaScript("window.scrollTo(scrollX+"+(-1*deltaX)+", scrollY+"+ (-1*deltaY)+")")
}
})
this.overlayCaptureEvents.addEventListener('mousewheel',(e)=>{
console.log("mousewheel",e.deltaY)
// webview.sendInputEvent({type:'mouseWheel', x: 0, y: 0, deltaX: e.deltaX, deltaY: -e.deltaY, canScroll: true })
this.web.executeJavaScript("window.scrollTo(scrollX+"+e.deltaX+", scrollY+"+ e.deltaY+")")
})
this.frame.appendChild(this.webBackground)
this.frame.appendChild(this.web)
this.frame.appendChild(this.webViewSnapshot)
this.frame.appendChild(this.overlay)
if(remote.getGlobal('multiUserMode'))this.frame.appendChild(this.overlayCaptureEvents)
this.webViewSnapshot.style.visibility="hidden"
this.web.src=url
this.web.preload= path.join(__dirname, './preloadPad.js')
this.closeButton = this.addButton("../assets/icons/svg/cross.svg", "close")
this.backButton = this.addButton("../assets/icons/svg/left.svg", "go back")
this.forwardButton = this.addButton("../assets/icons/svg/right.svg", "go forward")
this.backButton.style.opacity = 0.5
this.forwardButton.style.opacity = 0.5
/*for (let callback of window.padLoadedHandler) {
callback(this, url)
}*/
this.web.addEventListener('new-window', (e) => {
if(e.url.indexOf("youtube")>-1)return
if (urlPadMap.has(e.url)) {
let childPad = urlPadMap.get(e.url)
childPad.scatter.moveTo(x, y)
return childPad
}
let childPad = new Pad(this.scatterContainer, {
x: this.scatter.position.x+100,
y: this.scatter.position.y+100,
url: e.url,
width: this.scatter.width,
height: this.scatter.height,
scalable: true,
rotatable: true})
urlPadMap.set(e.url, childPad)
for(let callback of window.padLoadedHandler) {
callback(childPad, url)
}
})
this.web.addEventListener('did-navigate', (e) => {
this.enableButtons()
})
this.web.addEventListener('dom-ready',()=>{
//if(this.url.indexOf('local')>-1)this.web.openDevTools()
})
this.web.addEventListener('ipc-message', (e) => {
if(e.channel='webviewPointerDown')this.scatter.bringToFront()
})
this.web.addEventListener('did-start-loading', ()=>{
this.overlay.style.visibility="visible"
let w = this.overlay.offsetWidth
let h = this.overlay.offsetHeight
console.log("did start loading",h,w)
let animationSize = w<h ? w*0.5 : h*0.5
let animationRingWidth = animationSize*0.1;
this.loadAnim.style.border=animationRingWidth+"px solid #f3f3f3"
this.loadAnim.style.borderTop=animationRingWidth+"px solid #ffb18c"
this.loadAnim.style.borderRadius="50%"
this.loadAnim.style.height=animationSize-animationRingWidth*2+"px"
this.loadAnim.style.width=animationSize-animationRingWidth*2+"px"
this.loadAnim.style.top = h*0.25+"px"
this.loadAnim.style.left = w*0.25+"px"
w<h ? this.loadAnim.style.top = 0.5*(h-animationSize)+"px" : this.loadAnim.style.left = 0.5*(w-animationSize)+"px"
})
this.web.addEventListener('did-stop-loading', ()=>{
this.overlay.style.visibility="hidden"
})
/*this.backButton.addEventListener('click', ()=>{
if(this.web.canGoBack())
this.web.goBack()
})
this.forwardButton.addEventListener('click', ()=>{
if(this.web.canGoForward())
this.web.goForward()
})
this.closeButton.addEventListener('click', ()=>{
this.close()
})*/
InteractionMapper.on('tap',this.backButton, e => {
if(this.web.canGoBack())
this.web.goBack()
})
InteractionMapper.on('tap',this.forwardButton, e => {
if(this.web.canGoForward())
this.web.goForward()
})
InteractionMapper.on('tap',this.closeButton, e => {
this.close()
})
this.scatter = new DOMScatter(this.frame, scatterContainer, {
x: this.x,
y: this.y,
startScale: this.startScale,
width: this.width,
height: this.height,
minScale: this.minScale,
maxScale: this.maxScale,
scalable: this.scalable,
resizable: true,
rotatable: this.rotatable})
let img=document.createElement("img")
img.style.width = "70%"
img.style.position = "absolute"
img.style.bottom = "20%"
img.style.right = "20%"
img.style.pointerEvents="none"
img.src = "../../assets/icons/png/flat/resize.png"
this.scatter.resizeButton.appendChild(img)
this.scatter.moveTo({x, y})
this.scatter.bringToFront()
this.scatter.addTransformEventCallback((e) => {
let newBorder = 50 / e.scale
if (newBorder !== this.border) {
this.border = newBorder
this.layout()
}
})
this.layout()
}
rad2degree(alpha){
return alpha * 180 / Math.PI;
}
degree2rad(alpha){
return alpha * Math.PI / 180;
}
close() {
// this.frame.style.display="none"
this.frame.parentNode.removeChild(this.frame)
urlPadMap.delete(this.url)
}
enableButtons() {
this.backButton.style.opacity = (this.web.canGoBack()) ? 1 : 0.5
this.forwardButton.style.opacity = (this.web.canGoForward()) ? 1 : 0.5
}
addButton(src, value) {
let button = document.createElement("img")
button.type = "image"
button.className = "frameButton"
button.style.position = "absolute"
button.src = fileURL(src)
button.value="close"
button.draggable = false
button.classList.add("interactiveElement")
this.frame.appendChild(button)
return button
}
layout() {
let b = this.border
let b2 = b * 2
let b8 = b / 8
let b25 = b / 25
let b15 = b / 15
this.scatter.resizeButton.style.width=b+"px"
this.scatter.resizeButton.style.height=b+"px"
Elements.setStyle(this.frame, {
// borderRadius: b8 + "px",
// boxShadow: `${b25}px ${b15}px ${b8}px rgba(0, 0, 0, 0.5)`
})
let size = "calc(100% - " + (2*b+2) +"px)"
Elements.setStyle(this.web, {
width: size,
height: size,
margin: b+"px"})
Elements.setStyle(this.webViewSnapshot, {
width: size,
height: size,
margin: b+"px"})
Elements.setStyle(this.webBackground, {
width: size,
height: size,
margin: b+"px"})
Elements.setStyle(this.overlay, {
width: size,
height: size,
margin: b+"px"})
Elements.setStyle(this.overlayCaptureEvents, {
width: size,
height: size,
opacity: 0.0001,
background: "white",
margin: b+"px"})
Elements.setStyle(this.closeButton, {
right: (b * 1.75) + "px",
bottom: "0px",
width: b+"px",
height: b+"px"})
Elements.setStyle(this.backButton, {
left: (b * 0.8) +"px",
bottom: "0px",
width: b+"px",
height: b+"px"})
Elements.setStyle(this.forwardButton, {
left: (this.border + (b * 0.8)) +"px",
bottom: "0px",
width: b+"px",
height: b+"px"})
}
}
class PadFromElement {
constructor(element, scatterContainer, {
startScale=1.0, minScale=0.1, maxScale=1.0,
autoBringToFront=true,
translatable=true, scalable=true, rotatable=true,
movableX=true,
movableY=true,
rotationDegrees=null,
rotation=null,
onTransform=null,
transformOrigin = 'center center',
// extras which are in part needed
x=0,
y=0,
width=null,
height=null,
resizable=false,
} ={}) {
this.element = element
this.x = x
this.y = y
this.width = width
this.height = height
this.minScale = minScale
this.maxScale = maxScale
this.scatterContainer = scatterContainer
this.scale = startScale
this.scalable = scalable
this.rotatable = rotatable
this.rotationDegrees = this.startRotationDegrees
this.transformOrigin = transformOrigin
this.frame = document.createElement('div')
Elements.setStyle(this.frame, {
width: this.width+"px",
height: this.height+"px",
backgroundColor: "#333",
position: "fixed",
top: 0,
left: 0,
overflow: "auto"})
this.closeButton = this.addButton("../assets/icons/svg/cross.svg", "close")
document.body.appendChild( this.frame)
this.border = 50
this.frame.appendChild(this.element)
this.title = document.createElement("div")
this.title.innerHTML = "Titel"
this.title.style.color = "white"
this.frame.appendChild(this.title)
Elements.setStyle(this.title, {
position: "absolute"
})
// this.element.style.overflow = "auto"
// this.element.style.position = "absolute"
this.layout()
this.closeButton.addEventListener('click', ()=>{
this.frame.style.display="none"
})
this.scatter = new DOMScatter(this.frame, scatterContainer, {
x: this.x,
y: this.y,
startScale: this.startScale,
width: this.width,
height: this.height,
minScale: this.minScale,
maxScale: this.maxScale,
scalable: this.scalable,
resizable: true,
rotatable: this.rotatable})
this.scatter.bringToFront()
this.scatter.addTransformEventCallback((e) => {
let newBorder = 50 / e.scale
if (newBorder !== this.border) {
this.border = newBorder
this.layout()
}
})
this.element.addEventListener('pointerdown', (e) => {
this.scatter.bringToFront()
})
}
close() {
// this.frame.style.display="none"
this.frame.parentNode.removeChild(this.frame)
urlPadMap.delete(this.url)
}
addButton(src, value) {
let button = document.createElement("img")
button.type = "image"
button.className = "frameButton"
button.style.position = "absolute"
button.src = fileURL(src)
button.value="close"
button.draggable = false
this.frame.appendChild(button)
return button
}
layout() {
let b = this.border
let b2 = b * 2
let b8 = b / 8
let b25 = b / 25
let b15 = b / 15
this.scatter.resizeButton.style.width=b+"px"
this.scatter.resizeButton.style.height=b+"px"
Elements.setStyle(this.frame, {
// borderRadius: b8 + "px",
// boxShadow: `${b25}px ${b15}px ${b8}px rgba(0, 0, 0, 0.5)`
})
let size = "calc(100% - " + (2*b+2) +"px)"
Elements.setStyle(this.element, {
width: size,
height: size,
top: b+"px",
left: b+"px"})
Elements.setStyle(this.closeButton, {
right: (b * 0.75) + "px",
bottom: "0px",
width: b+"px",
height: b+"px"})
Elements.setStyle(this.title, {
left: (b * 1.5) + "px",
fontSize: (b * 0.8) + "px",
top: (0.1)+"0px"})
}
}
module.exports = { Pad, DOMPadContainer, PadFromElement }

3540
browser/padAccordion.js Normal file

File diff suppressed because it is too large Load Diff

2814
browser/padAccordionOld.js Normal file

File diff suppressed because it is too large Load Diff

1380
browser/padMinimal.js Normal file

File diff suppressed because it is too large Load Diff

231
browser/preload.js Normal file
View File

@ -0,0 +1,231 @@
const { fileURL, loadScript, hideCursor, showCursor } = require('./utils.js')
let { remote } = require('electron')
const webFrame = require('electron').webFrame
// UO: Disable unintended zoom of fullscreen page if user wants to zoom
// only parts like Eyevisit info cards.
console.log('Disable pinch zoom', webFrame)
webFrame.setVisualZoomLevelLimits(1, 1)
let padContainer = null
let hideCursorTimeout = null
let debug = false
let urlPadMap = new Map()
window.urlPadMap = urlPadMap
window.padLoadedHandler = []
window.nodeDirname = __dirname
function pageSize() {
var w = window,
d = document,
e = d.documentElement,
g = d.getElementsByTagName('body')[0],
width = w.innerWidth || e.clientWidth || g.clientWidth,
height = w.innerHeight || e.clientHeight || g.clientHeight
return [width, height]
}
let size = pageSize()
let pageWidth = size[0]
let pageHeight = size[1]
/* Open a new at x, y position. */
function openPad(url, x, y) {
console.log('openPad')
if (remote.getGlobal('useBrowserView')) {
return ipcRenderer.send('loadBrowserView', { url, x, y })
}
const { Pad } = require('./pad.js')
const { minimalPad } = require('./padMinimal.js')
pad = null
if (urlPadMap.has(url)) {
let pad = urlPadMap.get(url)
pad.scatter.bringToFront()
/*TweenMax.to(pad.frame, 0.5, {
boxShadow: "0 0 25px 5px white", onComplete: () => {
TweenMax.to(pad.frame, 0.5, { boxShadow: "none" })
}
})*/
TweenMax.to(pad.frame, 0.2, {
scale: '1.01',
onComplete: () => {
TweenMax.to(pad.frame, 0.2, { scale: '1' })
}
})
// pad.scatter.moveTo(x, y)
return pad
}
y + 1600 > pageHeight ? (y = pageHeight - 1600) : (y = y)
if (remote.getGlobal('useMinimalPad')) {
pad = new minimalPad(padContainer, {
x: x,
y: y,
url: url,
tabbedView: true,
hasTtitleBar: false,
hideOnStart: false,
startScale: 1,
width: 1000,
height: 1500,
scalable: true,
rotatable: true
})
}
if (!remote.getGlobal('useMinimalPad')) {
pad = new Pad(padContainer, {
x: x,
y: y,
url: url,
hideOnStart: false,
startScale: 1,
width: 1000,
height: 1500,
scalable: true,
rotatable: true
})
}
urlPadMap.set(url, pad)
for (let callback of window.padLoadedHandler) {
callback(pad, url)
}
}
window.padLoadedHandler.push((pad, url) => {
console.log('Add specific behavior')
})
/* According to https://electron.atom.io/docs/faq/
"I can not use jQuery/RequireJS/Meteor/AngularJS in Electron" we
have to rename the symbols in the page before including other libraries.
Remember to use nodeRequire after this point.
*/
window.nodeRequire = require
delete window.require
delete window.exports
delete window.module
/* Create a DOMPadContainer, i.e. a special DOMScatterContainer, as a wrapper
of the document body.
*/
window.addEventListener('load', e => {
console.log('preloading')
// ../iwmlib/dist/iwmlib.3rdparty.js
// loadScript('../iwmlib/lib/3rdparty/preload.js', () => {
loadScript('../../iwmlib/dist/iwmlib.3rdparty.preload.js', () => {
//console.log("../iwmlib/dist/iwmlib.3rdparty.js loaded")
console.log('greensock loaded')
// loadScript('../iwmlib/dist/iwmlib.js', () => {
loadScript('../../iwmlib/dist/iwmlib.js', () => {
console.log('../iwmlib/dist/iwmlib.js loaded')
/* const { Pad, DOMPadContainer } = nodeRequire('./pad.js')
padContainer = new DOMPadContainer(document.body)
window.nodePadContainer = padContainer
ipcRenderer.send('padContainerLoaded') */
/*Register a handler for mousemove events. Hide the cursor a few
*seconds after the last move event.
*/
document.body.addEventListener('mousemove', e => {
showCursor()
clearTimeout(hideCursorTimeout)
hideCursorTimeout = setTimeout(hideCursor, 3000)
})
})
if (debug) {
loadScript('../iwmlib/dist/iwmlib.pixi.js', () => {
console.log('../iwmlib/dist/iwmlib.pixi.js loaded')
const DebugApp = require('./debug.js')
let debugApp = new DebugApp(document.body)
debugApp.setup()
debugApp.run()
})
}
})
})
/* Register a handler for all click events and check whether the link target
opens a new window. If the link target is blank, prevent the default behavior
and create a Pad scatter object instead.
*/
window.addEventListener('click', e => {
let node = e.target
let url = ''
let target = ''
let multiUserMode = false // remote.getGlobal('multiUserMode') // DOMScatter && remote.getGlobal('multiUserMode')
// console.log("click", multiUserMode, remote.getGlobal('multiUserMode'))
if (multiUserMode) {
while (node !== null) {
if (node.tagName === 'A' || node.tagName === 'a') {
if (node.target instanceof SVGAnimatedString) {
url = node.href.baseVal
target = node.target.baseVal
} else {
url = node.href
target = node.target
}
if (target === '_blank') {
e.preventDefault()
openPad(url, e.clientX, e.clientY)
}
return
}
node = node.parentNode
}
}
})
/* Register a handler for contextmenu events and check whether the link target
// opens a new window. If the link target is blank, prevent the default behavior
and show a popup menu with the option to open a pad instead.
*/
window.addEventListener('contextmenu', e => {
let node = e.target
let url = null
if (remote.getGlobal('multiUserMode')) {
while (node !== null) {
if (node.tagName === 'A' || node.tagName === 'a') {
if (node.target instanceof SVGAnimatedString) {
url = node.href.baseVal
} else {
url = node.href
}
e.preventDefault()
let point = { x: e.clientX, y: e.clientY }
PopupMenu.open(
{
'Open new Pad': () => openPad(url, e.clientX, e.clientY)
},
point,
{ fontSize: '0.8em' }
)
return
}
node = node.parentNode
}
}
})
/* Special error handling if the rendere process sends a error notification
log this error on the main console.
*/
let { Console } = require('console')
let debugConsole = new Console(process.stdout, process.stderr)
let { ipcRenderer } = require('electron')
window.addEventListener('error', event => {
debugConsole.error('PAGE ERROR', event.error, event.filename)
debugConsole.error('open', window.location.href)
ipcRenderer.send('error', 1)
})
ipcRenderer.on('newPad', (e, data) => {
openPad(data, 0, 0)
})

83
browser/preloadPad.js Normal file
View File

@ -0,0 +1,83 @@
let { remote } = require('electron')
let { ipcRenderer } = require('electron')
const path = require('path')
const webFrame = require('electron').webFrame
console.log('Disable pinch zoom', webFrame)
webFrame.setVisualZoomLevelLimits(1, 1)
window.nodePath = path
window.nodeDirname = __dirname
window.nodeRequire = require
delete window.require
delete window.exports
delete window.module
window.padLoadedHandler = []
let pointerCounter = 0
window.addEventListener('pointerdown', (e) => {
//e.preventDefault()
// console.log("ipcRenderer.sendToHost('webviewPointerDown')")
ipcRenderer.sendToHost('webviewPointerDown')
})
window.addEventListener('pointerup', (e) => {
// console.log("ipcRenderer.sendToHost('webviewPointerUp')")
ipcRenderer.sendToHost('webviewPointerUp')
})
window.addEventListener('pointerenter', (e) => {
// console.log("ipcRenderer.sendToHost('webviewPointerEnter')")
ipcRenderer.sendToHost('webviewPointerEnter')
})
window.addEventListener('pointercancel', (e) => {
// console.log("ipcRenderer.sendToHost('webviewPointerCancel')")
ipcRenderer.sendToHost('webviewPointerCancel')
})
window.addEventListener('pointerleave', (e) => {
// console.log("ipcRenderer.sendToHost('webviewPointerLeave')")
ipcRenderer.sendToHost('webviewPointerLeave')
})
window.addEventListener('pointerout', (e) => {
// console.log("ipcRenderer.sendToHost('webviewPointerOut')")
ipcRenderer.sendToHost('webviewPointerOut')
})
window.addEventListener('pointerover', (e) => {
// console.log("ipcRenderer.sendToHost('webviewPointerOver')")
ipcRenderer.sendToHost('webviewPointerOver')
})
window.addEventListener('pointermove', (e) => {
// console.log("ipcRenderer.sendToHost('webviewPointerMove')")
ipcRenderer.sendToHost('webviewPointerMove')
})
window.addEventListener('touchmove', (e) => {
// console.log("ipcRenderer.sendToHost('touchmove')")
ipcRenderer.sendToHost('touchMove')
})
window.addEventListener('touchstart', (e) => {
pointerCounter++
// console.log("ipcRenderer.sendToHost('touchstart')")
ipcRenderer.sendToHost('touchStart')
})
window.addEventListener('touchend', (e) => {
pointerCounter--
// console.log("ipcRenderer.sendToHost('touchend')")
ipcRenderer.sendToHost('touchEnd')
})
ipcRenderer.on('overlayEvent', function () {
console.log('hello world From Preload')
})

47
browser/store.js Normal file
View File

@ -0,0 +1,47 @@
const electron = require('electron')
const path = require('path')
const fs = require('fs')
class Store {
constructor(opts) {
// Renderer process has to get `app` module via `remote`, whereas the main process can get it directly
// app.getPath('userData') will return a string of the user's app data directory path.
const userDataPath = (electron.app || electron.remote.app).getPath('userData')
// We'll use the `configName` property to set the file name and path.join to bring it all together as a string
this.path = path.join(userDataPath, opts.configName + '.json')
this.data = parseDataFile(this.path, opts.defaults)
this.data = Object.assign(opts.defaults, this.data)
}
// This will just return the property on the `data` object
get(key) {
return this.data[key]
}
// ...and this will set it
set(key, val) {
this.data[key] = val
// Wait, I thought using the node.js' synchronous APIs was bad form?
// We're not writing a server so there's not nearly the same IO demand on the process
// Also if we used an async API and our app was quit before the asynchronous write had a chance to complete,
// we might lose that data. Note that in a real app, we would try/catch this.
fs.writeFileSync(this.path, JSON.stringify(this.data))
}
}
function parseDataFile(filePath, defaults) {
// We'll try/catch it in case the file doesn't exist yet, which will be the case on the first application run.
// `fs.readFileSync` will return a JSON string which we then parse into a Javascript object
try {
return JSON.parse(fs.readFileSync(filePath))
} catch(error) {
// if there was some kind of error, return the passed in defaults instead.
return defaults
}
}
// expose the class
module.exports = Store

113
browser/test.js Normal file
View File

@ -0,0 +1,113 @@
let fs = require('fs')
let path = require('path')
let {thumbnail} = require('./utils.js')
let pairs = []
let urlMap = new Map()
function isFile(path) {
try {
return !fs.lstatSync(path).isDirectory()
} catch(e) {
if (e.code == 'ENOENT'){
return false
} else {
return false
}
}
}
function listPairs(src, dst, skipFiles=true) {
let dir = fs.readdirSync(src)
for(let name of dir) {
let srcPath = src + name
if (isFile(srcPath) && !skipFiles) {
if (srcPath.endsWith('.html')) {
let dstPath = dst + name.replace(/.html/, '.png')
pairs.push([srcPath, dstPath])
}
}
else {
if (srcPath.endsWith('.'))
continue
let indexPath = srcPath + path.sep + 'index.html'
if (isFile(indexPath)) {
let thumbnailPath = indexPath.replace(/index.html/, 'thumbnail.png')
pairs.push([indexPath, thumbnailPath])
}
}
}
}
function capturePage(focusedWindow, dstPath) {
focusedWindow.capturePage( (image) => {
fs.writeFile(dstPath, thumbnail(image), (err) => {
if (err) throw err;
nextLoadTest(focusedWindow)
})
})
}
function testLoading(focusedWindow, filePath, dstPath) {
let urlPath = filePath.replace(path.sep, '/')
let basePath = `${__dirname}`.replace('/browser', '')
let shortURL = `file://${basePath}/${urlPath}`
let fullURL = `file://${__dirname}/../../${urlPath}`
// console.log({basePath, shortURL, fullURL})
if (focusedWindow) {
urlMap.set(shortURL, dstPath)
focusedWindow.webContents.session.clearCache(() => console.log('Cache cleared'))
focusedWindow.webContents.loadURL(shortURL)
}
}
function listLibPairs() {
let src = "lib" + path.sep
let dst = "lib" + path.sep + 'thumbnails' + path.sep
listPairs(src, dst, false)
}
function listAppPairs() {
let src = "apps" + path.sep
let dst = "apps" + path.sep
listPairs(src, dst)
}
function listSrcPairs() {
let src = "src" + path.sep
let dst = "src" + path.sep
listPairs(src, dst)
}
function nextLoadTest(focusedWindow) {
if (global.errorCount > 0 && global.stopTestsOnError) {
console.log("Test aborted")
return
}
if (pairs.length > 0) {
let [file, image] = pairs.pop()
testLoading(focusedWindow, file, image)
}
else {
console.log("All thumbnails created")
}
}
function loadTests(focusedWindow) {
global.errorCount = 0
focusedWindow.webContents.on('did-finish-load', (e) => {
setTimeout(() => {
let url = e.sender.history[e.sender.history.length-1]
dstPath = urlMap.get(url)
capturePage(focusedWindow, dstPath)
}, 5000)
})
listLibPairs()
listSrcPairs()
listAppPairs()
nextLoadTest(focusedWindow)
}
module.exports = loadTests

38
browser/utils.js Normal file
View File

@ -0,0 +1,38 @@
function fileURL(src) {
let dir = __dirname.replace(/\\/g, '/')
return `file://${dir}/${src}`
}
function loadScript(src, callback) {
let url = fileURL(src)
let script = document.createElement('script')
script.onload = () => {
if (callback) {
callback.call(this, script)
}
}
script.src = url
document.head.appendChild(script)
}
function thumbnail(screenshot) {
return screenshot.resize({ width: 1024 }).toPNG()
}
let hiddenCursor = fileURL('../assets/cursor/cur0000.cur')
let defaultCursor = fileURL('../assets/cursor/cur1054.cur')
function hideCursor() {
// console.log("hideCursor")
document.body.style.cursor = `url('${hiddenCursor}'), default`
}
function showCursor() {
document.body.style.cursor = `url('${defaultCursor}'), default`
// console.log("showCursor")
}
module.exports = {
fileURL, loadScript, thumbnail, hideCursor, showCursor
}

11
css/article.css Normal file
View File

@ -0,0 +1,11 @@
body {
background-color: white;
color: black;
width: 100%;
height: 100%;
}
article {
top: 66px;
}

10719
css/bulma.css vendored Normal file

File diff suppressed because it is too large Load Diff

1
css/bulma.css.map Normal file

File diff suppressed because one or more lines are too long

440
css/card.css Normal file
View File

@ -0,0 +1,440 @@
@font-face {
font-family: "Material Icons";
font-style: normal;
font-weight: 400;
src: url(../fonts/material-icon-font/MaterialIcons-Regular.eot);
/* For IE6-8 */
src: local("Material Icons"), local("MaterialIcons-Regular"), url(../fonts/material-icon-font/MaterialIcons-Regular.woff2) format("woff2"), url(../fonts/material-icon-font/MaterialIcons-Regular.woff) format("woff"), url(../fonts/material-icon-font/MaterialIcons-Regular.ttf) format("truetype");
}
.material-icons {
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
font-size: 24px;
/* Preferred icon size */
display: inline-block;
line-height: 1;
text-transform: none;
letter-spacing: normal;
word-wrap: normal;
white-space: nowrap;
direction: ltr;
/* Support for all WebKit browsers. */
-webkit-font-smoothing: antialiased;
/* Support for Safari and Chrome. */
text-rendering: optimizeLegibility;
/* Support for Firefox. */
-moz-osx-font-smoothing: grayscale;
/* Support for IE. */
-webkit-font-feature-settings: 'liga';
font-feature-settings: 'liga';
}
html {
width: 100%;
height: 100%;
background-color: lightgray;
}
header {
color: white;
min-height: 33%;
}
main {
min-height: 67%;
}
article {
margin: 0px;
padding: 32px;
padding-right: 64px;
position: absolute;
overflow: hidden;
top: 66px;
}
.preview img {
max-height: 120px;
width: 80%;
height: 100%;
object-fit: cover;
}
.preview p {
margin-top: 44px;
}
.preview {
text-align: center;
display: inline;
}
.thumbnail {
position: relative;
box-shadow: 1px 3px 8px rgba(0, 0, 0, 0.1);
border: 2px solid lightgrey;
float: left;
margin: 12px;
max-height: 300px;
max-width: 480px;
height: auto;
width: auto;
}
.mainview {
background-color: #444;
color: white;
padding: 32px;
position: absolute;
overflow: hidden;
width: 1400px;
height: 1200px;
font-size: 1.5rem;
}
.subcard {
position: relative;
background-color: white;
height: 300px;
max-width: 400px;
}
.svg-wrapper {
text-align: center;
}
.subcard h3 {
color: black;
margin-left: auto;
margin-right: auto;
}
.card-icon {
width: 44px;
height: 44px;
}
.zoom-icon {
position: absolute;
right: 0px;
bottom: 0px;
width: 44px;
height: 44px;
}
.zoomable-wrapper {
display: inline-block;
-ms-flex-item-align: center;
-ms-grid-row-align: center;
align-self: center;
font-size: 0;
}
.zoomable-wrapper figure {
display: inline-block;
}
.zoomable-wrapper figcaption {
font-size: initial;
}
.zoomable-wrapper>figure>div {
height: 100%;
}
.zoomable-wrapper svg {
overflow: visible;
width: 100%;
height: 100%;
}
/* ------------ zoomables and zoomed items below ------------ */
.imggroupcontainer {
margin-top: 10px;
text-align: justify;
}
.imggroupcontainer:after {
content: '';
display: inline-block;
width: 100%;
}
.imggroupcontainer:before {
content: '';
display: block;
margin-top: -1.25em;
}
.imgcontainer {
text-align: center;
}
figure {
position: relative;
display: inline-block;
margin-left: auto;
margin-right: auto;
}
.singlefig {
max-width: 50%;
margin-top: 10px;
}
.videofig {
max-width: 100%;
margin-top: 10px;
}
.groupfig {
max-width: 100%;
margin-top: 10px;
}
figure img {
object-fit: cover;
}
figure svg {
object-fit: cover;
}
figure video {
object-fit: cover;
/*box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.5);
border: 10px solid rgba(122, 0, 0, 0.05);*/
}
figure .mainimg {
display: block;
overflow: hidden;
/*box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.5);
border: 10px solid rgba(122, 0, 0, 0.05);*/
}
figure .groupmainimg {
display: block;
overflow: hidden;
/*box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.5);
border: 10px solid rgba(122, 0, 0, 0.05);*/
}
figcaption {
/* position: absolute; */
text-align: center;
padding-top: 6px;
padding-left: 0px;
padding-right: 0px;
padding-bottom: 6px;
font-size: 12px;
}
.zoomcap {
/*position: absolute;*/
display: none;
overflow: hidden;
background: white;
box-shadow: 1px 4px 8px rgba(0, 0, 0, 0.5);
width: 100%;
padding: 10px;
}
.cap {
width: 100%;
}
.zoomed-figure {
position: absolute;
font-family: 'MyriadRegular', sans-serif;
background: white;
box-shadow: 1px 3px 8px rgba(0, 0, 0, 0.5);
display: flex;
margin-top: 0px;
margin-bottom: 0px;
}
.zoomed-figure img {
top: 0px;
/*box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.5);
border: 10px solid rgba(122, 0, 0, 0.05);*/
}
.zoomed-figure figure {
margin-top: 0px;
margin-bottom: 0px;
box-shadow: none;
}
.zoomed-figure figcaption {
color: black;
}
.ZoomedIcon {
top: 0px;
left: 0px;
}
.subcard-content {
padding: 25px;
display: flex;
flex-direction: column;
overflow: hidden;
height: 100%;
-webkit-hyphens: auto;
}
/* ------------ bulma overwrites below ------------ */
.content h1 {
min-height: 70px;
color: white;
}
.content figure {
background: transparent;
display: block;
margin-left: 0em;
margin-right: 0em;
}
.card-content {
padding: 25px;
display: flex;
flex-direction: column;
overflow: hidden;
height: 100%;
-webkit-hyphens: auto;
}
.content:not(:last-child) {
text-align: center;
}
.card-icon, .zoomable-icon {
position: absolute;
bottom: 0;
right: 0;
}
.speech-only-text {
opacity: 0;
position: absolute;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
pointer-events: none;
z-index: -1;
}
figure .icon {
position: absolute;
bottom: 0;
right: 0;
}
.button {
border: 0px solid transparent;
border-radius: 0px;
}
.button:hover {
color: #f2f2f2;
}
.view-button.icon {
background-color: #6699FF;
color: white;
position: absolute;
bottom: 0;
right: 0;
}
.view-button.icon.inverted:before {
color: #f2f2f2;
}
.view-button.icon:before {
font-size: 36px;
}
.view-button.icon:hover {
color: #f2f2f2;
}
.icon {
min-width: 44px;
min-height: 44px;
color: white;
background-color: #6699FF;
pointer-events: none;
}
.icon.button {
pointer-events: all;
}
.icon.button.corner-button {
border-radius: 0;
}
.icon.button.corner-button.bottom-right {}
.icon.inverted {
color: #f2f2f2;
background-color: #6699FF;
}
.icon.transparent-background {
background-color: #6699FF;
}
.icon.active {
color: #f2f2f2;
background-color: #6699FF;
}
.icon:before {
font-family: "Material Icons";
font-size: 36px;
}
.icon.info {
background-color: transparent;
font-size: 10px;
}
.icon.info:before {
font-size: 44px;
color: transparent;
content: url("../assets/images/info.svg") "w";
}
.icon.close:before {
content: "close";
}
.icon.zoom:before {
content: "search";
}
.icon.speech:before {
content: "record_voice_over";
}
.icon.language:before {
content: "language";
}
.info-card.debug .view-button {
background-color: rgba(255, 0, 0, 0.5) !important;
}
.info-card.debug .view-button.disabled {
-webkit-filter: grayscale(1);
filter: grayscale(1);
}

View File

@ -1,12 +1,208 @@
html
{
padding: 0px;
font-size: 16px;
background: white;
font-family: Arial,sans-serif;
color: #000;
max-width: 932px;
margin:0 auto;
:root {
--white: rgb(250, 250, 250);
--light-gray: rgb(219, 219, 219);
--gray: rgb(66, 66, 66);
--black: rgb(20, 20, 20);
--dark-background: rgb(50, 50, 50);
--border-radius: 5px;
}
html {
padding: 0;
font-size: 16px;
background: var(--white);
color: var(--black);
font-family: 'Open Sans', Arial, sans-serif;
max-width: 1200px;
margin: 0 auto;
}
.dark-mode nav {
border-color: var(--white);
}
nav {
margin-top: 50px;
min-width: 30%;
border-radius: var(--border-radius);
display: inline-block;
padding: 20px 30px;
/* background-color: var(--light-gray); */
border: 1px solid var(--black);
}
nav > h3 {
margin: 0;
}
nav > ol a {
font-weight: bold;
}
html.dark-mode {
background: var(--dark-background);
color: #ccc;
}
.dark-mode h1,
.dark-mode h2,
.dark-mode h3,
.dark-mode h4,
.dark-mode h5,
.dark-mode h6 {
color: white;
}
a {
color: #569cd6;
font-weight: bold;
}
.dark-mode a:hover {
color: white;
}
.dark-mode button {
border: 1px solid rgb(211, 211, 211);
color: rgb(211, 211, 211);
background: linear-gradient(to top, rgb(53, 53, 53), rgb(73, 73, 73));
}
button {
background-color: var(--white);
border: 1px solid var(--gray);
color: var(--gray);
padding: 10px 20px;
border-radius: 5px;
transition: transform 0.2s;
}
label {
display: flex;
align-items: center;
user-select: none;
cursor: pointer;
}
input[type='checkbox'] {
display: none;
}
input[type='checkbox'] + .checkbox {
position: relative;
margin-right: 10px;
width: 32px;
height: 32px;
}
.controls {
display: flex;
}
.controls > * {
margin-right: 1em;
}
.dark-mode .checkbox {
background-color: var(--gray);
border: 1px solid var(--white);
}
.checkbox {
display: inline-block;
border-radius: 3px;
background-color: var(--white);
border: 1px solid var(--black);
}
.checkbox:after {
content: '';
position: absolute;
}
input[type='checkbox']:checked + .checkbox {
background-color: rgb(174, 238, 78);
}
input[type='checkbox']:checked + .checkbox:after {
left: 11px;
top: 6px;
width: 5px;
height: 12px;
border: solid var(--white);
border-width: 0 4px 4px 0;
-webkit-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg);
}
button:active {
transform: scale(0.98);
}
button:hover {
filter: brightness(0.95);
}
button:focus {
box-shadow: 0 0 3px 1px #569cd6;
outline: none;
}
a {
text-decoration: none;
}
.title {
position: relative;
font-size: 2.5rem;
}
.description {
font-style: italic;
margin-bottom: 3rem;
}
.center {
display: block;
margin-left: auto;
margin-right: auto;
}
.doctest {
margin: 0;
padding-top: 20px;
padding-bottom: 20px;
box-shadow: inset 1px 1px 3px rgba(0, 0, 0, 0.5);
}
.collapsed .doctest {
height: 0;
margin: 0;
padding: 0;
}
.doctest-wrapper {
overflow: hidden;
border-radius: 5px;
margin-top: 1em;
margin-bottom: 1em;
}
.doctest-titlebar {
display: flex;
align-items: center;
color: whitesmoke;
background-color: #111;
padding: 10px;
}
.doctest-section-title {
margin: 0;
margin-left: 40px;
padding: 0;
font-size: 1.3em;
}
.grayBorder {
@ -24,10 +220,10 @@ html
}
.unselectable {
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
}
body {
@ -35,8 +231,8 @@ body {
}
canvas {
-ms-content-zooming: none; /** Crucial for MS Edge pointer events **/
touch-action: none; /** Crucial for MS Edge? **/
-ms-content-zooming: none; /** Crucial for MS Edge pointer events **/
touch-action: none; /** Crucial for MS Edge? **/
}
#runtime-errors {
@ -44,28 +240,47 @@ canvas {
margin-left: 8px;
}
.intrinsic-container {
position: relative;
height: 0;
overflow: hidden;
position: relative;
height: 0;
overflow: hidden;
}
/* 16x9 Aspect Ratio */
.intrinsic-container-16x9 {
padding-bottom: 56.25%;
padding-bottom: 56.25%;
}
/* 4x3 Aspect Ratio */
.intrinsic-container-4x3 {
padding-bottom: 75%;
padding-bottom: 75%;
}
.intrinsic-container iframe {
position: absolute;
border: 0;
top:0;
left: 0;
width: 100%;
height: 100%;
position: absolute;
border: 0;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
#ctxmenu {
position: fixed;
background: white;
color: black;
cursor: pointer;
border: 1px lightgray solid;
}
#ctxmenu > a {
display: block;
padding: 0.25rem 1rem;
font-size: 18px;
margin: 0.125rem;
}
#ctxmenu > a:hover {
background: black;
color: white;
}

View File

@ -1,6 +1,4 @@
.flipWrapper
{
.flipWrapper {
position: absolute;
top: 0;
left: 0;
@ -16,7 +14,8 @@
width: 100%;
height: 100%;
/*** See: https://stackoverflow.com/questions/7439042/css-js-to-prevent-dragging-of-ghost-image ***/
/*** See: https://stackoverflow.com/questions/7439042/css-js-to-prevent-dragging-of-ghost-image ***/
/* -webkit-user-drag: none;
-khtml-user-drag: none;
-moz-user-drag: none;
@ -24,21 +23,21 @@
user-drag: none; */
}
.flipFace{
.flipFace {
box-shadow: 2px 2px 10px #000;
visibility: hidden;
}
.front{
.front {
width: 100%;
height: 100%;
position:absolute;
background-color:#333;
position: absolute;
background-color: #333;
}
.back{
background-color:#333;
position:absolute;
.back {
background-color: #333;
position: absolute;
border: 8px solid white;
}
@ -48,8 +47,8 @@
width: 44px;
height: 44px;
padding: 4px;
right: 0px;
top: 0px;
right: 0;
top: 0;
}
.infoBtn {
@ -58,8 +57,8 @@
width: 44px;
height: 44px;
padding: 4px;
right: 0px;
bottom: 0px;
right: 0;
bottom: 0;
}
.backBtn {
@ -68,6 +67,6 @@
width: 44px;
height: 44px;
padding: 4px;
right: 0px;
bottom: 0px;
right: 0;
bottom: 0;
}

20
css/highlight.css Normal file
View File

@ -0,0 +1,20 @@
circle {
stroke: white;
fill: transparent;
stroke-width: 8px;
}
mask circle {
stroke-width: 0;
fill: white;
}
.addedImage {
filter: invert(1);
}
.debugRect {
stroke: red;
fill: transparent;
stroke-width: 8px;
}

View File

@ -1,19 +1,18 @@
html {
height: 100%;
width: 100%;
margin: 0px;
margin: 0;
}
body
{
margin: 0px;
padding: 0px;
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
font-family: sans-serif;
font-size: 22pt;
-webkit-tap-highlight-color: #ccc;
background-color: #DDD;
background-color: #ddd;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
@ -22,24 +21,28 @@ body
user-select: none;
-webkit-hyphens: auto;
hyphens: auto;
/* https://davidwalsh.name/font-smoothing */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
h3
{
h2 {
padding-left: 20px;
}
h3 {
color: white;
padding: 4px;
margin: 2px;
background-color: rgba(0, 0, 15, .5);
background-color: rgba(0, 0, 15, 0.5);
}
a { text-decoration: none; }
a {
text-decoration: none;
}
div.wrapper
{
div.wrapper {
overflow: hidden;
width: 100%;
height: 100%;
@ -49,29 +52,52 @@ div.wrapper
/* Color animation from https://www.tjvantoll.com/2012/02/20/css3-color-animations/ */
@-webkit-keyframes color_change {
from { background-color: rgba(0, 0, 0, 0); }
to { background-color: red; }
from {
background-color: rgba(0, 0, 0, 0);
}
to {
background-color: red;
}
}
@-moz-keyframes color_change {
from { background-color: rgba(0, 0, 0, 0); }
to { background-color: red; }
from {
background-color: rgba(0, 0, 0, 0);
}
to {
background-color: red;
}
}
@-ms-keyframes color_change {
from { background-color: rgba(0, 0, 0, 0); }
to { background-color: red; }
from {
background-color: rgba(0, 0, 0, 0);
}
to {
background-color: red;
}
}
@-o-keyframes color_change {
from { background-color: rgba(0, 0, 0, 0); }
to { background-color: red; }
from {
background-color: rgba(0, 0, 0, 0);
}
to {
background-color: red;
}
}
@keyframes color_change {
from { background-color:rgba(0, 0, 0, 0); }
to { background-color: red; }
from {
background-color: rgba(0, 0, 0, 0);
}
to {
background-color: red;
}
}
/*** CSS taken from https://medium.com/@jamesfuthey/simulating-the-creation-of-website-thumbnail-screenshots-using-iframes-7145269891db#.7v7fshos5 ***/
.thumbnail
{
.thumbnail {
position: relative;
-ms-zoom: 0.25;
-moz-transform: scale(0.25);
@ -82,10 +108,8 @@ div.wrapper
-webkit-transform-origin: 0 0;
}
.thumbnail:after
{
content: "";
.thumbnail::after {
content: '';
display: block;
position: absolute;
top: 0;
@ -95,11 +119,14 @@ div.wrapper
jamesfuthey blog. Otherwise touches would go through on iPad. ***/
}
.thumbnail iframe
{
iframe {
pointer-events: none;
}
.thumbnail iframe {
width: 1024px;
height: 624px;
-webkit-animation-delay: 3s; /* Safari 4.0 - 8.0 */
-webkit-animation-delay: 3s; /* Safari 4.0 - 8.0 */
animation-delay: 3s;
-webkit-animation: color_change 1s infinite alternate;
-moz-animation: color_change 1s infinite alternate;
@ -108,22 +135,20 @@ div.wrapper
animation: color_change 1s infinite alternate;
}
.thumbnail-container
{
.thumbnail-container {
width: calc(1024px * 0.25);
height: calc(624px * 0.25);
display: inline-block;
overflow: hidden;
position: relative;
box-shadow: 2px 2px 10px #000;
color: #DDD;
color: #ddd;
}
div.preview
{
div.preview {
display: inline-block;
margin: 22px;
padding: 0px;
padding: 0;
color: #333;
font-size: 12pt;
text-align: center;
@ -131,8 +156,7 @@ div.preview
height: 196px;
}
div.title
{
div.title {
padding-top: 8px;
width: 256px;
height: 20px;
@ -140,28 +164,22 @@ div.title
overflow: hidden;
}
.container
{
margin: 0px;
padding: 0px;
.container {
margin: 0;
padding: 0;
border: 2pt #000;
min-height: 100%;
min-width: 100%;
display: -webkit-flex;
-webkit-align-items: flex-end;
align-items: flex-end;
-webkit-align-items: flex-start;
align-items: flex-start;
-webkit-flex-wrap: wrap;
flex-wrap: wrap;
-webkit-align-content: flex-end;
align-content: flex-end;
}
iframe {
pointer-events: none;
-webkit-align-content: flex-start;
align-content: flex-start;
}
/** See https://github.com/electron/electron/issues/4420 */
::selection {
background: transparent;
}

35
css/popup.css Normal file
View File

@ -0,0 +1,35 @@
.popup {
width: 800px;
width: -webkit-fit-content;
width: -moz-fit-content;
width: fit-content;
min-width: 400px;
color: #191919;
background-color: #f2f2f2;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
padding: 25.64px 40px;
}
.popup img {
display: block;
margin: auto;
}
.popup img:not(:first-child) {
margin-top: 20px;
}
.popup img:not(:last-child) {
margin-bottom: 20px;
}
.popup .notch {
width: 20px;
height: 20px;
border-color: #f2f2f2;
}
.PopupContent p:not(:last-child) {
margin-bottom: 30px;
}

22
css/subcard.css Normal file
View File

@ -0,0 +1,22 @@
.info-card .subcard {
color: black;
}
.info-card .subcard p {
text-align: justify;
}
.info-card .content h1 {
color: black;
}
.info-card .subcard .preview p {
text-align: center;
}
.info-card>.zoomable-wrapper figcaption, .info-card .mainview>.subcard figcaption {
width: 100%;
position: absolute;
text-align: center;
}

147777
dist/iwmlib.3rdparty.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -8119,10 +8119,10 @@ if (_gsScope._gsDefine) { _gsScope._gsQueue.pop()(); } //necessary in case Tween
css transforms without perspective projection)
*/
(function () {
;(function () {
'use strict'
var I = (typeof(WebKitCSSMatrix) == 'undefined') ? new DOMMatrix() : new WebKitCSSMatrix()
var I = typeof WebKitCSSMatrix == 'undefined' ? new DOMMatrix() : new WebKitCSSMatrix()
function Point(x, y, z) {
this.x = x
@ -8137,8 +8137,8 @@ if (_gsScope._gsDefine) { _gsScope._gsQueue.pop()(); } //necessary in case Tween
function createMatrix(transform) {
try {
return (typeof(WebKitCSSMatrix) == 'undefined') ? new DOMMatrix(transform) : new WebKitCSSMatrix(transform)
} catch(e) {
return typeof WebKitCSSMatrix == 'undefined' ? new DOMMatrix(transform) : new WebKitCSSMatrix(transform)
} catch (e) {
console.warn(transform)
console.warn(e.toString())
return I
@ -8163,8 +8163,9 @@ if (_gsScope._gsDefine) { _gsScope._gsQueue.pop()(); } //necessary in case Tween
var left = +Infinity
var top = +Infinity
while (--i >= 0) {
var p = new Point(i === 0 || i === 1 ? 0 : w, i === 0 || i === 3 ? 0 : h,
0).transformBy(transformationMatrix)
var p = new Point(i === 0 || i === 1 ? 0 : w, i === 0 || i === 3 ? 0 : h, 0).transformBy(
transformationMatrix
)
if (p.x < left) {
left = p.x
}
@ -8173,20 +8174,19 @@ if (_gsScope._gsDefine) { _gsScope._gsQueue.pop()(); } //necessary in case Tween
}
}
var rect = element.getBoundingClientRect()
transformationMatrix = I.translate(window.pageXOffset + rect.left - left,
window.pageYOffset + rect.top - top, 0)
.multiply(transformationMatrix)
transformationMatrix = I.translate(
window.pageXOffset + rect.left - left,
window.pageYOffset + rect.top - top,
0
).multiply(transformationMatrix)
return transformationMatrix
}
window.convertPointFromPageToNode = function (element, pageX, pageY) {
return new Point(pageX, pageY, 0).transformBy(
getTransformationMatrix(element).inverse())
return new Point(pageX, pageY, 0).transformBy(getTransformationMatrix(element).inverse())
}
window.convertPointFromNodeToPage = function (element, offsetX, offsetY) {
return new Point(offsetX, offsetY, 0).transformBy(
getTransformationMatrix(element))
return new Point(offsetX, offsetY, 0).transformBy(getTransformationMatrix(element))
}
}())
})();

File diff suppressed because one or more lines are too long

6605
dist/iwmlib.js vendored

File diff suppressed because it is too large Load Diff

14615
dist/iwmlib.pixi.js vendored

File diff suppressed because it is too large Load Diff

View File

@ -20,4 +20,3 @@ This is the JavaScript API documentation of the IWM Browser JavaScript classes.
- [PixiJS](http://www.pixijs.com)
- [Greensock](https://greensock.com) with all Plugins
- [D3](https://d3js.org)

View File

@ -1,30 +1,28 @@
<!DOCTYPE html>
<meta charset="utf-8">
<meta charset="utf-8" />
<style>
.node circle {
fill: #999;
}
.node circle {
fill: #999;
}
.node text {
font: 10px sans-serif;
}
.node text {
font: 10px sans-serif;
}
.node--internal circle {
fill: #555;
}
.node--internal circle {
fill: #555;
}
.node--internal text {
text-shadow: 0 1px 0 #fff, 0 -1px 0 #fff, 1px 0 0 #fff, -1px 0 0 #fff;
}
.link {
fill: none;
stroke: #555;
stroke-opacity: 0.4;
stroke-width: 1.5px;
}
.node--internal text {
text-shadow: 0 1px 0 #fff, 0 -1px 0 #fff, 1px 0 0 #fff, -1px 0 0 #fff;
}
.link {
fill: none;
stroke: #555;
stroke-opacity: 0.4;
stroke-width: 1.5px;
}
</style>
<svg width="960" height="512"></svg>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
@ -32,104 +30,106 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.7.1/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/acorn/4.0.11/acorn.min.js"></script>
<script>
fetch('../apps/loader/js/main.js')
.then((response) => response.text())
.then((text) => {
const ast = acorn.parse(text, {
sourceType: 'module',
// collect ranges for each node
ranges: true,
// collect comments in Esprima's format
onComment: null,
// collect token ranges
onToken: null
})
fetch("../apps/loader/js/main.js")
.then(response => response.text())
.then(text => {
const ast = acorn.parse(text, {
sourceType: "module",
// collect ranges for each node
ranges: true,
// collect comments in Esprima's format
onComment: null,
// collect token ranges
onToken: null
})
console.info(ast)
console.info(ast)
drawAst(ast)
})
drawAst(ast)
})
/*
*
*/
function drawAst(ast) {
// Create SVG element
//---------------------------
let svg = d3.select("svg")
const width = svg.attr("width")
const height = svg.attr("height")
let g = svg.append("g").attr("transform", "translate(40,0)")
// Convert data
//---------------------------
const data = acornToHierarchy(ast)
// Create D3 Hierarchy
//---------------------------
let root = d3.hierarchy(data).sort((a, b) => {
return (a.height - b.height) || a.data.name.localeCompare(b.data.name);
})
/*
*
*/
function drawAst(ast) {
// Create SVG element
//---------------------------
let svg = d3.select('svg')
const width = svg.attr('width')
const height = svg.attr('height')
let g = svg.append('g').attr('transform', 'translate(40,0)')
// Create D3 Cluster
//---------------------------
let tree = d3.cluster().size([height, width - 200])
tree(root)
// Create SVG elements
//---------------------------
let link = g.selectAll(".link")
.data(root.descendants().slice(1))
.enter().append("path")
.attr("class", "link")
.attr("d", d => {
return `M${d.y},${d.x}C${d.parent.y + 100},${d.x} ${d.parent.y + 100},${d.parent.x} ${d.parent.y},${d.parent.x}`
})
let node = g.selectAll(".node")
.data(root.descendants())
.enter().append("g")
.attr("class", d => "node" + (d.children ? " node--internal" : " node--leaf"))
.attr("transform", d => `translate(${d.y},${d.x})`)
node.append("circle")
.attr("r", 5)
node.append("text")
.attr("dy", 3)
.attr("x", d => d.children ? -8 : 8)
.style("text-anchor", d => d.children ? "end" : "start")
.text(d => d.data.name)
}
// Convert data
//---------------------------
const data = acornToHierarchy(ast)
/*
*
*/
function acornToHierarchy(ast) {
console.info(JSON.stringify(ast))
let data = {}
for (const clazz of ast.body) {
if (clazz.type === "ClassDeclaration") {
data.name = clazz.id.name
data.children = []
for (const method of clazz.body.body) {
if (method.type === "MethodDefinition") {
data.children.push({
name: method.key.name,
children: []
})
}
}
}
}
/*
// Create D3 Hierarchy
//---------------------------
let root = d3.hierarchy(data).sort((a, b) => {
return a.height - b.height || a.data.name.localeCompare(b.data.name)
})
// Create D3 Cluster
//---------------------------
let tree = d3.cluster().size([height, width - 200])
tree(root)
// Create SVG elements
//---------------------------
let link = g
.selectAll('.link')
.data(root.descendants().slice(1))
.enter()
.append('path')
.attr('class', 'link')
.attr('d', (d) => {
return `M${d.y},${d.x}C${d.parent.y + 100},${d.x} ${d.parent.y + 100},${d.parent.x} ${d.parent.y},${
d.parent.x
}`
})
let node = g
.selectAll('.node')
.data(root.descendants())
.enter()
.append('g')
.attr('class', (d) => 'node' + (d.children ? ' node--internal' : ' node--leaf'))
.attr('transform', (d) => `translate(${d.y},${d.x})`)
node.append('circle').attr('r', 5)
node.append('text')
.attr('dy', 3)
.attr('x', (d) => (d.children ? -8 : 8))
.style('text-anchor', (d) => (d.children ? 'end' : 'start'))
.text((d) => d.data.name)
}
/*
*
*/
function acornToHierarchy(ast) {
console.info(JSON.stringify(ast))
let data = {}
for (const clazz of ast.body) {
if (clazz.type === 'ClassDeclaration') {
data.name = clazz.id.name
data.children = []
for (const method of clazz.body.body) {
if (method.type === 'MethodDefinition') {
data.children.push({
name: method.key.name,
children: []
})
}
}
}
}
/*
const data = {
"name": "Eve",
"children": [{
@ -153,22 +153,7 @@ function acornToHierarchy(ast) {
}]
}
*/
return data
}
</script>
return data
}
</script>

View File

@ -36,7 +36,21 @@
"./lib/pixi/switch.js",
"./lib/pixi/theme.js",
"./lib/pixi/tooltip.js",
"./lib/pixi/volatile.js"
"./lib/pixi/volatile.js",
"./lib/pixi/maps/mapapp.js",
"./lib/pixi/maps/mapviewport.js",
"./lib/pixi/maps/geographics.js",
"./lib/pixi/maps/geojson.js",
"./lib/pixi/maps/geolayer.js",
"./lib/pixi/maps/mapprojection.js",
"./lib/pixi/maps/maplist.js",
"./lib/pixi/maps/overlay.js",
"./lib/pixi/maps/scatter.js",
"./lib/pixi/maps/utils.js",
"./lib/pixi/maps/map.js",
"./lib/pixi/maps/projections/projection.js",
"./lib/pixi/maps/projections/mercator.js",
"./lib/pixi/maps/projections/robinson.js"
],
"exclude": [],
"includePattern": ".+\\.js(doc|x)?$",
@ -45,7 +59,10 @@
"sourceType": "module",
"tags": {
"allowUnknownTags": true,
"dictionaries": ["jsdoc", "closure"]
"dictionaries": [
"jsdoc",
"closure"
]
},
"templates": {
"applicationName": "iwmlib",
@ -70,4 +87,4 @@
"useLongnameInNav": false
}
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1 +1 @@
(function(){var e=0;var a;var t=document.getElementById("source-code");if(t){var n=config.linenums;if(n){t=t.getElementsByTagName("ol")[0];a=Array.prototype.slice.apply(t.children);a=a.map(function(a){e++;a.id="line"+e})}else{t=t.getElementsByTagName("code")[0];a=t.innerHTML.split("\n");a=a.map(function(a){e++;return'<span id="line'+e+'"></span>'+a});t.innerHTML=a.join("\n")}}})();$(function(){var e=$(".navigation");var a=e.find(".list");var t=$(".search");$("#search").on("keyup",function(t){var n=this.value.trim();if(n){var s=new RegExp(n,"i");e.addClass("searching").removeClass("not-searching").find("li, .itemMembers").removeClass("match");e.find("li").each(function(e,a){var t=$(a);if(t.data("name")&&s.test(t.data("name"))){t.addClass("match");t.closest(".itemMembers").addClass("match");t.closest(".item").addClass("match")}})}else{e.removeClass("searching").addClass("not-searching").find(".item, .itemMembers").removeClass("match")}a.scrollTop(0)});$("#menuToggle").click(function(){a.toggleClass("show");t.toggleClass("show")});e.addClass("not-searching");var n=$(".page-title").data("filename").replace(/\.[a-z]+$/,"");var s=e.find('.item[data-name*="'+n+'"]:eq(0)');if(s.length){s.remove().prependTo(a).addClass("current")}if(config.disqus){$(window).on("load",function(){var e=config.disqus;var a=document.createElement("script");a.type="text/javascript";a.async=true;a.src="http://"+e+".disqus.com/embed.js";(document.getElementsByTagName("head")[0]||document.getElementsByTagName("body")[0]).appendChild(a);var t=document.createElement("script");t.async=true;t.type="text/javascript";t.src="http://"+e+".disqus.com/count.js";document.getElementsByTagName("BODY")[0].appendChild(t)})}});
(function(){var e=0;var a;var t=document.getElementById("source-code");if(t){var n=config.linenums;if(n){t=t.getElementsByTagName("ol")[0];a=Array.prototype.slice.apply(t.children);a=a.map(function(a){e++;a.id="line"+e})}else{t=t.getElementsByTagName("code")[0];a=t.innerHTML.split("\n");a=a.map(function(a){e++;return'<span id="line'+e+'"></span>'+a});t.innerHTML=a.join("\n")}}})();$(function(){var e=$(".navigation");var a=e.find(".list");var t=$(".search");$("#search").on("keyup",function(t){var n=this.value.trim();if(n){var s=new RegExp(n,"i");e.addClass("searching").removeClass("not-searching").find("li, .itemMembers").removeClass("match");e.find("li").each(function(e,a){var t=$(a);if(t.data("name")&&s.test(t.data("name"))){t.addClass("match");t.closest(".itemMembers").addClass("match");t.closest(".item").addClass("match")}})}else{e.removeClass("searching").addClass("not-searching").find(".item, .itemMembers").removeClass("match")}a.scrollTop(0)});$("#menuToggle").click(function(){a.toggleClass("show");t.toggleClass("show")});e.addClass("not-searching");var n=$(".page-title").data("filename").replace(/\.[a-z]+$/,"");var s=e.find('a[href*="'+n+'"]:eq(0)').closest(".item");if(s.length){if(s.parents(".children").length){s.addClass("current");s.find("li.item").addClass("notCurrent");s=s.parents("ul.list>li.item")}s.remove().prependTo(a).addClass("current")}if(config.disqus){$(window).on("load",function(){var e=config.disqus;var a=document.createElement("script");a.type="text/javascript";a.async=true;a.src="http://"+e+".disqus.com/embed.js";(document.getElementsByTagName("head")[0]||document.getElementsByTagName("body")[0]).appendChild(a);var t=document.createElement("script");t.async=true;t.type="text/javascript";t.src="http://"+e+".disqus.com/count.js";document.getElementsByTagName("BODY")[0].appendChild(t)})}});

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 275 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,9 @@
The recommended way to use the Material Icons font is by linking to the web font hosted on Google Fonts:
```html
<link href="https://fonts.googleapis.com/icon?family=Material+Icons"
rel="stylesheet">
```
Read more in our full usage guide:
http://google.github.io/material-design-icons/#icon-font-for-the-web

View File

@ -0,0 +1,932 @@
3d_rotation e84d
ac_unit eb3b
access_alarm e190
access_alarms e191
access_time e192
accessibility e84e
accessible e914
account_balance e84f
account_balance_wallet e850
account_box e851
account_circle e853
adb e60e
add e145
add_a_photo e439
add_alarm e193
add_alert e003
add_box e146
add_circle e147
add_circle_outline e148
add_location e567
add_shopping_cart e854
add_to_photos e39d
add_to_queue e05c
adjust e39e
airline_seat_flat e630
airline_seat_flat_angled e631
airline_seat_individual_suite e632
airline_seat_legroom_extra e633
airline_seat_legroom_normal e634
airline_seat_legroom_reduced e635
airline_seat_recline_extra e636
airline_seat_recline_normal e637
airplanemode_active e195
airplanemode_inactive e194
airplay e055
airport_shuttle eb3c
alarm e855
alarm_add e856
alarm_off e857
alarm_on e858
album e019
all_inclusive eb3d
all_out e90b
android e859
announcement e85a
apps e5c3
archive e149
arrow_back e5c4
arrow_downward e5db
arrow_drop_down e5c5
arrow_drop_down_circle e5c6
arrow_drop_up e5c7
arrow_forward e5c8
arrow_upward e5d8
art_track e060
aspect_ratio e85b
assessment e85c
assignment e85d
assignment_ind e85e
assignment_late e85f
assignment_return e860
assignment_returned e861
assignment_turned_in e862
assistant e39f
assistant_photo e3a0
attach_file e226
attach_money e227
attachment e2bc
audiotrack e3a1
autorenew e863
av_timer e01b
backspace e14a
backup e864
battery_alert e19c
battery_charging_full e1a3
battery_full e1a4
battery_std e1a5
battery_unknown e1a6
beach_access eb3e
beenhere e52d
block e14b
bluetooth e1a7
bluetooth_audio e60f
bluetooth_connected e1a8
bluetooth_disabled e1a9
bluetooth_searching e1aa
blur_circular e3a2
blur_linear e3a3
blur_off e3a4
blur_on e3a5
book e865
bookmark e866
bookmark_border e867
border_all e228
border_bottom e229
border_clear e22a
border_color e22b
border_horizontal e22c
border_inner e22d
border_left e22e
border_outer e22f
border_right e230
border_style e231
border_top e232
border_vertical e233
branding_watermark e06b
brightness_1 e3a6
brightness_2 e3a7
brightness_3 e3a8
brightness_4 e3a9
brightness_5 e3aa
brightness_6 e3ab
brightness_7 e3ac
brightness_auto e1ab
brightness_high e1ac
brightness_low e1ad
brightness_medium e1ae
broken_image e3ad
brush e3ae
bubble_chart e6dd
bug_report e868
build e869
burst_mode e43c
business e0af
business_center eb3f
cached e86a
cake e7e9
call e0b0
call_end e0b1
call_made e0b2
call_merge e0b3
call_missed e0b4
call_missed_outgoing e0e4
call_received e0b5
call_split e0b6
call_to_action e06c
camera e3af
camera_alt e3b0
camera_enhance e8fc
camera_front e3b1
camera_rear e3b2
camera_roll e3b3
cancel e5c9
card_giftcard e8f6
card_membership e8f7
card_travel e8f8
casino eb40
cast e307
cast_connected e308
center_focus_strong e3b4
center_focus_weak e3b5
change_history e86b
chat e0b7
chat_bubble e0ca
chat_bubble_outline e0cb
check e5ca
check_box e834
check_box_outline_blank e835
check_circle e86c
chevron_left e5cb
chevron_right e5cc
child_care eb41
child_friendly eb42
chrome_reader_mode e86d
class e86e
clear e14c
clear_all e0b8
close e5cd
closed_caption e01c
cloud e2bd
cloud_circle e2be
cloud_done e2bf
cloud_download e2c0
cloud_off e2c1
cloud_queue e2c2
cloud_upload e2c3
code e86f
collections e3b6
collections_bookmark e431
color_lens e3b7
colorize e3b8
comment e0b9
compare e3b9
compare_arrows e915
computer e30a
confirmation_number e638
contact_mail e0d0
contact_phone e0cf
contacts e0ba
content_copy e14d
content_cut e14e
content_paste e14f
control_point e3ba
control_point_duplicate e3bb
copyright e90c
create e150
create_new_folder e2cc
credit_card e870
crop e3be
crop_16_9 e3bc
crop_3_2 e3bd
crop_5_4 e3bf
crop_7_5 e3c0
crop_din e3c1
crop_free e3c2
crop_landscape e3c3
crop_original e3c4
crop_portrait e3c5
crop_rotate e437
crop_square e3c6
dashboard e871
data_usage e1af
date_range e916
dehaze e3c7
delete e872
delete_forever e92b
delete_sweep e16c
description e873
desktop_mac e30b
desktop_windows e30c
details e3c8
developer_board e30d
developer_mode e1b0
device_hub e335
devices e1b1
devices_other e337
dialer_sip e0bb
dialpad e0bc
directions e52e
directions_bike e52f
directions_boat e532
directions_bus e530
directions_car e531
directions_railway e534
directions_run e566
directions_subway e533
directions_transit e535
directions_walk e536
disc_full e610
dns e875
do_not_disturb e612
do_not_disturb_alt e611
do_not_disturb_off e643
do_not_disturb_on e644
dock e30e
domain e7ee
done e876
done_all e877
donut_large e917
donut_small e918
drafts e151
drag_handle e25d
drive_eta e613
dvr e1b2
edit e3c9
edit_location e568
eject e8fb
email e0be
enhanced_encryption e63f
equalizer e01d
error e000
error_outline e001
euro_symbol e926
ev_station e56d
event e878
event_available e614
event_busy e615
event_note e616
event_seat e903
exit_to_app e879
expand_less e5ce
expand_more e5cf
explicit e01e
explore e87a
exposure e3ca
exposure_neg_1 e3cb
exposure_neg_2 e3cc
exposure_plus_1 e3cd
exposure_plus_2 e3ce
exposure_zero e3cf
extension e87b
face e87c
fast_forward e01f
fast_rewind e020
favorite e87d
favorite_border e87e
featured_play_list e06d
featured_video e06e
feedback e87f
fiber_dvr e05d
fiber_manual_record e061
fiber_new e05e
fiber_pin e06a
fiber_smart_record e062
file_download e2c4
file_upload e2c6
filter e3d3
filter_1 e3d0
filter_2 e3d1
filter_3 e3d2
filter_4 e3d4
filter_5 e3d5
filter_6 e3d6
filter_7 e3d7
filter_8 e3d8
filter_9 e3d9
filter_9_plus e3da
filter_b_and_w e3db
filter_center_focus e3dc
filter_drama e3dd
filter_frames e3de
filter_hdr e3df
filter_list e152
filter_none e3e0
filter_tilt_shift e3e2
filter_vintage e3e3
find_in_page e880
find_replace e881
fingerprint e90d
first_page e5dc
fitness_center eb43
flag e153
flare e3e4
flash_auto e3e5
flash_off e3e6
flash_on e3e7
flight e539
flight_land e904
flight_takeoff e905
flip e3e8
flip_to_back e882
flip_to_front e883
folder e2c7
folder_open e2c8
folder_shared e2c9
folder_special e617
font_download e167
format_align_center e234
format_align_justify e235
format_align_left e236
format_align_right e237
format_bold e238
format_clear e239
format_color_fill e23a
format_color_reset e23b
format_color_text e23c
format_indent_decrease e23d
format_indent_increase e23e
format_italic e23f
format_line_spacing e240
format_list_bulleted e241
format_list_numbered e242
format_paint e243
format_quote e244
format_shapes e25e
format_size e245
format_strikethrough e246
format_textdirection_l_to_r e247
format_textdirection_r_to_l e248
format_underlined e249
forum e0bf
forward e154
forward_10 e056
forward_30 e057
forward_5 e058
free_breakfast eb44
fullscreen e5d0
fullscreen_exit e5d1
functions e24a
g_translate e927
gamepad e30f
games e021
gavel e90e
gesture e155
get_app e884
gif e908
golf_course eb45
gps_fixed e1b3
gps_not_fixed e1b4
gps_off e1b5
grade e885
gradient e3e9
grain e3ea
graphic_eq e1b8
grid_off e3eb
grid_on e3ec
group e7ef
group_add e7f0
group_work e886
hd e052
hdr_off e3ed
hdr_on e3ee
hdr_strong e3f1
hdr_weak e3f2
headset e310
headset_mic e311
healing e3f3
hearing e023
help e887
help_outline e8fd
high_quality e024
highlight e25f
highlight_off e888
history e889
home e88a
hot_tub eb46
hotel e53a
hourglass_empty e88b
hourglass_full e88c
http e902
https e88d
image e3f4
image_aspect_ratio e3f5
import_contacts e0e0
import_export e0c3
important_devices e912
inbox e156
indeterminate_check_box e909
info e88e
info_outline e88f
input e890
insert_chart e24b
insert_comment e24c
insert_drive_file e24d
insert_emoticon e24e
insert_invitation e24f
insert_link e250
insert_photo e251
invert_colors e891
invert_colors_off e0c4
iso e3f6
keyboard e312
keyboard_arrow_down e313
keyboard_arrow_left e314
keyboard_arrow_right e315
keyboard_arrow_up e316
keyboard_backspace e317
keyboard_capslock e318
keyboard_hide e31a
keyboard_return e31b
keyboard_tab e31c
keyboard_voice e31d
kitchen eb47
label e892
label_outline e893
landscape e3f7
language e894
laptop e31e
laptop_chromebook e31f
laptop_mac e320
laptop_windows e321
last_page e5dd
launch e895
layers e53b
layers_clear e53c
leak_add e3f8
leak_remove e3f9
lens e3fa
library_add e02e
library_books e02f
library_music e030
lightbulb_outline e90f
line_style e919
line_weight e91a
linear_scale e260
link e157
linked_camera e438
list e896
live_help e0c6
live_tv e639
local_activity e53f
local_airport e53d
local_atm e53e
local_bar e540
local_cafe e541
local_car_wash e542
local_convenience_store e543
local_dining e556
local_drink e544
local_florist e545
local_gas_station e546
local_grocery_store e547
local_hospital e548
local_hotel e549
local_laundry_service e54a
local_library e54b
local_mall e54c
local_movies e54d
local_offer e54e
local_parking e54f
local_pharmacy e550
local_phone e551
local_pizza e552
local_play e553
local_post_office e554
local_printshop e555
local_see e557
local_shipping e558
local_taxi e559
location_city e7f1
location_disabled e1b6
location_off e0c7
location_on e0c8
location_searching e1b7
lock e897
lock_open e898
lock_outline e899
looks e3fc
looks_3 e3fb
looks_4 e3fd
looks_5 e3fe
looks_6 e3ff
looks_one e400
looks_two e401
loop e028
loupe e402
low_priority e16d
loyalty e89a
mail e158
mail_outline e0e1
map e55b
markunread e159
markunread_mailbox e89b
memory e322
menu e5d2
merge_type e252
message e0c9
mic e029
mic_none e02a
mic_off e02b
mms e618
mode_comment e253
mode_edit e254
monetization_on e263
money_off e25c
monochrome_photos e403
mood e7f2
mood_bad e7f3
more e619
more_horiz e5d3
more_vert e5d4
motorcycle e91b
mouse e323
move_to_inbox e168
movie e02c
movie_creation e404
movie_filter e43a
multiline_chart e6df
music_note e405
music_video e063
my_location e55c
nature e406
nature_people e407
navigate_before e408
navigate_next e409
navigation e55d
near_me e569
network_cell e1b9
network_check e640
network_locked e61a
network_wifi e1ba
new_releases e031
next_week e16a
nfc e1bb
no_encryption e641
no_sim e0cc
not_interested e033
note e06f
note_add e89c
notifications e7f4
notifications_active e7f7
notifications_none e7f5
notifications_off e7f6
notifications_paused e7f8
offline_pin e90a
ondemand_video e63a
opacity e91c
open_in_browser e89d
open_in_new e89e
open_with e89f
pages e7f9
pageview e8a0
palette e40a
pan_tool e925
panorama e40b
panorama_fish_eye e40c
panorama_horizontal e40d
panorama_vertical e40e
panorama_wide_angle e40f
party_mode e7fa
pause e034
pause_circle_filled e035
pause_circle_outline e036
payment e8a1
people e7fb
people_outline e7fc
perm_camera_mic e8a2
perm_contact_calendar e8a3
perm_data_setting e8a4
perm_device_information e8a5
perm_identity e8a6
perm_media e8a7
perm_phone_msg e8a8
perm_scan_wifi e8a9
person e7fd
person_add e7fe
person_outline e7ff
person_pin e55a
person_pin_circle e56a
personal_video e63b
pets e91d
phone e0cd
phone_android e324
phone_bluetooth_speaker e61b
phone_forwarded e61c
phone_in_talk e61d
phone_iphone e325
phone_locked e61e
phone_missed e61f
phone_paused e620
phonelink e326
phonelink_erase e0db
phonelink_lock e0dc
phonelink_off e327
phonelink_ring e0dd
phonelink_setup e0de
photo e410
photo_album e411
photo_camera e412
photo_filter e43b
photo_library e413
photo_size_select_actual e432
photo_size_select_large e433
photo_size_select_small e434
picture_as_pdf e415
picture_in_picture e8aa
picture_in_picture_alt e911
pie_chart e6c4
pie_chart_outlined e6c5
pin_drop e55e
place e55f
play_arrow e037
play_circle_filled e038
play_circle_outline e039
play_for_work e906
playlist_add e03b
playlist_add_check e065
playlist_play e05f
plus_one e800
poll e801
polymer e8ab
pool eb48
portable_wifi_off e0ce
portrait e416
power e63c
power_input e336
power_settings_new e8ac
pregnant_woman e91e
present_to_all e0df
print e8ad
priority_high e645
public e80b
publish e255
query_builder e8ae
question_answer e8af
queue e03c
queue_music e03d
queue_play_next e066
radio e03e
radio_button_checked e837
radio_button_unchecked e836
rate_review e560
receipt e8b0
recent_actors e03f
record_voice_over e91f
redeem e8b1
redo e15a
refresh e5d5
remove e15b
remove_circle e15c
remove_circle_outline e15d
remove_from_queue e067
remove_red_eye e417
remove_shopping_cart e928
reorder e8fe
repeat e040
repeat_one e041
replay e042
replay_10 e059
replay_30 e05a
replay_5 e05b
reply e15e
reply_all e15f
report e160
report_problem e8b2
restaurant e56c
restaurant_menu e561
restore e8b3
restore_page e929
ring_volume e0d1
room e8b4
room_service eb49
rotate_90_degrees_ccw e418
rotate_left e419
rotate_right e41a
rounded_corner e920
router e328
rowing e921
rss_feed e0e5
rv_hookup e642
satellite e562
save e161
scanner e329
schedule e8b5
school e80c
screen_lock_landscape e1be
screen_lock_portrait e1bf
screen_lock_rotation e1c0
screen_rotation e1c1
screen_share e0e2
sd_card e623
sd_storage e1c2
search e8b6
security e32a
select_all e162
send e163
sentiment_dissatisfied e811
sentiment_neutral e812
sentiment_satisfied e813
sentiment_very_dissatisfied e814
sentiment_very_satisfied e815
settings e8b8
settings_applications e8b9
settings_backup_restore e8ba
settings_bluetooth e8bb
settings_brightness e8bd
settings_cell e8bc
settings_ethernet e8be
settings_input_antenna e8bf
settings_input_component e8c0
settings_input_composite e8c1
settings_input_hdmi e8c2
settings_input_svideo e8c3
settings_overscan e8c4
settings_phone e8c5
settings_power e8c6
settings_remote e8c7
settings_system_daydream e1c3
settings_voice e8c8
share e80d
shop e8c9
shop_two e8ca
shopping_basket e8cb
shopping_cart e8cc
short_text e261
show_chart e6e1
shuffle e043
signal_cellular_4_bar e1c8
signal_cellular_connected_no_internet_4_bar e1cd
signal_cellular_no_sim e1ce
signal_cellular_null e1cf
signal_cellular_off e1d0
signal_wifi_4_bar e1d8
signal_wifi_4_bar_lock e1d9
signal_wifi_off e1da
sim_card e32b
sim_card_alert e624
skip_next e044
skip_previous e045
slideshow e41b
slow_motion_video e068
smartphone e32c
smoke_free eb4a
smoking_rooms eb4b
sms e625
sms_failed e626
snooze e046
sort e164
sort_by_alpha e053
spa eb4c
space_bar e256
speaker e32d
speaker_group e32e
speaker_notes e8cd
speaker_notes_off e92a
speaker_phone e0d2
spellcheck e8ce
star e838
star_border e83a
star_half e839
stars e8d0
stay_current_landscape e0d3
stay_current_portrait e0d4
stay_primary_landscape e0d5
stay_primary_portrait e0d6
stop e047
stop_screen_share e0e3
storage e1db
store e8d1
store_mall_directory e563
straighten e41c
streetview e56e
strikethrough_s e257
style e41d
subdirectory_arrow_left e5d9
subdirectory_arrow_right e5da
subject e8d2
subscriptions e064
subtitles e048
subway e56f
supervisor_account e8d3
surround_sound e049
swap_calls e0d7
swap_horiz e8d4
swap_vert e8d5
swap_vertical_circle e8d6
switch_camera e41e
switch_video e41f
sync e627
sync_disabled e628
sync_problem e629
system_update e62a
system_update_alt e8d7
tab e8d8
tab_unselected e8d9
tablet e32f
tablet_android e330
tablet_mac e331
tag_faces e420
tap_and_play e62b
terrain e564
text_fields e262
text_format e165
textsms e0d8
texture e421
theaters e8da
thumb_down e8db
thumb_up e8dc
thumbs_up_down e8dd
time_to_leave e62c
timelapse e422
timeline e922
timer e425
timer_10 e423
timer_3 e424
timer_off e426
title e264
toc e8de
today e8df
toll e8e0
tonality e427
touch_app e913
toys e332
track_changes e8e1
traffic e565
train e570
tram e571
transfer_within_a_station e572
transform e428
translate e8e2
trending_down e8e3
trending_flat e8e4
trending_up e8e5
tune e429
turned_in e8e6
turned_in_not e8e7
tv e333
unarchive e169
undo e166
unfold_less e5d6
unfold_more e5d7
update e923
usb e1e0
verified_user e8e8
vertical_align_bottom e258
vertical_align_center e259
vertical_align_top e25a
vibration e62d
video_call e070
video_label e071
video_library e04a
videocam e04b
videocam_off e04c
videogame_asset e338
view_agenda e8e9
view_array e8ea
view_carousel e8eb
view_column e8ec
view_comfy e42a
view_compact e42b
view_day e8ed
view_headline e8ee
view_list e8ef
view_module e8f0
view_quilt e8f1
view_stream e8f2
view_week e8f3
vignette e435
visibility e8f4
visibility_off e8f5
voice_chat e62e
voicemail e0d9
volume_down e04d
volume_mute e04e
volume_off e04f
volume_up e050
vpn_key e0da
vpn_lock e62f
wallpaper e1bc
warning e002
watch e334
watch_later e924
wb_auto e42c
wb_cloudy e42d
wb_incandescent e42e
wb_iridescent e436
wb_sunny e430
wc e63d
web e051
web_asset e069
weekend e16b
whatshot e80e
widgets e1bd
wifi e63e
wifi_lock e1e1
wifi_tethering e1e2
work e8f9
wrap_text e25b
youtube_searched_for e8fa
zoom_in e8ff
zoom_out e900
zoom_out_map e56b

View File

@ -0,0 +1,36 @@
@font-face {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: url(MaterialIcons-Regular.eot); /* For IE6-8 */
src: local('Material Icons'),
local('MaterialIcons-Regular'),
url(MaterialIcons-Regular.woff2) format('woff2'),
url(MaterialIcons-Regular.woff) format('woff'),
url(MaterialIcons-Regular.ttf) format('truetype');
}
.material-icons {
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
font-size: 24px; /* Preferred icon size */
display: inline-block;
line-height: 1;
text-transform: none;
letter-spacing: normal;
word-wrap: normal;
white-space: nowrap;
direction: ltr;
/* Support for all WebKit browsers. */
-webkit-font-smoothing: antialiased;
/* Support for Safari and Chrome. */
text-rendering: optimizeLegibility;
/* Support for Firefox. */
-moz-osx-font-smoothing: grayscale;
/* Support for IE. */
font-feature-settings: 'liga';
}

View File

@ -1,45 +1,72 @@
const {src, dest, parallel} = require('gulp');
const uglify = require('gulp-uglify');
const rename = require('gulp-rename');
const concat = require('gulp-concat');
const replace = require('gulp-replace');
const { src, dest, parallel } = require('gulp')
const uglify = require('gulp-uglify')
const rename = require('gulp-rename')
const concat = require('gulp-concat')
const replace = require('gulp-replace')
const prettier = require('gulp-prettier')
function vendors() {
return src([
'./node_modules/optimal-select/dist/optimal-select.js',
'./node_modules/hammerjs/hammer.js',
'./node_modules/propagating-hammerjs/propagating.js',
'./node_modules/pixi.js/dist/pixi.js',
'./node_modules/pixi-compressed-textures/lib/crn_decomp.js',
'./node_modules/pixi-compressed-textures/bin/pixi-compressed-textures.js',
'./node_modules/pixi-filters/dist/pixi-filters.js',
'./node_modules/pixi-particles/dist/pixi-particles.js',
'./node_modules/pixi-projection/dist/pixi-projection.js',
'./node_modules/gsap/src/uncompressed/TweenMax.js',
'./node_modules/gsap/src/uncompressed/TimelineMax.js',
'./lib/3rdparty/pixi-ease.js',
'./lib/3rdparty/pixi-viewport.js',
'./lib/3rdparty/convertPointFromPageToNode.js'
], {sourcemaps: false})
return src(
[
'./node_modules/optimal-select/dist/optimal-select.js',
'./node_modules/hammerjs/hammer.js',
'./node_modules/propagating-hammerjs/propagating.js',
'./node_modules/pixi.js/dist/browser/pixi.js',
'./node_modules/pixi-compressed-textures/lib/crn_decomp.js',
'./node_modules/pixi-compressed-textures/dist/pixi-compressed-textures.js',
'./node_modules/pixi-filters/dist/pixi-filters.js',
'./node_modules/pixi-particles/dist/pixi-particles.js',
'./node_modules/pixi-projection/dist/pixi-projection.umd.js',
'./node_modules/gsap/src/uncompressed/TweenMax.js',
'./node_modules/gsap/src/uncompressed/TimelineMax.js',
'./lib/3rdparty/jquery.js',
'./lib/3rdparty/pixi-ease.js',
'./lib/3rdparty/pixi-viewport.js',
'./lib/3rdparty/convertPointFromPageToNode.js',
'./lib/3rdparty/jquery.hypher.js',
'./lib/3rdparty/hyphenation/de.js',
'./lib/3rdparty/hyphenation/en-gb.js'
],
{ sourcemaps: false }
)
.pipe(concat('iwmlib.3rdparty.js'))
.pipe(replace(/^\/\/# sourceMappingURL=.*$/gmi, ''))
.pipe(dest('dist', {sourcemaps: false}))
.pipe(rename({extname: '.min.js'}))
.pipe(replace(/^\/\/# sourceMappingURL=.*$/gim, ''))
.pipe(dest('dist', { sourcemaps: false }))
.pipe(rename({ extname: '.min.js' }))
.pipe(uglify())
.pipe(dest('dist', {sourcemaps: false}))
.pipe(dest('dist', { sourcemaps: false }))
}
function preload() {
return src([
'./node_modules/gsap/src/uncompressed/TweenMax.js',
'./lib/3rdparty/convertPointFromPageToNode.js',
], {sourcemaps: false})
return src(['./node_modules/gsap/src/uncompressed/TweenMax.js', './lib/3rdparty/convertPointFromPageToNode.js'], {
sourcemaps: false
})
.pipe(concat('iwmlib.3rdparty.preload.js'))
.pipe(replace(/^\/\/# sourceMappingURL=.*$/gmi, ''))
.pipe(dest('dist', {sourcemaps: false}))
.pipe(rename({extname: '.min.js'}))
.pipe(replace(/^\/\/# sourceMappingURL=.*$/gim, ''))
.pipe(dest('dist', { sourcemaps: false }))
.pipe(rename({ extname: '.min.js' }))
.pipe(uglify())
.pipe(dest('dist', {sourcemaps: false}))
.pipe(dest('dist', { sourcemaps: false }))
}
exports.default = parallel(vendors, preload);
function prettify() {
return src(
['./lib/*.js', './lib/card/*.js', './lib/pixi/*.js', './lib/pixi/deepzoom/*.js', '!./lib/bootstrap.babel.js'],
{
base: './lib'
}
)
.pipe(
prettier({
singleQuote: true,
jsxSingleQuote: true,
tabWidth: 4,
semi: false,
printWidth: 120
})
)
.pipe(dest('./lib'))
}
exports.prettify = prettify
exports.default = parallel(vendors, preload)

8
iwmlib.code-workspace Normal file
View File

@ -0,0 +1,8 @@
{
"folders": [
{
"path": "."
}
],
"settings": {}
}

View File

@ -10,10 +10,10 @@
css transforms without perspective projection)
*/
(function () {
;(function () {
'use strict'
var I = (typeof(WebKitCSSMatrix) == 'undefined') ? new DOMMatrix() : new WebKitCSSMatrix()
var I = typeof WebKitCSSMatrix == 'undefined' ? new DOMMatrix() : new WebKitCSSMatrix()
function Point(x, y, z) {
this.x = x
@ -28,8 +28,8 @@
function createMatrix(transform) {
try {
return (typeof(WebKitCSSMatrix) == 'undefined') ? new DOMMatrix(transform) : new WebKitCSSMatrix(transform)
} catch(e) {
return typeof WebKitCSSMatrix == 'undefined' ? new DOMMatrix(transform) : new WebKitCSSMatrix(transform)
} catch (e) {
console.warn(transform)
console.warn(e.toString())
return I
@ -54,8 +54,9 @@
var left = +Infinity
var top = +Infinity
while (--i >= 0) {
var p = new Point(i === 0 || i === 1 ? 0 : w, i === 0 || i === 3 ? 0 : h,
0).transformBy(transformationMatrix)
var p = new Point(i === 0 || i === 1 ? 0 : w, i === 0 || i === 3 ? 0 : h, 0).transformBy(
transformationMatrix
)
if (p.x < left) {
left = p.x
}
@ -64,20 +65,19 @@
}
}
var rect = element.getBoundingClientRect()
transformationMatrix = I.translate(window.pageXOffset + rect.left - left,
window.pageYOffset + rect.top - top, 0)
.multiply(transformationMatrix)
transformationMatrix = I.translate(
window.pageXOffset + rect.left - left,
window.pageYOffset + rect.top - top,
0
).multiply(transformationMatrix)
return transformationMatrix
}
window.convertPointFromPageToNode = function (element, pageX, pageY) {
return new Point(pageX, pageY, 0).transformBy(
getTransformationMatrix(element).inverse())
return new Point(pageX, pageY, 0).transformBy(getTransformationMatrix(element).inverse())
}
window.convertPointFromNodeToPage = function (element, offsetX, offsetY) {
return new Point(offsetX, offsetY, 0).transformBy(
getTransformationMatrix(element))
return new Point(offsetX, offsetY, 0).transformBy(getTransformationMatrix(element))
}
}())
})();

View File

@ -1,6 +1,6 @@
/*!
* VERSION: 0.1.9
* DATE: 2019-02-07
* VERSION: 0.1.11
* DATE: 2019-05-16
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
@ -720,7 +720,7 @@ TweenPlugin.activate([CSSPlugin, AttrPlugin]); // to ensure treeshaking doesn't
record("out", outProgress);
}
startTime = 0;
maxDuration = Math.min(1000, vars.maxDuration || 1000, _getClippedDuration(selectedAnimation));
maxDuration = vars.maxDuration || Math.min(1000, _getClippedDuration(selectedAnimation));
if (selectedAnimation === _recordedRoot || vars.globalSync !== false) {
_merge();
linkedAnimation = _rootTween;
@ -1105,7 +1105,7 @@ TweenPlugin.activate([CSSPlugin, AttrPlugin]); // to ensure treeshaking doesn't
GSDevTools.version = "0.1.9";
GSDevTools.version = "0.1.11";
GSDevTools.logOverwrites = false;
GSDevTools.globalRecordingTime = 2;

View File

@ -1,6 +1,6 @@
/*!
* VERSION: 0.9.0
* DATE: 2019-02-07
* VERSION: 0.9.1
* DATE: 2019-02-21
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
@ -903,11 +903,11 @@ import { _gsScope } from "gsap/TweenLite.js";
propName: "morphSVG",
API: 2,
global: true,
version: "0.9.0",
version: "0.9.1",
//called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
init: function(target, value, tween, index) {
var cs = window.getComputedStyle(target),
var cs = target.nodeType ? window.getComputedStyle(target) : {},
fill = cs.fill + "",
fillSafe = !(fill === "none" || (fill.match(_numbersExp) || [])[3] === "0" || cs.fillRule === "evenodd"),
origins = (value.origin || "50 50").split(","),

View File

@ -1,6 +1,6 @@
/*!
* VERSION: 0.1.9
* DATE: 2019-02-07
* VERSION: 0.1.11
* DATE: 2019-05-16
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
@ -717,7 +717,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
record("out", outProgress);
}
startTime = 0;
maxDuration = Math.min(1000, vars.maxDuration || 1000, _getClippedDuration(selectedAnimation));
maxDuration = vars.maxDuration || Math.min(1000, _getClippedDuration(selectedAnimation));
if (selectedAnimation === _recordedRoot || vars.globalSync !== false) {
_merge();
linkedAnimation = _rootTween;
@ -1102,7 +1102,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
GSDevTools.version = "0.1.9";
GSDevTools.version = "0.1.11";
GSDevTools.logOverwrites = false;
GSDevTools.globalRecordingTime = 2;
@ -2986,7 +2986,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
if (e && e.target) {
_addListener(e.target, "mouseup", onRelease); //we also have to listen directly on the element because some browsers don't bubble up the event to the _doc on elements with contentEditable="true"
}
isClicking = (isClickable.call(self, e.target) && vars.dragClickables !== false && !force);
isClicking = (isClickable.call(self, e.target) && vars.dragClickables === false && !force);
if (isClicking) {
_addListener(e.target, "change", onRelease); //in some browsers, when you mousedown on a <select> element, no mouseup gets dispatched! So we listen for a "change" event instead.
_dispatchEvent(self, "pressInit", "onPressInit");
@ -3689,7 +3689,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
p.constructor = Draggable;
p.pointerX = p.pointerY = p.startX = p.startY = p.deltaX = p.deltaY = 0;
p.isDragging = p.isPressed = false;
Draggable.version = "0.17.0";
Draggable.version = "0.17.1";
Draggable.zIndex = 1000;
_addListener(_doc, "touchcancel", function() {

View File

@ -1,6 +1,6 @@
/*!
* VERSION: 0.9.0
* DATE: 2019-02-07
* VERSION: 0.9.1
* DATE: 2019-02-21
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
@ -906,12 +906,12 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
propName: "morphSVG",
API: 2,
global: true,
version: "0.9.0",
version: "0.9.1",
overwriteProps: ["morphSVG"],
//called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
init: function(target, value, tween, index) {
var cs = window.getComputedStyle(target),
var cs = target.nodeType ? window.getComputedStyle(target) : {},
fill = cs.fill + "",
fillSafe = !(fill === "none" || (fill.match(_numbersExp) || [])[3] === "0" || cs.fillRule === "evenodd"),
origins = (value.origin || "50 50").split(","),

View File

@ -1,6 +1,6 @@
/*!
* VERSION: 1.3.8
* DATE: 2018-05-30
* VERSION: 1.3.9
* DATE: 2019-05-17
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
@ -312,7 +312,7 @@ import { _gsScope } from "./TweenLite.js";
BezierPlugin = _gsScope._gsDefine.plugin({
propName: "bezier",
priority: -1,
version: "1.3.8",
version: "1.3.9",
API: 2,
global:true,
@ -389,26 +389,26 @@ import { _gsScope } from "./TweenLite.js";
func = this._func,
target = this._target,
notStart = (v !== this._startRatio),
curIndex, inv, i, p, b, t, val, l, lengths, curSeg;
curIndex, inv, i, p, b, t, val, l, lengths, curSeg, v1;
if (!this._timeRes) {
curIndex = (v < 0) ? 0 : (v >= 1) ? segments - 1 : (segments * v) >> 0;
t = (v - (curIndex * (1 / segments))) * segments;
} else {
lengths = this._lengths;
curSeg = this._curSeg;
v *= this._length;
v1 = v * this._length;
i = this._li;
//find the appropriate segment (if the currently cached one isn't correct)
if (v > this._l2 && i < segments - 1) {
if (v1 > this._l2 && i < segments - 1) {
l = segments - 1;
while (i < l && (this._l2 = lengths[++i]) <= v) { }
while (i < l && (this._l2 = lengths[++i]) <= v1) { }
this._l1 = lengths[i-1];
this._li = i;
this._curSeg = curSeg = this._segments[i];
this._s2 = curSeg[(this._s1 = this._si = 0)];
} else if (v < this._l1 && i > 0) {
while (i > 0 && (this._l1 = lengths[--i]) >= v) { }
if (i === 0 && v < this._l1) {
} else if (v1 < this._l1 && i > 0) {
while (i > 0 && (this._l1 = lengths[--i]) >= v1) { }
if (i === 0 && v1 < this._l1) {
this._l1 = 0;
} else {
i++;
@ -421,16 +421,16 @@ import { _gsScope } from "./TweenLite.js";
}
curIndex = i;
//now find the appropriate sub-segment (we split it into the number of pieces that was defined by "precision" and measured each one)
v -= this._l1;
v1 -= this._l1;
i = this._si;
if (v > this._s2 && i < curSeg.length - 1) {
if (v1 > this._s2 && i < curSeg.length - 1) {
l = curSeg.length - 1;
while (i < l && (this._s2 = curSeg[++i]) <= v) { }
while (i < l && (this._s2 = curSeg[++i]) <= v1) { }
this._s1 = curSeg[i-1];
this._si = i;
} else if (v < this._s1 && i > 0) {
while (i > 0 && (this._s1 = curSeg[--i]) >= v) { }
if (i === 0 && v < this._s1) {
} else if (v1 < this._s1 && i > 0) {
while (i > 0 && (this._s1 = curSeg[--i]) >= v1) { }
if (i === 0 && v1 < this._s1) {
this._s1 = 0;
} else {
i++;
@ -438,7 +438,7 @@ import { _gsScope } from "./TweenLite.js";
this._s2 = curSeg[i];
this._si = i;
}
t = ((i + (v - this._s1) / (this._s2 - this._s1)) * this._prec) || 0;
t = (v === 1) ? 1 : ((i + (v1 - this._s1) / (this._s2 - this._s1)) * this._prec) || 0;
}
inv = 1 - t;

View File

@ -1,6 +1,6 @@
/*!
* VERSION: 2.1.0
* DATE: 2019-02-15
* VERSION: 2.1.3
* DATE: 2019-05-17
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
@ -30,7 +30,7 @@ import TweenLite, { _gsScope, globals, TweenPlugin } from "./TweenLite.js";
p = CSSPlugin.prototype = new TweenPlugin("css");
p.constructor = CSSPlugin;
CSSPlugin.version = "2.1.0";
CSSPlugin.version = "2.1.3";
CSSPlugin.API = 2;
CSSPlugin.defaultTransformPerspective = 0;
CSSPlugin.defaultSkewType = "compensated";
@ -42,6 +42,7 @@ import TweenLite, { _gsScope, globals, TweenPlugin } from "./TweenLite.js";
var _numExp = /(?:\-|\.|\b)(\d|\.|e\-)+/g,
_relNumExp = /(?:\d|\-\d|\.\d|\-\.\d|\+=\d|\-=\d|\+=.\d|\-=\.\d)+/g,
_valuesExp = /(?:\+=|\-=|\-|\b)[\d\-\.]+[a-zA-Z0-9]*(?:%|\b)/gi, //finds all the values that begin with numbers or += or -= and then a number. Includes suffixes. We use this to split complex values apart like "1px 5px 20px rgb(255,102,51)"
_valuesExpWithCommas = /(?:\+=|\-=|\-|\b)[\d\-\.]+[a-zA-Z0-9]*(?:%|\b),?/gi, //finds all the values that begin with numbers or += or -= and then a number. Includes suffixes. We use this to split complex values apart like "1px 5px 20px rgb(255,102,51)"
_NaNExp = /(?![+-]?\d*\.?\d+|[+-]|e[+-]\d+)[^0-9]/g, //also allows scientific notation and doesn't kill the leading -/+ in -= and +=
_suffixExp = /(?:\d|\-|\+|=|#|\.)*/g,
_opacityExp = /opacity *= *([^)]*)/i,
@ -63,7 +64,8 @@ import TweenLite, { _gsScope, globals, TweenPlugin } from "./TweenLite.js";
_dummyElement = {style:{}},
_doc = _gsScope.document || {createElement: function() {return _dummyElement;}},
_createElement = function(type, ns) {
return (ns && _doc.createElementNS) ? _doc.createElementNS(ns, type) : _doc.createElement(type);
var e = _doc.createElementNS ? _doc.createElementNS(ns || "http://www.w3.org/1999/xhtml", type) : _doc.createElement(type);
return e.style ? e : _doc.createElement(type); //some environments won't allow access to the element's style when created with a namespace in which case we default to the standard createElement() to work around the issue. Also note that when GSAP is embedded directly inside an SVG file, createElement() won't allow access to the style object in Firefox (see https://greensock.com/forums/topic/20215-problem-using-tweenmax-in-standalone-self-containing-svg-file-err-cannot-set-property-csstext-of-undefined/).
},
_tempDiv = _createElement("div"),
_tempImg = _createElement("img"),
@ -643,14 +645,14 @@ import TweenLite, { _gsScope, globals, TweenPlugin } from "./TweenLite.js";
}
return a.join(",");
}
vals = v.match(_valuesExp) || [];
vals = v.match(delim === "," ? _valuesExp : _valuesExpWithCommas) || [];
i = vals.length;
if (numVals > i--) {
while (++i < numVals) {
vals[i] = collapsible ? vals[(((i - 1) / 2) | 0)] : dVals[i];
}
}
return pfx + vals.join(delim) + sfx;
return ((pfx && v !== "none") ? v.substr(0, v.indexOf(vals[0])) || pfx : pfx) + vals.join(delim) + sfx; //note: prefix might be different, like for clipPath it could start with inset( or polygon(
};
return formatter;
},
@ -1233,7 +1235,7 @@ import TweenLite, { _gsScope, globals, TweenPlugin } from "./TweenLite.js";
//IE and Android stock don't support CSS transforms on SVG elements, so we must write them to the "transform" attribute. We populate this variable in the _parseTransform() method, and only if/when we come across an SVG element
var force = _ieVers || (/Android/i.test(_agent) && !_gsScope.chrome),
svg, rect, width;
if (_doc.createElementNS && !force) { //IE8 and earlier doesn't support SVG anyway
if (_doc.createElementNS && _docElement.appendChild && !force) { //IE8 and earlier doesn't support SVG anyway
svg = _createSVG("svg", _docElement);
rect = _createSVG("rect", svg, {width:100, height:50, x:100});
width = rect.getBoundingClientRect().width;
@ -1351,7 +1353,7 @@ import TweenLite, { _gsScope, globals, TweenPlugin } from "./TweenLite.js";
s = (s && s.length === 4) ? [s[0].substr(4), Number(s[2].substr(4)), Number(s[1].substr(4)), s[3].substr(4), (tm.x || 0), (tm.y || 0)].join(",") : "";
}
isDefault = (!s || s === "none" || s === "matrix(1, 0, 0, 1, 0, 0)");
if (_transformProp && isDefault && !e.offsetParent) { //note: if offsetParent is null, that means the element isn't in the normal document flow, like if it has display:none or one of its ancestors has display:none). Firefox returns null for getComputedStyle() if the element is in an iframe that has display:none. https://bugzilla.mozilla.org/show_bug.cgi?id=548397
if (_transformProp && isDefault && !e.offsetParent && e !== _docElement) { //note: if offsetParent is null, that means the element isn't in the normal document flow, like if it has display:none or one of its ancestors has display:none). Firefox returns null for getComputedStyle() if the element is in an iframe that has display:none. https://bugzilla.mozilla.org/show_bug.cgi?id=548397
//browsers don't report transforms accurately unless the element is in the DOM and has a display value that's not "none". Firefox and Microsoft browsers have a partial bug where they'll report transforms even if display:none BUT not any percentage-based values like translate(-50%, 8px) will be reported as if it's translate(0, 8px).
n = style.display;
style.display = "block";
@ -2113,7 +2115,7 @@ import TweenLite, { _gsScope, globals, TweenPlugin } from "./TweenLite.js";
}, allowFunc:true, prefix:true});
_registerComplexSpecialProp("boxShadow", {defaultValue:"0px 0px 0px 0px #999", prefix:true, color:true, multi:true, keyword:"inset"});
_registerComplexSpecialProp("clipPath", {defaultValue:"inset(0px)", prefix:true, multi:true, formatter:_getFormatter("inset(0px 0px 0px 0px)", false, true)});
_registerComplexSpecialProp("clipPath", {defaultValue:"inset(0%)", prefix:true, multi:true, formatter:_getFormatter("inset(0% 0% 0% 0%)", false, true)});
_registerComplexSpecialProp("borderRadius", {defaultValue:"0px", parser:function(t, e, p, cssp, pt, plugin) {
e = this.format(e);
@ -2367,7 +2369,9 @@ import TweenLite, { _gsScope, globals, TweenPlugin } from "./TweenLite.js";
difData = _cssDif(t, bs, _getAllStyles(t), vars, cnptLookup);
t.setAttribute("class", b);
pt.data = difData.firstMPT;
t.style.cssText = cssText; //we recorded cssText before we swapped classes and ran _getAllStyles() because in cases when a className tween is overwritten, we remove all the related tweening properties from that class change (otherwise class-specific stuff can't override properties we've directly set on the target's style object due to specificity).
if (t.style.cssText !== cssText) { //only apply if things change. Otherwise, in cases like a background-image that's pulled dynamically, it could cause a refresh. See https://greensock.com/forums/topic/20368-possible-gsap-bug-switching-classnames-in-chrome/.
t.style.cssText = cssText; //we recorded cssText before we swapped classes and ran _getAllStyles() because in cases when a className tween is overwritten, we remove all the related tweening properties from that class change (otherwise class-specific stuff can't override properties we've directly set on the target's style object due to specificity).
}
pt = pt.xfirst = cssp.parse(t, difData.difs, pt, plugin); //we record the CSSPropTween as the xfirst so that we can handle overwriting propertly (if "className" gets overwritten, we must kill all the properties associated with the className part of the tween, so we can loop through from xfirst to the pt itself)
return pt;
}});

View File

@ -1,6 +1,6 @@
/*!
* VERSION: 0.6.7
* DATE: 2018-08-27
* VERSION: 0.6.8
* DATE: 2019-02-22
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
@ -27,7 +27,7 @@ _gsScope._gsDefine("plugins.CSSRulePlugin", ["plugins.TweenPlugin","TweenLite","
p._propName = "cssRule";
p.constructor = CSSRulePlugin;
CSSRulePlugin.version = "0.6.7";
CSSRulePlugin.version = "0.6.8";
CSSRulePlugin.API = 2;
/**
@ -93,7 +93,12 @@ _gsScope._gsDefine("plugins.CSSRulePlugin", ["plugins.TweenPlugin","TweenLite","
// @private gets called every time the tween updates, passing the new ratio (typically a value between 0 and 1, but not always (for example, if an Elastic.easeOut is used, the value can jump above 1 mid-tween). It will always start and 0 and end at 1.
p.setRatio = function(v) {
_superSetRatio.call(this, v);
this._ss.cssText = this._proxy.cssText;
var proxy = this._proxy,
ss = this._ss,
i = proxy.length;
while (--i > -1) {
ss[proxy[i]] = proxy[proxy[i]];
}
};

View File

@ -1,6 +1,6 @@
/*!
* VERSION: 0.17.0
* DATE: 2019-02-07
* VERSION: 0.17.1
* DATE: 2019-02-28
* UPDATES AND DOCS AT: http://greensock.com
*
* Requires TweenLite and CSSPlugin version 1.17.0 or later (TweenMax contains both TweenLite and CSSPlugin). ThrowPropsPlugin is required for momentum-based continuation of movement after the mouse/touch is released (ThrowPropsPlugin is a membership benefit of Club GreenSock - http://greensock.com/club/).
@ -1695,7 +1695,7 @@ import CSSPlugin from "./CSSPlugin.js";
if (e && e.target) {
_addListener(e.target, "mouseup", onRelease); //we also have to listen directly on the element because some browsers don't bubble up the event to the _doc on elements with contentEditable="true"
}
isClicking = (isClickable.call(self, e.target) && vars.dragClickables !== false && !force);
isClicking = (isClickable.call(self, e.target) && vars.dragClickables === false && !force);
if (isClicking) {
_addListener(e.target, "change", onRelease); //in some browsers, when you mousedown on a <select> element, no mouseup gets dispatched! So we listen for a "change" event instead.
_dispatchEvent(self, "pressInit", "onPressInit");
@ -2398,7 +2398,7 @@ import CSSPlugin from "./CSSPlugin.js";
p.constructor = Draggable;
p.pointerX = p.pointerY = p.startX = p.startY = p.deltaX = p.deltaY = 0;
p.isDragging = p.isPressed = false;
Draggable.version = "0.17.0";
Draggable.version = "0.17.1";
Draggable.zIndex = 1000;
_addListener(_doc, "touchcancel", function() {

View File

@ -1,6 +1,6 @@
/*!
* VERSION: 0.2.1
* DATE: 2018-05-30
* VERSION: 0.3.0
* DATE: 2019-05-13
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
@ -389,13 +389,14 @@ import { _gsScope } from "./TweenLite.js";
priority: 0,
API: 2,
global: true,
version: "0.2.1",
version: "0.3.0",
init: function (target, values, tween, index) {
if (!target instanceof _gsScope.PIXI.DisplayObject) {
return false;
}
var context, axis, value, colorMatrix, filter, p, padding, colorSetter, i, data, pt;
var isV4 = _gsScope.PIXI.VERSION.charAt(0) === "4",
context, axis, value, colorMatrix, filter, p, padding, colorSetter, i, data, pt;
for (p in values) {
context = _contexts[p];
value = values[p];
@ -431,12 +432,12 @@ import { _gsScope } from "./TweenLite.js";
colorSetter = _buildColorSetter(tween, this);
}
if ((p === "lineColor" || p === "fillColor") && target instanceof _gsScope.PIXI.Graphics) {
data = target.graphicsData;
data = (target.geometry || target).graphicsData; //"geometry" was introduced in PIXI version 5
i = data.length;
while (--i > -1) {
_addColorTween(data[i], p, value, colorSetter, this);
_addColorTween(isV4 ? data[i] : data[i][p.substr(0, 4) + "Style"], isV4 ? p : "color", value, colorSetter, this);
}
colorSetter.graphics = target;
colorSetter.graphics = target.geometry || target;
} else {
_addColorTween(target, p, value, colorSetter, this);
}
@ -460,5 +461,8 @@ import { _gsScope } from "./TweenLite.js";
PixiPlugin.parseColor = _parseColor;
PixiPlugin.formatColors = _formatColors;
PixiPlugin.colorStringFilter = _colorStringFilter;
PixiPlugin.registerPIXI = function(PIXI) {
_gsScope.PIXI = PIXI;
};
export { PixiPlugin, PixiPlugin as default };

View File

@ -1,6 +1,6 @@
/*!
* VERSION: 2.1.0
* DATE: 2019-02-15
* VERSION: 2.1.3
* DATE: 2019-05-17
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
@ -70,16 +70,16 @@ _gsScope._gsDefine("TimelineLite", ["core.Animation","core.SimpleTimeline","Twee
_defaultImmediateRender = function(tl, toVars, fromVars, defaultFalse) { //default to immediateRender:true unless otherwise set in toVars, fromVars or if defaultFalse is passed in as true
var ir = "immediateRender";
if (!(ir in toVars)) {
toVars[ir] = !(tl._paused || (fromVars && fromVars[ir] === false) || defaultFalse);
toVars[ir] = !((fromVars && fromVars[ir] === false) || defaultFalse);
}
return toVars;
},
//for distributing values across an array. Can accept a number, a function or (most commonly) a function which can contain the following properties: {base, amount, from, ease, grid, axis, length}. Returns a function that expects the following parameters: index, target, array. Recognizes the following
//for distributing values across an array. Can accept a number, a function or (most commonly) a function which can contain the following properties: {base, amount, from, ease, grid, axis, length, each}. Returns a function that expects the following parameters: index, target, array. Recognizes the following
_distribute = function(v) {
if (typeof(v) === "function") {
return v;
}
var vars = isNaN(v) ? v : {n:1, from:(v < 0) ? ((v = -v) && "end") : 0}, //n:1 is just to indicate v was a number; we leverage that later to set v according to the length we get. If a number is passed in, we treat it like the old stagger value where 0.1, for example, would mean that things would be distributed with 0.1 between each element in the array rather than a total "amount" that's chunked out among them all.
var vars = (typeof(v) === "object") ? v : {each:v}, //n:1 is just to indicate v was a number; we leverage that later to set v according to the length we get. If a number is passed in, we treat it like the old stagger value where 0.1, for example, would mean that things would be distributed with 0.1 between each element in the array rather than a total "amount" that's chunked out among them all.
ease = vars.ease,
from = vars.from || 0,
base = vars.base || 0,
@ -116,15 +116,16 @@ _gsScope._gsDefine("TimelineLite", ["core.Animation","core.SimpleTimeline","Twee
}
distances.max = max - min;
distances.min = min;
distances.v = vars.n ? l * (v || 0) : vars.amount;
distances.v = l = vars.amount || (vars.each * (wrap > l ? l - 1 : !axis ? Math.max(wrap, l / wrap) : axis === "y" ? l / wrap : wrap)) || 0;
distances.b = (l < 0) ? base - l : base;
}
l = (distances[i] - distances.min) / distances.max;
return base + (ease ? ease.getRatio(l) : l) * distances.v;
return distances.b + (ease ? ease.getRatio(l) : l) * distances.v;
};
},
p = TimelineLite.prototype = new SimpleTimeline();
TimelineLite.version = "2.1.0";
TimelineLite.version = "2.1.3";
TimelineLite.distribute = _distribute;
p.constructor = TimelineLite;
p.kill()._gc = p._forcingPlayhead = p._hasPause = false;
@ -441,6 +442,29 @@ _gsScope._gsDefine("TimelineLite", ["core.Animation","core.SimpleTimeline","Twee
if (prevTime !== self._time) { //if totalDuration() finds a child with a negative startTime and smoothChildTiming is true, things get shifted around internally so we need to adjust the time accordingly. For example, if a tween starts at -30 we must shift EVERYTHING forward 30 seconds and move this timeline's startTime backward by 30 seconds so that things align with the playhead (no jump).
time += self._time - prevTime;
}
if (self._hasPause && !self._forcingPlayhead && !suppressEvents) {
if (time > prevTime) {
tween = self._first;
while (tween && tween._startTime <= time && !pauseTween) {
if (!tween._duration) if (tween.data === "isPause" && !tween.ratio && !(tween._startTime === 0 && self._rawPrevTime === 0)) {
pauseTween = tween;
}
tween = tween._next;
}
} else {
tween = self._last;
while (tween && tween._startTime >= time && !pauseTween) {
if (!tween._duration) if (tween.data === "isPause" && tween._rawPrevTime > 0) {
pauseTween = tween;
}
tween = tween._prev;
}
}
if (pauseTween) {
self._time = self._totalTime = time = pauseTween._startTime;
pauseTime = self._startTime + (self._reversed ? self._duration - time : time) / self._timeScale;
}
}
if (time >= totalDur - _tinyNum && time >= 0) { //to work around occasional floating point math artifacts.
self._totalTime = self._time = totalDur;
if (!self._reversed) if (!self._hasPausedChild()) {
@ -493,31 +517,6 @@ _gsScope._gsDefine("TimelineLite", ["core.Animation","core.SimpleTimeline","Twee
}
} else {
if (self._hasPause && !self._forcingPlayhead && !suppressEvents) {
if (time >= prevTime) {
tween = self._first;
while (tween && tween._startTime <= time && !pauseTween) {
if (!tween._duration) if (tween.data === "isPause" && !tween.ratio && !(tween._startTime === 0 && self._rawPrevTime === 0)) {
pauseTween = tween;
}
tween = tween._next;
}
} else {
tween = self._last;
while (tween && tween._startTime >= time && !pauseTween) {
if (!tween._duration) if (tween.data === "isPause" && tween._rawPrevTime > 0) {
pauseTween = tween;
}
tween = tween._prev;
}
}
if (pauseTween) {
self._time = self._totalTime = time = pauseTween._startTime;
pauseTime = self._startTime + (time / self._timeScale);
}
}
self._totalTime = self._time = self._rawPrevTime = time;
}
if ((self._time === prevTime || !self._first) && !force && !internalForce && !pauseTween) {

View File

@ -1,6 +1,6 @@
/*!
* VERSION: 2.1.0
* DATE: 2019-02-15
* VERSION: 2.1.3
* DATE: 2019-05-17
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
@ -34,7 +34,7 @@ _gsScope._gsDefine("TimelineMax", ["TimelineLite","TweenLite","easing.Ease"], fu
p.constructor = TimelineMax;
p.kill()._gc = false;
TimelineMax.version = "2.1.0";
TimelineMax.version = "2.1.3";
p.invalidate = function() {
this._yoyo = !!this.vars.yoyo;
@ -210,35 +210,34 @@ _gsScope._gsDefine("TimelineMax", ["TimelineLite","TweenLite","easing.Ease"], fu
}
}
}
}
if (self._hasPause && !self._forcingPlayhead && !suppressEvents) {
time = self._time;
if (time >= prevTime || (self._repeat && prevCycle !== self._cycle)) {
tween = self._first;
while (tween && tween._startTime <= time && !pauseTween) {
if (!tween._duration) if (tween.data === "isPause" && !tween.ratio && !(tween._startTime === 0 && self._rawPrevTime === 0)) {
pauseTween = tween;
}
tween = tween._next;
}
} else {
tween = self._last;
while (tween && tween._startTime >= time && !pauseTween) {
if (!tween._duration) if (tween.data === "isPause" && tween._rawPrevTime > 0) {
pauseTween = tween;
}
tween = tween._prev;
if (self._hasPause && !self._forcingPlayhead && !suppressEvents) {
time = self._time;
if (time > prevTime || (self._repeat && prevCycle !== self._cycle)) {
tween = self._first;
while (tween && tween._startTime <= time && !pauseTween) {
if (!tween._duration) if (tween.data === "isPause" && !tween.ratio && !(tween._startTime === 0 && self._rawPrevTime === 0)) {
pauseTween = tween;
}
tween = tween._next;
}
if (pauseTween) {
pauseTime = self._startTime + (pauseTween._startTime / self._timeScale);
if (pauseTween._startTime < dur) {
self._time = self._rawPrevTime = time = pauseTween._startTime;
self._totalTime = time + (self._cycle * (self._totalDuration + self._repeatDelay));
} else {
tween = self._last;
while (tween && tween._startTime >= time && !pauseTween) {
if (!tween._duration) if (tween.data === "isPause" && tween._rawPrevTime > 0) {
pauseTween = tween;
}
tween = tween._prev;
}
}
if (pauseTween) {
pauseTime = self._startTime + (self._reversed ? self._duration - pauseTween._startTime : pauseTween._startTime) / self._timeScale;
if (pauseTween._startTime < dur) {
self._time = self._rawPrevTime = time = pauseTween._startTime;
self._totalTime = time + (self._cycle * (self._totalDuration + self._repeatDelay));
}
}
}
if (self._cycle !== prevCycle) if (!self._locked) {
@ -477,7 +476,7 @@ _gsScope._gsDefine("TimelineMax", ["TimelineLite","TweenLite","easing.Ease"], fu
}
var duration = this._duration,
cycle = this._cycle,
cycleDur = cycle * (duration * this._repeatDelay);
cycleDur = cycle * (duration + this._repeatDelay);
if (value > duration) {
value = duration;
}

View File

@ -1,6 +1,6 @@
/*!
* VERSION: 2.1.0
* DATE: 2019-02-15
* VERSION: 2.1.3
* DATE: 2019-05-17
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
@ -972,7 +972,7 @@ export var TweenLite = (function(window) {
p._firstPT = p._targets = p._overwrittenProps = p._startAt = null;
p._notifyPluginsOfEnabled = p._lazy = false;
TweenLite.version = "2.1.0";
TweenLite.version = "2.1.3";
TweenLite.defaultEase = p._ease = new Ease(null, null, 1, 1);
TweenLite.defaultOverwrite = "auto";
TweenLite.ticker = _ticker;

View File

@ -1,6 +1,6 @@
/*!
* VERSION: 2.1.0
* DATE: 2019-02-15
* VERSION: 2.1.3
* DATE: 2019-05-17
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.

View File

@ -1,6 +1,6 @@
/*!
* VERSION: 2.1.0
* DATE: 2019-02-15
* VERSION: 2.1.3
* DATE: 2019-05-17
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
@ -32,12 +32,12 @@ _gsScope._gsDefine("TweenMax", ["core.Animation","core.SimpleTimeline","TweenLit
}
delete vars.cycle;
},
//for distributing values across an array. Can accept a number, a function or (most commonly) a function which can contain the following properties: {base, amount, from, ease, grid, axis, length}. Returns a function that expects the following parameters: index, target, array. Recognizes the following
//for distributing values across an array. Can accept a number, a function or (most commonly) a function which can contain the following properties: {base, amount, from, ease, grid, axis, length, each}. Returns a function that expects the following parameters: index, target, array. Recognizes the following
_distribute = function(v) {
if (typeof(v) === "function") {
return v;
}
var vars = isNaN(v) ? v : {n:1, from:(v < 0) ? ((v = -v) && "end") : 0}, //n:1 is just to indicate v was a number; we leverage that later to set v according to the length we get. If a number is passed in, we treat it like the old stagger value where 0.1, for example, would mean that things would be distributed with 0.1 between each element in the array rather than a total "amount" that's chunked out among them all.
var vars = (typeof(v) === "object") ? v : {each:v}, //n:1 is just to indicate v was a number; we leverage that later to set v according to the length we get. If a number is passed in, we treat it like the old stagger value where 0.1, for example, would mean that things would be distributed with 0.1 between each element in the array rather than a total "amount" that's chunked out among them all.
ease = vars.ease,
from = vars.from || 0,
base = vars.base || 0,
@ -74,10 +74,11 @@ _gsScope._gsDefine("TweenMax", ["core.Animation","core.SimpleTimeline","TweenLit
}
distances.max = max - min;
distances.min = min;
distances.v = vars.n ? l * (v || 0) : vars.amount;
distances.v = l = vars.amount || (vars.each * (wrap > l ? l - 1 : !axis ? Math.max(wrap, l / wrap) : axis === "y" ? l / wrap : wrap)) || 0;
distances.b = (l < 0) ? base - l : base;
}
l = (distances[i] - distances.min) / distances.max;
return base + (ease ? ease.getRatio(l) : l) * distances.v;
return distances.b + (ease ? ease.getRatio(l) : l) * distances.v;
};
},
TweenMax = function(target, duration, vars) {
@ -98,7 +99,7 @@ _gsScope._gsDefine("TweenMax", ["core.Animation","core.SimpleTimeline","TweenLit
p = TweenMax.prototype = TweenLite.to({}, 0.1, {}),
_blankArray = [];
TweenMax.version = "2.1.0";
TweenMax.version = "2.1.3";
p.constructor = TweenMax;
p.kill()._gc = false;
TweenMax.killTweensOf = TweenMax.killDelayedCallsTo = TweenLite.killTweensOf;
@ -594,7 +595,7 @@ _gsScope._gsDefine("TweenMax", ["core.Animation","core.SimpleTimeline","TweenLit
//---- GETTERS / SETTERS ----------------------------------------------------------------------------------------------------------
p.progress = function(value, suppressEvents) {
return (!arguments.length) ? this._time / this.duration() : this.totalTime( this.duration() * ((this._yoyo && (this._cycle & 1) !== 0) ? 1 - value : value) + (this._cycle * (this._duration + this._repeatDelay)), suppressEvents);
return (!arguments.length) ? (this.duration() ? this._time / this._duration : this.ratio) : this.totalTime( this.duration() * ((this._yoyo && (this._cycle & 1) !== 0) ? 1 - value : value) + (this._cycle * (this._duration + this._repeatDelay)), suppressEvents);
};
p.totalProgress = function(value, suppressEvents) {
@ -610,7 +611,7 @@ _gsScope._gsDefine("TweenMax", ["core.Animation","core.SimpleTimeline","TweenLit
}
var duration = this._duration,
cycle = this._cycle,
cycleDur = cycle * (duration * this._repeatDelay);
cycleDur = cycle * (duration + this._repeatDelay);
if (value > duration) {
value = duration;
}

View File

@ -1,6 +1,6 @@
/*!
* VERSION: 2.1.0
* DATE: 2019-02-15
* VERSION: 2.1.3
* DATE: 2019-05-17
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.

View File

@ -1,6 +1,6 @@
/*!
* VERSION: 2.1.0
* DATE: 2019-02-07
* VERSION: 2.1.3
* DATE: 2019-05-17
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.

View File

@ -1,7 +1,7 @@
{
"name": "gsap",
"version": "2.1.0",
"description": "GSAP is a JavaScript library for creating high-performance animations that work in **every** major browser (or beyond the browser). No other library delivers such advanced sequencing, reliability, API efficiency, and tight control while solving real-world problems on over 4 million sites. GSAP works around countless browser inconsistencies; your animations 'just work'. Animate CSS properties, SVG, canvas libraries, custom properties of generic objects, colors, strings...pretty much anything! At its core, GSAP is a property manipulator, updating values over time very quickly with extreme accuracy. And it's up to 20x faster than jQuery! See http://greensock.com/why-gsap/ for details about what makes GSAP so special.",
"version": "2.1.3",
"description": "GSAP is a JavaScript library for creating high-performance animations that work in **every** major browser (or beyond the browser). No other library delivers such advanced sequencing, reliability, API efficiency, and tight control while solving real-world problems on over 8 million sites. GSAP works around countless browser inconsistencies; your animations 'just work'. Animate CSS properties, SVG, canvas libraries, custom properties of generic objects, colors, strings...pretty much anything! At its core, GSAP is a property manipulator, updating values over time very quickly with extreme accuracy. And it's up to 20x faster than jQuery! See http://greensock.com/why-gsap/ for details about what makes GSAP so special.",
"homepage": "https://greensock.com/gsap/",
"filename": "index.js",
"module": "index.js",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
/*!
* VERSION: 0.6.6
* DATE: 2018-02-15
* VERSION: 0.6.8
* DATE: 2018-02-22
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
@ -9,4 +9,4 @@
*
* @author: Jack Doyle, jack@greensock.com
*/
var _gsScope="undefined"!=typeof module&&module.exports&&"undefined"!=typeof global?global:this||window;(_gsScope._gsQueue||(_gsScope._gsQueue=[])).push(function(){"use strict";_gsScope._gsDefine("plugins.CSSRulePlugin",["plugins.TweenPlugin","TweenLite","plugins.CSSPlugin"],function(a,b,c){var d=function(){a.call(this,"cssRule"),this._overwriteProps.length=0},e=_gsScope.document,f=c.prototype.setRatio,g=d.prototype=new c;return g._propName="cssRule",g.constructor=d,d.version="0.6.6",d.API=2,d.getRule=function(a){var b,c,d,f,g=e.all?"rules":"cssRules",h=e.styleSheets,i=h.length,j=":"===a.charAt(0);for(a=(j?"":",")+a.split("::").join(":").toLowerCase()+",",j&&(f=[]);--i>-1;){try{if(c=h[i][g],!c)continue;b=c.length}catch(k){console.log(k);continue}for(;--b>-1;)if(d=c[b],d.selectorText&&-1!==(","+d.selectorText.split("::").join(":").toLowerCase()+",").indexOf(a)){if(!j)return d.style;f.push(d.style)}}return f},g._onInitTween=function(a,b,d){if(void 0===a.cssText)return!1;var f=a._gsProxy=a._gsProxy||e.createElement("div");return this._ss=a,this._proxy=f.style,f.style.cssText=a.cssText,c.prototype._onInitTween.call(this,f,b,d),!0},g.setRatio=function(a){f.call(this,a),this._ss.cssText=this._proxy.cssText},a.activate([d]),d},!0)}),_gsScope._gsDefine&&_gsScope._gsQueue.pop()(),function(a){"use strict";var b=function(){return(_gsScope.GreenSockGlobals||_gsScope)[a]};"undefined"!=typeof module&&module.exports?(require("../TweenLite.min.js"),module.exports=b()):"function"==typeof define&&define.amd&&define(["TweenLite"],b)}("CSSRulePlugin");
var _gsScope="undefined"!=typeof module&&module.exports&&"undefined"!=typeof global?global:this||window;(_gsScope._gsQueue||(_gsScope._gsQueue=[])).push(function(){"use strict";_gsScope._gsDefine("plugins.CSSRulePlugin",["plugins.TweenPlugin","TweenLite","plugins.CSSPlugin"],function(a,b,c){var d=function(){a.call(this,"cssRule"),this._overwriteProps.length=0},e=_gsScope.document,f=c.prototype.setRatio,g=d.prototype=new c;return g._propName="cssRule",g.constructor=d,d.version="0.6.8",d.API=2,d.getRule=function(a){var b,c,d,f,g=e.all?"rules":"cssRules",h=e.styleSheets,i=h.length,j=":"===a.charAt(0);for(a=(j?"":",")+a.split("::").join(":").toLowerCase()+",",j&&(f=[]);--i>-1;){try{if(c=h[i][g],!c)continue;b=c.length}catch(k){console.log(k);continue}for(;--b>-1;)if(d=c[b],d.selectorText&&-1!==(","+d.selectorText.split("::").join(":").toLowerCase()+",").indexOf(a)){if(!j)return d.style;f.push(d.style)}}return f},g._onInitTween=function(a,b,d){if(void 0===a.cssText)return!1;var f=a._gsProxy=a._gsProxy||e.createElement("div");return this._ss=a,this._proxy=f.style,f.style.cssText=a.cssText,c.prototype._onInitTween.call(this,f,b,d),!0},g.setRatio=function(a){f.call(this,a);for(var b=this._proxy,c=this._ss,d=b.length;--d>-1;)c[b[d]]=b[b[d]]},a.activate([d]),d},!0)}),_gsScope._gsDefine&&_gsScope._gsQueue.pop()(),function(a){"use strict";var b=function(){return(_gsScope.GreenSockGlobals||_gsScope)[a]};"undefined"!=typeof module&&module.exports?(require("../TweenLite.min.js"),module.exports=b()):"function"==typeof define&&define.amd&&define(["TweenLite"],b)}("CSSRulePlugin");

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
/*!
* VERSION: 2.1.0
* DATE: 2019-02-15
* VERSION: 2.1.3
* DATE: 2019-05-17
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
@ -72,16 +72,16 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
_defaultImmediateRender = function(tl, toVars, fromVars, defaultFalse) { //default to immediateRender:true unless otherwise set in toVars, fromVars or if defaultFalse is passed in as true
var ir = "immediateRender";
if (!(ir in toVars)) {
toVars[ir] = !(tl._paused || (fromVars && fromVars[ir] === false) || defaultFalse);
toVars[ir] = !((fromVars && fromVars[ir] === false) || defaultFalse);
}
return toVars;
},
//for distributing values across an array. Can accept a number, a function or (most commonly) a function which can contain the following properties: {base, amount, from, ease, grid, axis, length}. Returns a function that expects the following parameters: index, target, array. Recognizes the following
//for distributing values across an array. Can accept a number, a function or (most commonly) a function which can contain the following properties: {base, amount, from, ease, grid, axis, length, each}. Returns a function that expects the following parameters: index, target, array. Recognizes the following
_distribute = function(v) {
if (typeof(v) === "function") {
return v;
}
var vars = isNaN(v) ? v : {n:1, from:(v < 0) ? ((v = -v) && "end") : 0}, //n:1 is just to indicate v was a number; we leverage that later to set v according to the length we get. If a number is passed in, we treat it like the old stagger value where 0.1, for example, would mean that things would be distributed with 0.1 between each element in the array rather than a total "amount" that's chunked out among them all.
var vars = (typeof(v) === "object") ? v : {each:v}, //n:1 is just to indicate v was a number; we leverage that later to set v according to the length we get. If a number is passed in, we treat it like the old stagger value where 0.1, for example, would mean that things would be distributed with 0.1 between each element in the array rather than a total "amount" that's chunked out among them all.
ease = vars.ease,
from = vars.from || 0,
base = vars.base || 0,
@ -118,15 +118,16 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
}
distances.max = max - min;
distances.min = min;
distances.v = vars.n ? l * (v || 0) : vars.amount;
distances.v = l = vars.amount || (vars.each * (wrap > l ? l - 1 : !axis ? Math.max(wrap, l / wrap) : axis === "y" ? l / wrap : wrap)) || 0;
distances.b = (l < 0) ? base - l : base;
}
l = (distances[i] - distances.min) / distances.max;
return base + (ease ? ease.getRatio(l) : l) * distances.v;
return distances.b + (ease ? ease.getRatio(l) : l) * distances.v;
};
},
p = TimelineLite.prototype = new SimpleTimeline();
TimelineLite.version = "2.1.0";
TimelineLite.version = "2.1.3";
TimelineLite.distribute = _distribute;
p.constructor = TimelineLite;
p.kill()._gc = p._forcingPlayhead = p._hasPause = false;
@ -443,6 +444,29 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
if (prevTime !== self._time) { //if totalDuration() finds a child with a negative startTime and smoothChildTiming is true, things get shifted around internally so we need to adjust the time accordingly. For example, if a tween starts at -30 we must shift EVERYTHING forward 30 seconds and move this timeline's startTime backward by 30 seconds so that things align with the playhead (no jump).
time += self._time - prevTime;
}
if (self._hasPause && !self._forcingPlayhead && !suppressEvents) {
if (time > prevTime) {
tween = self._first;
while (tween && tween._startTime <= time && !pauseTween) {
if (!tween._duration) if (tween.data === "isPause" && !tween.ratio && !(tween._startTime === 0 && self._rawPrevTime === 0)) {
pauseTween = tween;
}
tween = tween._next;
}
} else {
tween = self._last;
while (tween && tween._startTime >= time && !pauseTween) {
if (!tween._duration) if (tween.data === "isPause" && tween._rawPrevTime > 0) {
pauseTween = tween;
}
tween = tween._prev;
}
}
if (pauseTween) {
self._time = self._totalTime = time = pauseTween._startTime;
pauseTime = self._startTime + (self._reversed ? self._duration - time : time) / self._timeScale;
}
}
if (time >= totalDur - _tinyNum && time >= 0) { //to work around occasional floating point math artifacts.
self._totalTime = self._time = totalDur;
if (!self._reversed) if (!self._hasPausedChild()) {
@ -495,31 +519,6 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
}
} else {
if (self._hasPause && !self._forcingPlayhead && !suppressEvents) {
if (time >= prevTime) {
tween = self._first;
while (tween && tween._startTime <= time && !pauseTween) {
if (!tween._duration) if (tween.data === "isPause" && !tween.ratio && !(tween._startTime === 0 && self._rawPrevTime === 0)) {
pauseTween = tween;
}
tween = tween._next;
}
} else {
tween = self._last;
while (tween && tween._startTime >= time && !pauseTween) {
if (!tween._duration) if (tween.data === "isPause" && tween._rawPrevTime > 0) {
pauseTween = tween;
}
tween = tween._prev;
}
}
if (pauseTween) {
self._time = self._totalTime = time = pauseTween._startTime;
pauseTime = self._startTime + (time / self._timeScale);
}
}
self._totalTime = self._time = self._rawPrevTime = time;
}
if ((self._time === prevTime || !self._first) && !force && !internalForce && !pauseTween) {

View File

@ -1,6 +1,6 @@
/*!
* VERSION: 2.1.0
* DATE: 2019-02-11
* VERSION: 2.1.3
* DATE: 2019-05-17
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
@ -35,7 +35,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
p.constructor = TimelineMax;
p.kill()._gc = false;
TimelineMax.version = "2.1.0";
TimelineMax.version = "2.1.3";
p.invalidate = function() {
this._yoyo = !!this.vars.yoyo;
@ -211,35 +211,34 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
}
}
}
}
if (self._hasPause && !self._forcingPlayhead && !suppressEvents) {
time = self._time;
if (time >= prevTime || (self._repeat && prevCycle !== self._cycle)) {
tween = self._first;
while (tween && tween._startTime <= time && !pauseTween) {
if (!tween._duration) if (tween.data === "isPause" && !tween.ratio && !(tween._startTime === 0 && self._rawPrevTime === 0)) {
pauseTween = tween;
}
tween = tween._next;
}
} else {
tween = self._last;
while (tween && tween._startTime >= time && !pauseTween) {
if (!tween._duration) if (tween.data === "isPause" && tween._rawPrevTime > 0) {
pauseTween = tween;
}
tween = tween._prev;
if (self._hasPause && !self._forcingPlayhead && !suppressEvents) {
time = self._time;
if (time > prevTime || (self._repeat && prevCycle !== self._cycle)) {
tween = self._first;
while (tween && tween._startTime <= time && !pauseTween) {
if (!tween._duration) if (tween.data === "isPause" && !tween.ratio && !(tween._startTime === 0 && self._rawPrevTime === 0)) {
pauseTween = tween;
}
tween = tween._next;
}
if (pauseTween) {
pauseTime = self._startTime + (pauseTween._startTime / self._timeScale);
if (pauseTween._startTime < dur) {
self._time = self._rawPrevTime = time = pauseTween._startTime;
self._totalTime = time + (self._cycle * (self._totalDuration + self._repeatDelay));
} else {
tween = self._last;
while (tween && tween._startTime >= time && !pauseTween) {
if (!tween._duration) if (tween.data === "isPause" && tween._rawPrevTime > 0) {
pauseTween = tween;
}
tween = tween._prev;
}
}
if (pauseTween) {
pauseTime = self._startTime + (self._reversed ? self._duration - pauseTween._startTime : pauseTween._startTime) / self._timeScale;
if (pauseTween._startTime < dur) {
self._time = self._rawPrevTime = time = pauseTween._startTime;
self._totalTime = time + (self._cycle * (self._totalDuration + self._repeatDelay));
}
}
}
if (self._cycle !== prevCycle) if (!self._locked) {
@ -478,7 +477,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
}
var duration = this._duration,
cycle = this._cycle,
cycleDur = cycle * (duration * this._repeatDelay);
cycleDur = cycle * (duration + this._repeatDelay);
if (value > duration) {
value = duration;
}
@ -589,16 +588,16 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
_defaultImmediateRender = function(tl, toVars, fromVars, defaultFalse) { //default to immediateRender:true unless otherwise set in toVars, fromVars or if defaultFalse is passed in as true
var ir = "immediateRender";
if (!(ir in toVars)) {
toVars[ir] = !(tl._paused || (fromVars && fromVars[ir] === false) || defaultFalse);
toVars[ir] = !((fromVars && fromVars[ir] === false) || defaultFalse);
}
return toVars;
},
//for distributing values across an array. Can accept a number, a function or (most commonly) a function which can contain the following properties: {base, amount, from, ease, grid, axis, length}. Returns a function that expects the following parameters: index, target, array. Recognizes the following
//for distributing values across an array. Can accept a number, a function or (most commonly) a function which can contain the following properties: {base, amount, from, ease, grid, axis, length, each}. Returns a function that expects the following parameters: index, target, array. Recognizes the following
_distribute = function(v) {
if (typeof(v) === "function") {
return v;
}
var vars = isNaN(v) ? v : {n:1, from:(v < 0) ? ((v = -v) && "end") : 0}, //n:1 is just to indicate v was a number; we leverage that later to set v according to the length we get. If a number is passed in, we treat it like the old stagger value where 0.1, for example, would mean that things would be distributed with 0.1 between each element in the array rather than a total "amount" that's chunked out among them all.
var vars = (typeof(v) === "object") ? v : {each:v}, //n:1 is just to indicate v was a number; we leverage that later to set v according to the length we get. If a number is passed in, we treat it like the old stagger value where 0.1, for example, would mean that things would be distributed with 0.1 between each element in the array rather than a total "amount" that's chunked out among them all.
ease = vars.ease,
from = vars.from || 0,
base = vars.base || 0,
@ -635,15 +634,16 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
}
distances.max = max - min;
distances.min = min;
distances.v = vars.n ? l * (v || 0) : vars.amount;
distances.v = l = vars.amount || (vars.each * (wrap > l ? l - 1 : !axis ? Math.max(wrap, l / wrap) : axis === "y" ? l / wrap : wrap)) || 0;
distances.b = (l < 0) ? base - l : base;
}
l = (distances[i] - distances.min) / distances.max;
return base + (ease ? ease.getRatio(l) : l) * distances.v;
return distances.b + (ease ? ease.getRatio(l) : l) * distances.v;
};
},
p = TimelineLite.prototype = new SimpleTimeline();
TimelineLite.version = "2.1.0";
TimelineLite.version = "2.1.3";
TimelineLite.distribute = _distribute;
p.constructor = TimelineLite;
p.kill()._gc = p._forcingPlayhead = p._hasPause = false;
@ -960,6 +960,29 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
if (prevTime !== self._time) { //if totalDuration() finds a child with a negative startTime and smoothChildTiming is true, things get shifted around internally so we need to adjust the time accordingly. For example, if a tween starts at -30 we must shift EVERYTHING forward 30 seconds and move this timeline's startTime backward by 30 seconds so that things align with the playhead (no jump).
time += self._time - prevTime;
}
if (self._hasPause && !self._forcingPlayhead && !suppressEvents) {
if (time > prevTime) {
tween = self._first;
while (tween && tween._startTime <= time && !pauseTween) {
if (!tween._duration) if (tween.data === "isPause" && !tween.ratio && !(tween._startTime === 0 && self._rawPrevTime === 0)) {
pauseTween = tween;
}
tween = tween._next;
}
} else {
tween = self._last;
while (tween && tween._startTime >= time && !pauseTween) {
if (!tween._duration) if (tween.data === "isPause" && tween._rawPrevTime > 0) {
pauseTween = tween;
}
tween = tween._prev;
}
}
if (pauseTween) {
self._time = self._totalTime = time = pauseTween._startTime;
pauseTime = self._startTime + (self._reversed ? self._duration - time : time) / self._timeScale;
}
}
if (time >= totalDur - _tinyNum && time >= 0) { //to work around occasional floating point math artifacts.
self._totalTime = self._time = totalDur;
if (!self._reversed) if (!self._hasPausedChild()) {
@ -1012,31 +1035,6 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
}
} else {
if (self._hasPause && !self._forcingPlayhead && !suppressEvents) {
if (time >= prevTime) {
tween = self._first;
while (tween && tween._startTime <= time && !pauseTween) {
if (!tween._duration) if (tween.data === "isPause" && !tween.ratio && !(tween._startTime === 0 && self._rawPrevTime === 0)) {
pauseTween = tween;
}
tween = tween._next;
}
} else {
tween = self._last;
while (tween && tween._startTime >= time && !pauseTween) {
if (!tween._duration) if (tween.data === "isPause" && tween._rawPrevTime > 0) {
pauseTween = tween;
}
tween = tween._prev;
}
}
if (pauseTween) {
self._time = self._totalTime = time = pauseTween._startTime;
pauseTime = self._startTime + (time / self._timeScale);
}
}
self._totalTime = self._time = self._rawPrevTime = time;
}
if ((self._time === prevTime || !self._first) && !force && !internalForce && !pauseTween) {

View File

@ -1,6 +1,6 @@
/*!
* VERSION: 2.1.0
* DATE: 2019-02-15
* VERSION: 2.1.3
* DATE: 2019-05-17
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
@ -963,7 +963,7 @@
p._firstPT = p._targets = p._overwrittenProps = p._startAt = null;
p._notifyPluginsOfEnabled = p._lazy = false;
TweenLite.version = "2.1.0";
TweenLite.version = "2.1.3";
TweenLite.defaultEase = p._ease = new Ease(null, null, 1, 1);
TweenLite.defaultOverwrite = "auto";
TweenLite.ticker = _ticker;

View File

@ -1,6 +1,6 @@
/*!
* VERSION: 2.1.0
* DATE: 2019-02-15
* VERSION: 2.1.3
* DATE: 2019-05-17
* UPDATES AND DOCS AT: http://greensock.com
*
* Includes all of the following: TweenLite, TweenMax, TimelineLite, TimelineMax, EasePack, CSSPlugin, RoundPropsPlugin, BezierPlugin, AttrPlugin, DirectionalRotationPlugin
@ -35,12 +35,12 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
}
delete vars.cycle;
},
//for distributing values across an array. Can accept a number, a function or (most commonly) a function which can contain the following properties: {base, amount, from, ease, grid, axis, length}. Returns a function that expects the following parameters: index, target, array. Recognizes the following
//for distributing values across an array. Can accept a number, a function or (most commonly) a function which can contain the following properties: {base, amount, from, ease, grid, axis, length, each}. Returns a function that expects the following parameters: index, target, array. Recognizes the following
_distribute = function(v) {
if (typeof(v) === "function") {
return v;
}
var vars = isNaN(v) ? v : {n:1, from:(v < 0) ? ((v = -v) && "end") : 0}, //n:1 is just to indicate v was a number; we leverage that later to set v according to the length we get. If a number is passed in, we treat it like the old stagger value where 0.1, for example, would mean that things would be distributed with 0.1 between each element in the array rather than a total "amount" that's chunked out among them all.
var vars = (typeof(v) === "object") ? v : {each:v}, //n:1 is just to indicate v was a number; we leverage that later to set v according to the length we get. If a number is passed in, we treat it like the old stagger value where 0.1, for example, would mean that things would be distributed with 0.1 between each element in the array rather than a total "amount" that's chunked out among them all.
ease = vars.ease,
from = vars.from || 0,
base = vars.base || 0,
@ -77,10 +77,11 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
}
distances.max = max - min;
distances.min = min;
distances.v = vars.n ? l * (v || 0) : vars.amount;
distances.v = l = vars.amount || (vars.each * (wrap > l ? l - 1 : !axis ? Math.max(wrap, l / wrap) : axis === "y" ? l / wrap : wrap)) || 0;
distances.b = (l < 0) ? base - l : base;
}
l = (distances[i] - distances.min) / distances.max;
return base + (ease ? ease.getRatio(l) : l) * distances.v;
return distances.b + (ease ? ease.getRatio(l) : l) * distances.v;
};
},
TweenMax = function(target, duration, vars) {
@ -101,7 +102,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
p = TweenMax.prototype = TweenLite.to({}, 0.1, {}),
_blankArray = [];
TweenMax.version = "2.1.0";
TweenMax.version = "2.1.3";
p.constructor = TweenMax;
p.kill()._gc = false;
TweenMax.killTweensOf = TweenMax.killDelayedCallsTo = TweenLite.killTweensOf;
@ -597,7 +598,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
//---- GETTERS / SETTERS ----------------------------------------------------------------------------------------------------------
p.progress = function(value, suppressEvents) {
return (!arguments.length) ? this._time / this.duration() : this.totalTime( this.duration() * ((this._yoyo && (this._cycle & 1) !== 0) ? 1 - value : value) + (this._cycle * (this._duration + this._repeatDelay)), suppressEvents);
return (!arguments.length) ? (this.duration() ? this._time / this._duration : this.ratio) : this.totalTime( this.duration() * ((this._yoyo && (this._cycle & 1) !== 0) ? 1 - value : value) + (this._cycle * (this._duration + this._repeatDelay)), suppressEvents);
};
p.totalProgress = function(value, suppressEvents) {
@ -613,7 +614,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
}
var duration = this._duration,
cycle = this._cycle,
cycleDur = cycle * (duration * this._repeatDelay);
cycleDur = cycle * (duration + this._repeatDelay);
if (value > duration) {
value = duration;
}
@ -737,16 +738,16 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
_defaultImmediateRender = function(tl, toVars, fromVars, defaultFalse) { //default to immediateRender:true unless otherwise set in toVars, fromVars or if defaultFalse is passed in as true
var ir = "immediateRender";
if (!(ir in toVars)) {
toVars[ir] = !(tl._paused || (fromVars && fromVars[ir] === false) || defaultFalse);
toVars[ir] = !((fromVars && fromVars[ir] === false) || defaultFalse);
}
return toVars;
},
//for distributing values across an array. Can accept a number, a function or (most commonly) a function which can contain the following properties: {base, amount, from, ease, grid, axis, length}. Returns a function that expects the following parameters: index, target, array. Recognizes the following
//for distributing values across an array. Can accept a number, a function or (most commonly) a function which can contain the following properties: {base, amount, from, ease, grid, axis, length, each}. Returns a function that expects the following parameters: index, target, array. Recognizes the following
_distribute = function(v) {
if (typeof(v) === "function") {
return v;
}
var vars = isNaN(v) ? v : {n:1, from:(v < 0) ? ((v = -v) && "end") : 0}, //n:1 is just to indicate v was a number; we leverage that later to set v according to the length we get. If a number is passed in, we treat it like the old stagger value where 0.1, for example, would mean that things would be distributed with 0.1 between each element in the array rather than a total "amount" that's chunked out among them all.
var vars = (typeof(v) === "object") ? v : {each:v}, //n:1 is just to indicate v was a number; we leverage that later to set v according to the length we get. If a number is passed in, we treat it like the old stagger value where 0.1, for example, would mean that things would be distributed with 0.1 between each element in the array rather than a total "amount" that's chunked out among them all.
ease = vars.ease,
from = vars.from || 0,
base = vars.base || 0,
@ -783,15 +784,16 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
}
distances.max = max - min;
distances.min = min;
distances.v = vars.n ? l * (v || 0) : vars.amount;
distances.v = l = vars.amount || (vars.each * (wrap > l ? l - 1 : !axis ? Math.max(wrap, l / wrap) : axis === "y" ? l / wrap : wrap)) || 0;
distances.b = (l < 0) ? base - l : base;
}
l = (distances[i] - distances.min) / distances.max;
return base + (ease ? ease.getRatio(l) : l) * distances.v;
return distances.b + (ease ? ease.getRatio(l) : l) * distances.v;
};
},
p = TimelineLite.prototype = new SimpleTimeline();
TimelineLite.version = "2.1.0";
TimelineLite.version = "2.1.3";
TimelineLite.distribute = _distribute;
p.constructor = TimelineLite;
p.kill()._gc = p._forcingPlayhead = p._hasPause = false;
@ -1108,6 +1110,29 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
if (prevTime !== self._time) { //if totalDuration() finds a child with a negative startTime and smoothChildTiming is true, things get shifted around internally so we need to adjust the time accordingly. For example, if a tween starts at -30 we must shift EVERYTHING forward 30 seconds and move this timeline's startTime backward by 30 seconds so that things align with the playhead (no jump).
time += self._time - prevTime;
}
if (self._hasPause && !self._forcingPlayhead && !suppressEvents) {
if (time > prevTime) {
tween = self._first;
while (tween && tween._startTime <= time && !pauseTween) {
if (!tween._duration) if (tween.data === "isPause" && !tween.ratio && !(tween._startTime === 0 && self._rawPrevTime === 0)) {
pauseTween = tween;
}
tween = tween._next;
}
} else {
tween = self._last;
while (tween && tween._startTime >= time && !pauseTween) {
if (!tween._duration) if (tween.data === "isPause" && tween._rawPrevTime > 0) {
pauseTween = tween;
}
tween = tween._prev;
}
}
if (pauseTween) {
self._time = self._totalTime = time = pauseTween._startTime;
pauseTime = self._startTime + (self._reversed ? self._duration - time : time) / self._timeScale;
}
}
if (time >= totalDur - _tinyNum && time >= 0) { //to work around occasional floating point math artifacts.
self._totalTime = self._time = totalDur;
if (!self._reversed) if (!self._hasPausedChild()) {
@ -1160,31 +1185,6 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
}
} else {
if (self._hasPause && !self._forcingPlayhead && !suppressEvents) {
if (time >= prevTime) {
tween = self._first;
while (tween && tween._startTime <= time && !pauseTween) {
if (!tween._duration) if (tween.data === "isPause" && !tween.ratio && !(tween._startTime === 0 && self._rawPrevTime === 0)) {
pauseTween = tween;
}
tween = tween._next;
}
} else {
tween = self._last;
while (tween && tween._startTime >= time && !pauseTween) {
if (!tween._duration) if (tween.data === "isPause" && tween._rawPrevTime > 0) {
pauseTween = tween;
}
tween = tween._prev;
}
}
if (pauseTween) {
self._time = self._totalTime = time = pauseTween._startTime;
pauseTime = self._startTime + (time / self._timeScale);
}
}
self._totalTime = self._time = self._rawPrevTime = time;
}
if ((self._time === prevTime || !self._first) && !force && !internalForce && !pauseTween) {
@ -1544,7 +1544,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
p.constructor = TimelineMax;
p.kill()._gc = false;
TimelineMax.version = "2.1.0";
TimelineMax.version = "2.1.3";
p.invalidate = function() {
this._yoyo = !!this.vars.yoyo;
@ -1720,35 +1720,34 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
}
}
}
}
if (self._hasPause && !self._forcingPlayhead && !suppressEvents) {
time = self._time;
if (time >= prevTime || (self._repeat && prevCycle !== self._cycle)) {
tween = self._first;
while (tween && tween._startTime <= time && !pauseTween) {
if (!tween._duration) if (tween.data === "isPause" && !tween.ratio && !(tween._startTime === 0 && self._rawPrevTime === 0)) {
pauseTween = tween;
}
tween = tween._next;
}
} else {
tween = self._last;
while (tween && tween._startTime >= time && !pauseTween) {
if (!tween._duration) if (tween.data === "isPause" && tween._rawPrevTime > 0) {
pauseTween = tween;
}
tween = tween._prev;
if (self._hasPause && !self._forcingPlayhead && !suppressEvents) {
time = self._time;
if (time > prevTime || (self._repeat && prevCycle !== self._cycle)) {
tween = self._first;
while (tween && tween._startTime <= time && !pauseTween) {
if (!tween._duration) if (tween.data === "isPause" && !tween.ratio && !(tween._startTime === 0 && self._rawPrevTime === 0)) {
pauseTween = tween;
}
tween = tween._next;
}
if (pauseTween) {
pauseTime = self._startTime + (pauseTween._startTime / self._timeScale);
if (pauseTween._startTime < dur) {
self._time = self._rawPrevTime = time = pauseTween._startTime;
self._totalTime = time + (self._cycle * (self._totalDuration + self._repeatDelay));
} else {
tween = self._last;
while (tween && tween._startTime >= time && !pauseTween) {
if (!tween._duration) if (tween.data === "isPause" && tween._rawPrevTime > 0) {
pauseTween = tween;
}
tween = tween._prev;
}
}
if (pauseTween) {
pauseTime = self._startTime + (self._reversed ? self._duration - pauseTween._startTime : pauseTween._startTime) / self._timeScale;
if (pauseTween._startTime < dur) {
self._time = self._rawPrevTime = time = pauseTween._startTime;
self._totalTime = time + (self._cycle * (self._totalDuration + self._repeatDelay));
}
}
}
if (self._cycle !== prevCycle) if (!self._locked) {
@ -1987,7 +1986,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
}
var duration = this._duration,
cycle = this._cycle,
cycleDur = cycle * (duration * this._repeatDelay);
cycleDur = cycle * (duration + this._repeatDelay);
if (value > duration) {
value = duration;
}
@ -2347,7 +2346,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
BezierPlugin = _gsScope._gsDefine.plugin({
propName: "bezier",
priority: -1,
version: "1.3.8",
version: "1.3.9",
API: 2,
global:true,
@ -2424,26 +2423,26 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
func = this._func,
target = this._target,
notStart = (v !== this._startRatio),
curIndex, inv, i, p, b, t, val, l, lengths, curSeg;
curIndex, inv, i, p, b, t, val, l, lengths, curSeg, v1;
if (!this._timeRes) {
curIndex = (v < 0) ? 0 : (v >= 1) ? segments - 1 : (segments * v) >> 0;
t = (v - (curIndex * (1 / segments))) * segments;
} else {
lengths = this._lengths;
curSeg = this._curSeg;
v *= this._length;
v1 = v * this._length;
i = this._li;
//find the appropriate segment (if the currently cached one isn't correct)
if (v > this._l2 && i < segments - 1) {
if (v1 > this._l2 && i < segments - 1) {
l = segments - 1;
while (i < l && (this._l2 = lengths[++i]) <= v) { }
while (i < l && (this._l2 = lengths[++i]) <= v1) { }
this._l1 = lengths[i-1];
this._li = i;
this._curSeg = curSeg = this._segments[i];
this._s2 = curSeg[(this._s1 = this._si = 0)];
} else if (v < this._l1 && i > 0) {
while (i > 0 && (this._l1 = lengths[--i]) >= v) { }
if (i === 0 && v < this._l1) {
} else if (v1 < this._l1 && i > 0) {
while (i > 0 && (this._l1 = lengths[--i]) >= v1) { }
if (i === 0 && v1 < this._l1) {
this._l1 = 0;
} else {
i++;
@ -2456,16 +2455,16 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
}
curIndex = i;
//now find the appropriate sub-segment (we split it into the number of pieces that was defined by "precision" and measured each one)
v -= this._l1;
v1 -= this._l1;
i = this._si;
if (v > this._s2 && i < curSeg.length - 1) {
if (v1 > this._s2 && i < curSeg.length - 1) {
l = curSeg.length - 1;
while (i < l && (this._s2 = curSeg[++i]) <= v) { }
while (i < l && (this._s2 = curSeg[++i]) <= v1) { }
this._s1 = curSeg[i-1];
this._si = i;
} else if (v < this._s1 && i > 0) {
while (i > 0 && (this._s1 = curSeg[--i]) >= v) { }
if (i === 0 && v < this._s1) {
} else if (v1 < this._s1 && i > 0) {
while (i > 0 && (this._s1 = curSeg[--i]) >= v1) { }
if (i === 0 && v1 < this._s1) {
this._s1 = 0;
} else {
i++;
@ -2473,7 +2472,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
this._s2 = curSeg[i];
this._si = i;
}
t = ((i + (v - this._s1) / (this._s2 - this._s1)) * this._prec) || 0;
t = (v === 1) ? 1 : ((i + (v1 - this._s1) / (this._s2 - this._s1)) * this._prec) || 0;
}
inv = 1 - t;
@ -2673,7 +2672,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
p = CSSPlugin.prototype = new TweenPlugin("css");
p.constructor = CSSPlugin;
CSSPlugin.version = "2.1.0";
CSSPlugin.version = "2.1.3";
CSSPlugin.API = 2;
CSSPlugin.defaultTransformPerspective = 0;
CSSPlugin.defaultSkewType = "compensated";
@ -2685,6 +2684,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
var _numExp = /(?:\-|\.|\b)(\d|\.|e\-)+/g,
_relNumExp = /(?:\d|\-\d|\.\d|\-\.\d|\+=\d|\-=\d|\+=.\d|\-=\.\d)+/g,
_valuesExp = /(?:\+=|\-=|\-|\b)[\d\-\.]+[a-zA-Z0-9]*(?:%|\b)/gi, //finds all the values that begin with numbers or += or -= and then a number. Includes suffixes. We use this to split complex values apart like "1px 5px 20px rgb(255,102,51)"
_valuesExpWithCommas = /(?:\+=|\-=|\-|\b)[\d\-\.]+[a-zA-Z0-9]*(?:%|\b),?/gi, //finds all the values that begin with numbers or += or -= and then a number. Includes suffixes. We use this to split complex values apart like "1px 5px 20px rgb(255,102,51)"
_NaNExp = /(?![+-]?\d*\.?\d+|[+-]|e[+-]\d+)[^0-9]/g, //also allows scientific notation and doesn't kill the leading -/+ in -= and +=
_suffixExp = /(?:\d|\-|\+|=|#|\.)*/g,
_opacityExp = /opacity *= *([^)]*)/i,
@ -2706,7 +2706,8 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
_dummyElement = {style:{}},
_doc = _gsScope.document || {createElement: function() {return _dummyElement;}},
_createElement = function(type, ns) {
return (ns && _doc.createElementNS) ? _doc.createElementNS(ns, type) : _doc.createElement(type);
var e = _doc.createElementNS ? _doc.createElementNS(ns || "http://www.w3.org/1999/xhtml", type) : _doc.createElement(type);
return e.style ? e : _doc.createElement(type); //some environments won't allow access to the element's style when created with a namespace in which case we default to the standard createElement() to work around the issue. Also note that when GSAP is embedded directly inside an SVG file, createElement() won't allow access to the style object in Firefox (see https://greensock.com/forums/topic/20215-problem-using-tweenmax-in-standalone-self-containing-svg-file-err-cannot-set-property-csstext-of-undefined/).
},
_tempDiv = _createElement("div"),
_tempImg = _createElement("img"),
@ -3286,14 +3287,14 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
}
return a.join(",");
}
vals = v.match(_valuesExp) || [];
vals = v.match(delim === "," ? _valuesExp : _valuesExpWithCommas) || [];
i = vals.length;
if (numVals > i--) {
while (++i < numVals) {
vals[i] = collapsible ? vals[(((i - 1) / 2) | 0)] : dVals[i];
}
}
return pfx + vals.join(delim) + sfx;
return ((pfx && v !== "none") ? v.substr(0, v.indexOf(vals[0])) || pfx : pfx) + vals.join(delim) + sfx; //note: prefix might be different, like for clipPath it could start with inset( or polygon(
};
return formatter;
},
@ -3876,7 +3877,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
//IE and Android stock don't support CSS transforms on SVG elements, so we must write them to the "transform" attribute. We populate this variable in the _parseTransform() method, and only if/when we come across an SVG element
var force = _ieVers || (/Android/i.test(_agent) && !_gsScope.chrome),
svg, rect, width;
if (_doc.createElementNS && !force) { //IE8 and earlier doesn't support SVG anyway
if (_doc.createElementNS && _docElement.appendChild && !force) { //IE8 and earlier doesn't support SVG anyway
svg = _createSVG("svg", _docElement);
rect = _createSVG("rect", svg, {width:100, height:50, x:100});
width = rect.getBoundingClientRect().width;
@ -3994,7 +3995,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
s = (s && s.length === 4) ? [s[0].substr(4), Number(s[2].substr(4)), Number(s[1].substr(4)), s[3].substr(4), (tm.x || 0), (tm.y || 0)].join(",") : "";
}
isDefault = (!s || s === "none" || s === "matrix(1, 0, 0, 1, 0, 0)");
if (_transformProp && isDefault && !e.offsetParent) { //note: if offsetParent is null, that means the element isn't in the normal document flow, like if it has display:none or one of its ancestors has display:none). Firefox returns null for getComputedStyle() if the element is in an iframe that has display:none. https://bugzilla.mozilla.org/show_bug.cgi?id=548397
if (_transformProp && isDefault && !e.offsetParent && e !== _docElement) { //note: if offsetParent is null, that means the element isn't in the normal document flow, like if it has display:none or one of its ancestors has display:none). Firefox returns null for getComputedStyle() if the element is in an iframe that has display:none. https://bugzilla.mozilla.org/show_bug.cgi?id=548397
//browsers don't report transforms accurately unless the element is in the DOM and has a display value that's not "none". Firefox and Microsoft browsers have a partial bug where they'll report transforms even if display:none BUT not any percentage-based values like translate(-50%, 8px) will be reported as if it's translate(0, 8px).
n = style.display;
style.display = "block";
@ -4756,7 +4757,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
}, allowFunc:true, prefix:true});
_registerComplexSpecialProp("boxShadow", {defaultValue:"0px 0px 0px 0px #999", prefix:true, color:true, multi:true, keyword:"inset"});
_registerComplexSpecialProp("clipPath", {defaultValue:"inset(0px)", prefix:true, multi:true, formatter:_getFormatter("inset(0px 0px 0px 0px)", false, true)});
_registerComplexSpecialProp("clipPath", {defaultValue:"inset(0%)", prefix:true, multi:true, formatter:_getFormatter("inset(0% 0% 0% 0%)", false, true)});
_registerComplexSpecialProp("borderRadius", {defaultValue:"0px", parser:function(t, e, p, cssp, pt, plugin) {
e = this.format(e);
@ -5010,7 +5011,9 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
difData = _cssDif(t, bs, _getAllStyles(t), vars, cnptLookup);
t.setAttribute("class", b);
pt.data = difData.firstMPT;
t.style.cssText = cssText; //we recorded cssText before we swapped classes and ran _getAllStyles() because in cases when a className tween is overwritten, we remove all the related tweening properties from that class change (otherwise class-specific stuff can't override properties we've directly set on the target's style object due to specificity).
if (t.style.cssText !== cssText) { //only apply if things change. Otherwise, in cases like a background-image that's pulled dynamically, it could cause a refresh. See https://greensock.com/forums/topic/20368-possible-gsap-bug-switching-classnames-in-chrome/.
t.style.cssText = cssText; //we recorded cssText before we swapped classes and ran _getAllStyles() because in cases when a className tween is overwritten, we remove all the related tweening properties from that class change (otherwise class-specific stuff can't override properties we've directly set on the target's style object due to specificity).
}
pt = pt.xfirst = cssp.parse(t, difData.difs, pt, plugin); //we record the CSSPropTween as the xfirst so that we can handle overwriting propertly (if "className" gets overwritten, we must kill all the properties associated with the className part of the tween, so we can loop through from xfirst to the pt itself)
return pt;
}});
@ -7120,7 +7123,7 @@ if (_gsScope._gsDefine) { _gsScope._gsQueue.pop()(); } //necessary in case Tween
p._firstPT = p._targets = p._overwrittenProps = p._startAt = null;
p._notifyPluginsOfEnabled = p._lazy = false;
TweenLite.version = "2.1.0";
TweenLite.version = "2.1.3";
TweenLite.defaultEase = p._ease = new Ease(null, null, 1, 1);
TweenLite.defaultOverwrite = "auto";
TweenLite.ticker = _ticker;

View File

@ -1,6 +1,6 @@
/*!
* VERSION: 1.3.8
* DATE: 2018-02-15
* VERSION: 1.3.9
* DATE: 2019-05-17
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
@ -315,7 +315,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
BezierPlugin = _gsScope._gsDefine.plugin({
propName: "bezier",
priority: -1,
version: "1.3.8",
version: "1.3.9",
API: 2,
global:true,
@ -392,26 +392,26 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
func = this._func,
target = this._target,
notStart = (v !== this._startRatio),
curIndex, inv, i, p, b, t, val, l, lengths, curSeg;
curIndex, inv, i, p, b, t, val, l, lengths, curSeg, v1;
if (!this._timeRes) {
curIndex = (v < 0) ? 0 : (v >= 1) ? segments - 1 : (segments * v) >> 0;
t = (v - (curIndex * (1 / segments))) * segments;
} else {
lengths = this._lengths;
curSeg = this._curSeg;
v *= this._length;
v1 = v * this._length;
i = this._li;
//find the appropriate segment (if the currently cached one isn't correct)
if (v > this._l2 && i < segments - 1) {
if (v1 > this._l2 && i < segments - 1) {
l = segments - 1;
while (i < l && (this._l2 = lengths[++i]) <= v) { }
while (i < l && (this._l2 = lengths[++i]) <= v1) { }
this._l1 = lengths[i-1];
this._li = i;
this._curSeg = curSeg = this._segments[i];
this._s2 = curSeg[(this._s1 = this._si = 0)];
} else if (v < this._l1 && i > 0) {
while (i > 0 && (this._l1 = lengths[--i]) >= v) { }
if (i === 0 && v < this._l1) {
} else if (v1 < this._l1 && i > 0) {
while (i > 0 && (this._l1 = lengths[--i]) >= v1) { }
if (i === 0 && v1 < this._l1) {
this._l1 = 0;
} else {
i++;
@ -424,16 +424,16 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
}
curIndex = i;
//now find the appropriate sub-segment (we split it into the number of pieces that was defined by "precision" and measured each one)
v -= this._l1;
v1 -= this._l1;
i = this._si;
if (v > this._s2 && i < curSeg.length - 1) {
if (v1 > this._s2 && i < curSeg.length - 1) {
l = curSeg.length - 1;
while (i < l && (this._s2 = curSeg[++i]) <= v) { }
while (i < l && (this._s2 = curSeg[++i]) <= v1) { }
this._s1 = curSeg[i-1];
this._si = i;
} else if (v < this._s1 && i > 0) {
while (i > 0 && (this._s1 = curSeg[--i]) >= v) { }
if (i === 0 && v < this._s1) {
} else if (v1 < this._s1 && i > 0) {
while (i > 0 && (this._s1 = curSeg[--i]) >= v1) { }
if (i === 0 && v1 < this._s1) {
this._s1 = 0;
} else {
i++;
@ -441,7 +441,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
this._s2 = curSeg[i];
this._si = i;
}
t = ((i + (v - this._s1) / (this._s2 - this._s1)) * this._prec) || 0;
t = (v === 1) ? 1 : ((i + (v1 - this._s1) / (this._s2 - this._s1)) * this._prec) || 0;
}
inv = 1 - t;

View File

@ -1,6 +1,6 @@
/*!
* VERSION: 2.1.0
* DATE: 2019-02-15
* VERSION: 2.1.3
* DATE: 2019-05-17
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
@ -32,7 +32,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
p = CSSPlugin.prototype = new TweenPlugin("css");
p.constructor = CSSPlugin;
CSSPlugin.version = "2.1.0";
CSSPlugin.version = "2.1.3";
CSSPlugin.API = 2;
CSSPlugin.defaultTransformPerspective = 0;
CSSPlugin.defaultSkewType = "compensated";
@ -44,6 +44,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
var _numExp = /(?:\-|\.|\b)(\d|\.|e\-)+/g,
_relNumExp = /(?:\d|\-\d|\.\d|\-\.\d|\+=\d|\-=\d|\+=.\d|\-=\.\d)+/g,
_valuesExp = /(?:\+=|\-=|\-|\b)[\d\-\.]+[a-zA-Z0-9]*(?:%|\b)/gi, //finds all the values that begin with numbers or += or -= and then a number. Includes suffixes. We use this to split complex values apart like "1px 5px 20px rgb(255,102,51)"
_valuesExpWithCommas = /(?:\+=|\-=|\-|\b)[\d\-\.]+[a-zA-Z0-9]*(?:%|\b),?/gi, //finds all the values that begin with numbers or += or -= and then a number. Includes suffixes. We use this to split complex values apart like "1px 5px 20px rgb(255,102,51)"
_NaNExp = /(?![+-]?\d*\.?\d+|[+-]|e[+-]\d+)[^0-9]/g, //also allows scientific notation and doesn't kill the leading -/+ in -= and +=
_suffixExp = /(?:\d|\-|\+|=|#|\.)*/g,
_opacityExp = /opacity *= *([^)]*)/i,
@ -65,7 +66,8 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
_dummyElement = {style:{}},
_doc = _gsScope.document || {createElement: function() {return _dummyElement;}},
_createElement = function(type, ns) {
return (ns && _doc.createElementNS) ? _doc.createElementNS(ns, type) : _doc.createElement(type);
var e = _doc.createElementNS ? _doc.createElementNS(ns || "http://www.w3.org/1999/xhtml", type) : _doc.createElement(type);
return e.style ? e : _doc.createElement(type); //some environments won't allow access to the element's style when created with a namespace in which case we default to the standard createElement() to work around the issue. Also note that when GSAP is embedded directly inside an SVG file, createElement() won't allow access to the style object in Firefox (see https://greensock.com/forums/topic/20215-problem-using-tweenmax-in-standalone-self-containing-svg-file-err-cannot-set-property-csstext-of-undefined/).
},
_tempDiv = _createElement("div"),
_tempImg = _createElement("img"),
@ -645,14 +647,14 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
}
return a.join(",");
}
vals = v.match(_valuesExp) || [];
vals = v.match(delim === "," ? _valuesExp : _valuesExpWithCommas) || [];
i = vals.length;
if (numVals > i--) {
while (++i < numVals) {
vals[i] = collapsible ? vals[(((i - 1) / 2) | 0)] : dVals[i];
}
}
return pfx + vals.join(delim) + sfx;
return ((pfx && v !== "none") ? v.substr(0, v.indexOf(vals[0])) || pfx : pfx) + vals.join(delim) + sfx; //note: prefix might be different, like for clipPath it could start with inset( or polygon(
};
return formatter;
},
@ -1235,7 +1237,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
//IE and Android stock don't support CSS transforms on SVG elements, so we must write them to the "transform" attribute. We populate this variable in the _parseTransform() method, and only if/when we come across an SVG element
var force = _ieVers || (/Android/i.test(_agent) && !_gsScope.chrome),
svg, rect, width;
if (_doc.createElementNS && !force) { //IE8 and earlier doesn't support SVG anyway
if (_doc.createElementNS && _docElement.appendChild && !force) { //IE8 and earlier doesn't support SVG anyway
svg = _createSVG("svg", _docElement);
rect = _createSVG("rect", svg, {width:100, height:50, x:100});
width = rect.getBoundingClientRect().width;
@ -1353,7 +1355,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
s = (s && s.length === 4) ? [s[0].substr(4), Number(s[2].substr(4)), Number(s[1].substr(4)), s[3].substr(4), (tm.x || 0), (tm.y || 0)].join(",") : "";
}
isDefault = (!s || s === "none" || s === "matrix(1, 0, 0, 1, 0, 0)");
if (_transformProp && isDefault && !e.offsetParent) { //note: if offsetParent is null, that means the element isn't in the normal document flow, like if it has display:none or one of its ancestors has display:none). Firefox returns null for getComputedStyle() if the element is in an iframe that has display:none. https://bugzilla.mozilla.org/show_bug.cgi?id=548397
if (_transformProp && isDefault && !e.offsetParent && e !== _docElement) { //note: if offsetParent is null, that means the element isn't in the normal document flow, like if it has display:none or one of its ancestors has display:none). Firefox returns null for getComputedStyle() if the element is in an iframe that has display:none. https://bugzilla.mozilla.org/show_bug.cgi?id=548397
//browsers don't report transforms accurately unless the element is in the DOM and has a display value that's not "none". Firefox and Microsoft browsers have a partial bug where they'll report transforms even if display:none BUT not any percentage-based values like translate(-50%, 8px) will be reported as if it's translate(0, 8px).
n = style.display;
style.display = "block";
@ -2115,7 +2117,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
}, allowFunc:true, prefix:true});
_registerComplexSpecialProp("boxShadow", {defaultValue:"0px 0px 0px 0px #999", prefix:true, color:true, multi:true, keyword:"inset"});
_registerComplexSpecialProp("clipPath", {defaultValue:"inset(0px)", prefix:true, multi:true, formatter:_getFormatter("inset(0px 0px 0px 0px)", false, true)});
_registerComplexSpecialProp("clipPath", {defaultValue:"inset(0%)", prefix:true, multi:true, formatter:_getFormatter("inset(0% 0% 0% 0%)", false, true)});
_registerComplexSpecialProp("borderRadius", {defaultValue:"0px", parser:function(t, e, p, cssp, pt, plugin) {
e = this.format(e);
@ -2369,7 +2371,9 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
difData = _cssDif(t, bs, _getAllStyles(t), vars, cnptLookup);
t.setAttribute("class", b);
pt.data = difData.firstMPT;
t.style.cssText = cssText; //we recorded cssText before we swapped classes and ran _getAllStyles() because in cases when a className tween is overwritten, we remove all the related tweening properties from that class change (otherwise class-specific stuff can't override properties we've directly set on the target's style object due to specificity).
if (t.style.cssText !== cssText) { //only apply if things change. Otherwise, in cases like a background-image that's pulled dynamically, it could cause a refresh. See https://greensock.com/forums/topic/20368-possible-gsap-bug-switching-classnames-in-chrome/.
t.style.cssText = cssText; //we recorded cssText before we swapped classes and ran _getAllStyles() because in cases when a className tween is overwritten, we remove all the related tweening properties from that class change (otherwise class-specific stuff can't override properties we've directly set on the target's style object due to specificity).
}
pt = pt.xfirst = cssp.parse(t, difData.difs, pt, plugin); //we record the CSSPropTween as the xfirst so that we can handle overwriting propertly (if "className" gets overwritten, we must kill all the properties associated with the className part of the tween, so we can loop through from xfirst to the pt itself)
return pt;
}});

View File

@ -1,6 +1,6 @@
/*!
* VERSION: 0.6.6
* DATE: 2018-02-15
* VERSION: 0.6.8
* DATE: 2018-02-22
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
@ -28,7 +28,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
p._propName = "cssRule";
p.constructor = CSSRulePlugin;
CSSRulePlugin.version = "0.6.6";
CSSRulePlugin.version = "0.6.8";
CSSRulePlugin.API = 2;
/**
@ -94,7 +94,12 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
// @private gets called every time the tween updates, passing the new ratio (typically a value between 0 and 1, but not always (for example, if an Elastic.easeOut is used, the value can jump above 1 mid-tween). It will always start and 0 and end at 1.
p.setRatio = function(v) {
_superSetRatio.call(this, v);
this._ss.cssText = this._proxy.cssText;
var proxy = this._proxy,
ss = this._ss,
i = proxy.length;
while (--i > -1) {
ss[proxy[i]] = proxy[proxy[i]];
}
};

View File

@ -1,6 +1,6 @@
/*!
* VERSION: 0.9.0
* DATE: 2019-02-07
* VERSION: 0.9.1
* DATE: 2019-02-21
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
@ -906,12 +906,12 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
propName: "morphSVG",
API: 2,
global: true,
version: "0.9.0",
version: "0.9.1",
overwriteProps: ["morphSVG"],
//called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
init: function(target, value, tween, index) {
var cs = window.getComputedStyle(target),
var cs = target.nodeType ? window.getComputedStyle(target) : {},
fill = cs.fill + "",
fillSafe = !(fill === "none" || (fill.match(_numbersExp) || [])[3] === "0" || cs.fillRule === "evenodd"),
origins = (value.origin || "50 50").split(","),

View File

@ -1,6 +1,6 @@
/*!
* VERSION: 0.2.1
* DATE: 2018-02-15
* VERSION: 0.3.0
* DATE: 2019-05-13
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
@ -389,13 +389,14 @@ var _gsScope = (typeof module !== "undefined" && module.exports && typeof global
priority: 0,
API: 2,
global: true,
version: "0.2.1",
version: "0.3.0",
init: function (target, values, tween, index) {
if (!target instanceof _gsScope.PIXI.DisplayObject) {
return false;
}
var context, axis, value, colorMatrix, filter, p, padding, colorSetter, i, data, pt;
var isV4 = _gsScope.PIXI.VERSION.charAt(0) === "4",
context, axis, value, colorMatrix, filter, p, padding, colorSetter, i, data, pt;
for (p in values) {
context = _contexts[p];
value = values[p];
@ -431,12 +432,12 @@ var _gsScope = (typeof module !== "undefined" && module.exports && typeof global
colorSetter = _buildColorSetter(tween, this);
}
if ((p === "lineColor" || p === "fillColor") && target instanceof _gsScope.PIXI.Graphics) {
data = target.graphicsData;
data = (target.geometry || target).graphicsData; //"geometry" was introduced in PIXI version 5
i = data.length;
while (--i > -1) {
_addColorTween(data[i], p, value, colorSetter, this);
_addColorTween(isV4 ? data[i] : data[i][p.substr(0, 4) + "Style"], isV4 ? p : "color", value, colorSetter, this);
}
colorSetter.graphics = target;
colorSetter.graphics = target.geometry || target;
} else {
_addColorTween(target, p, value, colorSetter, this);
}
@ -460,6 +461,9 @@ var _gsScope = (typeof module !== "undefined" && module.exports && typeof global
PixiPlugin.parseColor = _parseColor;
PixiPlugin.formatColors = _formatColors;
PixiPlugin.colorStringFilter = _colorStringFilter;
PixiPlugin.registerPIXI = function(PIXI) {
_gsScope.PIXI = PIXI;
};
}); if (_gsScope._gsDefine) { _gsScope._gsQueue.pop()(); }

View File

@ -1,6 +1,6 @@
/*!
* VERSION: 0.17.0
* DATE: 2019-02-12
* VERSION: 0.17.1
* DATE: 2019-02-28
* UPDATES AND DOCS AT: http://greensock.com
*
* Requires TweenLite and CSSPlugin version 1.17.0 or later (TweenMax contains both TweenLite and CSSPlugin). ThrowPropsPlugin is required for momentum-based continuation of movement after the mouse/touch is released (ThrowPropsPlugin is a membership benefit of Club GreenSock - http://greensock.com/club/).
@ -1696,7 +1696,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
if (e && e.target) {
_addListener(e.target, "mouseup", onRelease); //we also have to listen directly on the element because some browsers don't bubble up the event to the _doc on elements with contentEditable="true"
}
isClicking = (isClickable.call(self, e.target) && vars.dragClickables !== false && !force);
isClicking = (isClickable.call(self, e.target) && vars.dragClickables === false && !force);
if (isClicking) {
_addListener(e.target, "change", onRelease); //in some browsers, when you mousedown on a <select> element, no mouseup gets dispatched! So we listen for a "change" event instead.
_dispatchEvent(self, "pressInit", "onPressInit");
@ -2399,7 +2399,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
p.constructor = Draggable;
p.pointerX = p.pointerY = p.startX = p.startY = p.deltaX = p.deltaY = 0;
p.isDragging = p.isPressed = false;
Draggable.version = "0.17.0";
Draggable.version = "0.17.1";
Draggable.zIndex = 1000;
_addListener(_doc, "touchcancel", function() {

View File

@ -1,6 +1,6 @@
/*!
* VERSION: 0.1.9
* DATE: 2019-02-07
* VERSION: 0.1.11
* DATE: 2019-05-16
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
@ -717,7 +717,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
record("out", outProgress);
}
startTime = 0;
maxDuration = Math.min(1000, vars.maxDuration || 1000, _getClippedDuration(selectedAnimation));
maxDuration = vars.maxDuration || Math.min(1000, _getClippedDuration(selectedAnimation));
if (selectedAnimation === _recordedRoot || vars.globalSync !== false) {
_merge();
linkedAnimation = _rootTween;
@ -1102,7 +1102,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
GSDevTools.version = "0.1.9";
GSDevTools.version = "0.1.11";
GSDevTools.logOverwrites = false;
GSDevTools.globalRecordingTime = 2;
@ -2986,7 +2986,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
if (e && e.target) {
_addListener(e.target, "mouseup", onRelease); //we also have to listen directly on the element because some browsers don't bubble up the event to the _doc on elements with contentEditable="true"
}
isClicking = (isClickable.call(self, e.target) && vars.dragClickables !== false && !force);
isClicking = (isClickable.call(self, e.target) && vars.dragClickables === false && !force);
if (isClicking) {
_addListener(e.target, "change", onRelease); //in some browsers, when you mousedown on a <select> element, no mouseup gets dispatched! So we listen for a "change" event instead.
_dispatchEvent(self, "pressInit", "onPressInit");
@ -3689,7 +3689,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
p.constructor = Draggable;
p.pointerX = p.pointerY = p.startX = p.startY = p.deltaX = p.deltaY = 0;
p.isDragging = p.isPressed = false;
Draggable.version = "0.17.0";
Draggable.version = "0.17.1";
Draggable.zIndex = 1000;
_addListener(_doc, "touchcancel", function() {

37
lib/3rdparty/hyphenation/de.js vendored Normal file

File diff suppressed because one or more lines are too long

32
lib/3rdparty/hyphenation/en-gb.js vendored Normal file

File diff suppressed because one or more lines are too long

35
lib/3rdparty/hyphenation/en-us.js vendored Normal file

File diff suppressed because one or more lines are too long

40
lib/3rdparty/hyphenation/fr.js vendored Normal file
View File

@ -0,0 +1,40 @@
(function () {
var module = {
exports: null
};
// The french hyphenation patterns are retrieved from
// http://tug_org/svn/texhyphen/trunk/collaboration/repository/hyphenator/
module.exports = {
'id': 'fr',
'leftmin': 2,
'rightmin': 3,
'patterns': {
2 : "1ç1j1q",
3 : "1gèâ41zu1zo1zi1zè1zé1ze1zay4_y41wu1wo1wi1we1wa1vy1vû1vu1vô1vo1vî1vi1vê1vè1vé1ve1vâ1vaû4_û4u4_u41ba1bâ1ty1be1bé1bè1bê1tû1tu1tô1bi1bî1to1tî1ti1tê1tè1té1te1tà1tâ1ta1bo1bô1sy1sû1su1sœ1bu1bû1by221ca1câ1sô1ce1cé1cè1cê1so1sî1si1sê1sè1sé1se1sâ1sa1ry1rû1ru1rô1ro1rî1ri1rê1rè1ré1re1râ1raa41py1pû1pu1pô1po1pî1pi1pê1pè1pé1pe1pâ1pa_ô41ci1cîô4o4_o41nyn1x1nû1nu1nœ1nô1no1nî1ni1nê1nè1né1ne1nâ1co1cô1na1my1mû1mu1mœ1mô1mo1mî1mi1cœ1mê1mè1mé1me1mâ1ma1ly1lû1lu1lô1lo1lî1li1lê1lè1cu1cû1cy1lé1d1da1dâ1le1là1de1dé1dè1dê1lâ1la1ky1kû1ku1kô1ko1kî1ki1kê1kè1ké1ke1kâ1ka2jk_a4î4_î4i4_i41hy1hû1hu1hô1ho1hî1hi1hê1hè1hé1he1hâ1ha1gy1gû1gu1gô1go1gî1gi1gê_â41gé1ge1gâ1ga1fy1di1dî1fû1fu1fô1foe41fî1fi1fê1fè1do1dô1fé1fe1fâ1faè41du1dû1dy_è4é4_é4ê4_ê4_e41zy",
4 : "1f2lab2h2ckg2ckp2cksd1s22ckb4ck_1c2k2chw4ze_4ne_2ckt1c2lad2hm1s22cht2chsch2r2chp4pe_1t2r1p2h_ph44ph_ph2l2phnph2r2phs1d2r2pht2chn4fe_2chm1p2l1p2r4me_1w2rch2l2chg1c2r2chb4ch_1f2r4le_4re_4de_f1s21k2r4we_1r2h_kh44kh_1k2h4ke_1c2h_ch44ge_4je_4se_1v2r_sh41s2h4ve_4sh_2shm2shr2shs4ce_il2l1b2r4be_1b2l4he_4te__th41t2h4th_g1s21g2r2thl1g2l2thm2thnth2r1g2n2ths2ckf",
5 : "2ck3h4rhe_4kes_4wes_4res_4cke_éd2hi4vre_4jes_4tre_4zes_4ges_4des_i1oxy4gle_d1d2h_cul44gne_4fre_o1d2l_sch44nes_4les_4gre_1s2ch_réu24sch_4the_1g2hy4gue_2schs4cle_1g2ho1g2hi1g2he4ses_4tes_1g2ha4ves_4she_4che_4cre_4ces_t1t2l4hes_l1s2t4bes_4ble__con4xil3lco1ap4que_vil3l4fle_co1arco1exco1enco1auco1axco1ef4pes_co1é2per3h4mes__pe4r4bre_4pre_4phe_1p2né4ple__dé2smil3llil3lhil3l4dre_cil3lgil3l4fes_",
6 : "in1o2rcil4l4phre_4dres_l3lioni1algi2fent_émil4l4phle_rmil4l4ples_4phes_1p2neuextra14pres_y1asthpé2nul2xent__mé2sa2pent_y1algi4chre_1m2nès4bres_1p2tèr1p2tér4chle_en1o24fles_oxy1a2avil4l_en1o24ques_uvil4lco1a2d4bles__in1a2in1a21s2por_cons4_bi1u2as2ta_in1e2in1e2_in1é2in1é21s2lov1s2lavco1acq2cent__as2ta_co1o24ches_hémi1é_in2erin2er2s3homo1ioni_in1i2in1i22went_4shes__ré1a2_ré1é2_ré1e2_ré2el_in1o2ucil4lco1accu2s3tr_ré2er_ré2èr4cles_2vent__ré1i22sent_2tent_2gent__ré1o24gues__re1s24sche_4thes_en1a2e2s3ch4gres_1s2cop2lent__en1a22nent__in1u2in1u24gnes_4cres_wa2g3n4fres_4tres_4gles_1octet_dé1o2_dé1io4thre__bi1au2jent__dé1a22zent_4vres_2dent_4ckes_4rhes__dy2s3sub1s22kent_2rent_2bent_3d2hal",
7 : "a2g3nos3d2houdé3rent__dé3s2t_dé3s2pé3dent_2r3heur2r3hydri1s2tat2frent_io1a2ctla2w3rein2u3l_in2u3l2crent_in2uit_in2uit1s2caph1s2clér_ré2ussi2s3ché_re2s3t_re2s3s4sches_é3cent__seu2lein2ond_in2ondin2i3t_in2i3tin2i3q_ré2aux_in2i3q2shent__di1alduni1a2xin2ept2flent__in2eptuni1o2v2brent_co2nurb2chent_2quent_1s2perm1s2phèr_ma2c3kuevil4l1s2phér1s2piel1s2tein1s2tigm4chles_1s2tock1s2tyle1p2sych_pro1é2_ma2r1x_stil3lpusil3libril3lcyril3l_pré1s2thril3l_mé3san_pré1u2_mé2s1i_pré1o2_pré1i2piril3lpupil3lâ2ment__pré1e2_pré1é2_pré2au_pré1a22prent_2vrent_supero2_di1e2npoly1u2è2ment_poly1s2poly1o2poly1i2poly1è2poly1é2poly1e2poly1a2supe4r1capil3l2plent_armil5lsemil4lmil4letvacil4l_di2s3h3ph2tis2dlent_a2s3tro4phres_l2ment_i1è2drei1arthr2drent_4phles_supers2ô2ment_extra2i2phent_su3r2ah_su2r3hextra2chypo1u21alcool_per1u2_per1o2_per1i2_per1é2hypo1s2_per1a2hypo1o2hypo1i2hypo1é2_pen2tahypo1e2hypo1a2y1s2tome2s3cophyperu2hype4r1hypers2hypero21m2némohyperi21m2nési4chres_a1è2drehyperé2hypere2hypera2oua1ou_oua1ouo1s2tomo1s2timo1s2tato1s2tasomni1s2tung2s3_dé3s2c2blent__bio1a2télé1e2télé1i22clent_télé1s22guent_1é2nerg2grent_2trent__dé2s1œ2t3heuro1è2dre2gnent_2glent_4thres__bi1a2t1é2drie_bi1a2c_i2g3nin3s2at_i2g3ni2ckent__i2g3néab3réai2g3né_ab3réa_per1e2",
8 : "_ma2l1ap_dy2s1u2_dy2s1o2_dy2s1i2n3s2ats__dy2s1a2distil3l1é2lectrinstil3l1s2trophe2n1i2vro2b3long1s2tomos_ae3s4chae3s4ch_eu2r1a2ombud2s3eu2r1a2_mono1s2_mono1u2o1s2téro_mono1o2eu1s2tato1s2tradfritil3la2l1algi_mono1i2_mono1é2_ovi1s2covi1s2c_mono1e2_mono1a2co1assocpaléo1é2boutil3l1s2piros_ré2i3fi_pa2n1ischevil4l1s2patiaca3ou3t2_di1a2cé_para1s2_pa2r3héco1assur_su2b1é2tu2ment_su2ment__su2b1in_su2b3lupapil3lire3pent_inte4r3_su2b1urab3sent__su2b1a2di2s3cophu2ment_fu2ment__intera2au2ment_as2ment_or2ment_intera2_intere2pé1r2é2q_péri1os_péri1s2ja3cent__anti1a2_péri1u2anti1a2er2ment__anti1e2ac3cent_ar2ment_to2ment_intere2ré3gent_papil3leom2ment_anti1e2photo1s2_anti1é2_interé2anti1é2_anti1s2anti1s23ph2taléinteré2ri2ment__interi2interi2mi2ment_apo2s3tri2s3chio_pluri1ai2s3chia_intero2intero2_inte4r3po1astre_interu2interu2_inters2ai2ment_inters2papil3la_tri1o2n_su2r1a2_pon2tet_pos2t3h_dés2a3mes3cent__pos2t3r_post1s2_tri1a2tta2ment__tri1a2nra2ment_is3cent__su2r1e2_tri1a2cfa2ment_da2ment__su3r2et_su2r1é2_mé2s1es_mé2g1oh_su2r1of_su2r1ox_re3s4ty_re3s4tu_ma2l1oca2g3nat_dé2s1é2_ma2l1entachy1a2_pud1d2ltchin3t2_re3s4trtran2s3p_bi2s1a2tran2s3hhémo1p2té3quent__a2g3nat_dé2s1i2télé1o2bo2g3nosiradio1a2télé1o2ppu2g3nacru3lent__sta2g3nre3lent__ré2a3le_di1a2mi",
9 : "_ré2a3lit_dé3s2o3lthermo1s2_dé3s2ist_dé3s2i3rmit3tent_éni3tent__do3lent__ré2a3lisopu3lent__pa3tent__re2s3cap_la3tent__co2o3lie_re2s3cou_re2s3cri_ma2g3num_re2s3pir_dé3s2i3dco2g3nititran2s1a2tran2s1o2_dé3s2exu_re3s4tab_re3s4tag_dé3s2ert_re3s4tat_re3s4tén_re3s4tér_re3s4tim_re3s4tip_re3s4toc_re3s4toptran2s1u2_no2n1obs_ma2l1a2v_ma2l1int_prou3d2hpro2s3tativa3lent__ta3lent__rétro1a2_pro1s2cé_ma2l1o2dcci3dent__pa3rent__su2r1int_su2r1inf_su2r1i2mtor3rent_cur3rent__mé2s1u2stri3dent__dé3s2orm_su3r2ell_ar3dent__su3r2eaupru3dent__pré2a3lacla2ment__su3r2a3t_pos2t1o2_pos2t1inqua2ment_ter3gent_ser3gent_rai3ment_abî2ment_éci2ment_ar3gent__ar3gent_rin3gent_tan3gent_éli2ment_ani2ment_apo2s3ta_apo2s3tavélo1s2kivol2t1amp_dé3s2orp_dé2s1u2n_péri2s3ssesqui1a2ana3s4trfir2ment_écu2ment_ser3pent_pré3sent_ar3pent__ar3pent_in1s2tab_in1s2tabin2o3cul_in2o3culplu2ment_bou2ment_in2exora_in2exora_su2b3linbru2ment__su3b2é3r_milli1amin2effab_in2effabin2augur_di1a2cid_in2augur_pa2n1optin2a3nit_in2a3nit1informat_ana3s4trvanil3lis_di1a2tom_su3b2altvanil3linstéréo1s2_pa2n1a2fo1s2tratuépi2s3cop_ci2s1alp1s2tructu1é2lément1é2driquepapil3lomllu2ment_",
10 : "1s2tandardimmi3nent__émi3nent_imma3nent_réma3nent_épi3s4cope_in2i3mitiin2i3miti_res3sent_moye2n1â2gréti3cent__dé3s2a3crmon2t3réalinno3cent__mono1ï2dé_pa2n1a2méimpu3dent__pa2n1a2ra_amino1a2camino1a2c_pa2n1o2phinci3dent__ser3ment_appa3rent_déca3dent__dacryo1a2_dé3s2astr_re4s5trin_dé3s2é3gr_péri2s3ta_sar3ment__dé3s2oufr_re3s4tandchro2ment__com3ment__re2s3quil_re2s3pons_gem2ment__re2s3pect_re2s3ciso_dé3s2i3gn_dé3s2i3ligram2ment__dé3s2invo_re2s3cisitran3s2actanti2enneindo3lent__sou3vent_indi3gent_dili3gent_flam2ment_impo3tent_inso3lent_esti2ment_on3guent__on3guent_inti2ment__dé3s2o3défécu3lent_veni2ment_reli2ment_vidi2ment_chlo2r3é2tpu2g3nablechlo2r3a2cryth2ment_o2g3nomonicarê2ment__méta1s2ta_ma2l1aisé_macro1s2célo3quent_tran3s2ats_anti2enne",
11 : "_contre1s2cperti3nent_conti3nent__ma2l1a2dro_in2é3lucta_psycho1a2n_dé3s2o3pilin2é3luctaperma3nent__in2é3narratesta3ment__su2b3liminrésur3gent_in2é3narraimmis4cent__pro2g3nathchien3dent_sporu4lent_dissi3dent_corpu3lent_archi1é2pissubli2ment_indul3gent_confi3dent__syn2g3nathtrucu3lent_détri3ment_nutri3ment_succu3lent_turbu3lent__pa2r1a2che_pa2r1a2chèfichu3ment_entre3gent_conni3vent_mécon3tent_compé3tent__re4s5trict_dé3s2i3nen_re2s3plend1a2nesthésislalo2ment__dé3s2ensib_re4s5trein_phalan3s2tabsti3nent_",
12 : "polyva3lent_équiva4lent_monova3lent_amalga2ment_omnipo3tent__ma2l1a2dreséquipo3tent__dé3s2a3tellproémi3nent_contin3gent_munifi3cent__ma2g3nicideo1s2trictionsurémi3nent_préémi3nent__bai2se3main",
13 : "acquies4cent_intelli3gent_tempéra3ment_transpa3rent__ma2g3nificatantifer3ment_",
14 : "privatdo3cent_diaphrag2ment_privatdo3zent_ventripo3tent__contre3maître",
15 : "grandilo3quent_",
16 : "_chè2vre3feuille"
}
};
var h = new window['Hypher'](module.exports);
if (typeof module.exports.id === 'string') {
module.exports.id = [module.exports.id];
}
for (var i = 0; i < module.exports.id.length; i += 1) {
window['Hypher']['languages'][module.exports.id[i]] = h;
}
}());

224
lib/3rdparty/jquery.hypher.js vendored Normal file
View File

@ -0,0 +1,224 @@
;(function () {
var module = {
exports: null,
}
/**
* @constructor
* @param {!{patterns: !Object, leftmin: !number, rightmin: !number}} language The language pattern file. Compatible with Hyphenator.js.
*/
function Hypher(language) {
var exceptions = [],
i = 0
/**
* @type {!Hypher.TrieNode}
*/
this.trie = this.createTrie(language['patterns'])
/**
* @type {!number}
* @const
*/
this.leftMin = language['leftmin']
/**
* @type {!number}
* @const
*/
this.rightMin = language['rightmin']
/**
* @type {!Object.<string, !Array.<string>>}
*/
this.exceptions = {}
if (language['exceptions']) {
exceptions = language['exceptions'].split(/,\s?/g)
for (; i < exceptions.length; i += 1) {
this.exceptions[exceptions[i].replace(/\u2027/g, '').toLowerCase()] = new RegExp(
'(' + exceptions[i].split('\u2027').join(')(') + ')',
'i'
)
}
}
}
/**
* @typedef {{_points: !Array.<number>}}
*/
Hypher.TrieNode
/**
* Creates a trie from a language pattern.
* @private
* @param {!Object} patternObject An object with language patterns.
* @return {!Hypher.TrieNode} An object trie.
*/
Hypher.prototype.createTrie = function (patternObject) {
var size = 0,
i = 0,
c = 0,
p = 0,
chars = null,
points = null,
codePoint = null,
t = null,
tree = {
_points: [],
},
patterns
for (size in patternObject) {
if (patternObject.hasOwnProperty(size)) {
patterns = patternObject[size].match(new RegExp('.{1,' + +size + '}', 'g'))
for (i = 0; i < patterns.length; i += 1) {
chars = patterns[i].replace(/[0-9]/g, '').split('')
points = patterns[i].split(/\D/)
t = tree
for (c = 0; c < chars.length; c += 1) {
codePoint = chars[c].charCodeAt(0)
if (!t[codePoint]) {
t[codePoint] = {}
}
t = t[codePoint]
}
t._points = []
for (p = 0; p < points.length; p += 1) {
t._points[p] = points[p] || 0
}
}
}
}
return tree
}
/**
* Hyphenates a text.
*
* @param {!string} str The text to hyphenate.
* @return {!string} The same text with soft hyphens inserted in the right positions.
*/
Hypher.prototype.hyphenateText = function (str, minLength) {
minLength = minLength || 4
// Regexp("\b", "g") splits on word boundaries,
// compound separators and ZWNJ so we don't need
// any special cases for those characters. Unfortunately
// it does not support unicode word boundaries, so
// we implement it manually.
var words = str.split(
/([a-zA-Z0-9_\u0027\u00DF-\u00EA\u00EC-\u00EF\u00F1-\u00F6\u00F8-\u00FD\u0101\u0103\u0105\u0107\u0109\u010D\u010F\u0111\u0113\u0117\u0119\u011B\u011D\u011F\u0123\u0125\u012B\u012F\u0131\u0135\u0137\u013C\u013E\u0142\u0144\u0146\u0148\u0151\u0153\u0155\u0159\u015B\u015D\u015F\u0161\u0165\u016B\u016D\u016F\u0171\u0173\u017A\u017C\u017E\u017F\u0219\u021B\u02BC\u0390\u03AC-\u03CE\u03F2\u0401\u0410-\u044F\u0451\u0454\u0456\u0457\u045E\u0491\u0531-\u0556\u0561-\u0587\u0902\u0903\u0905-\u090B\u090E-\u0910\u0912\u0914-\u0928\u092A-\u0939\u093E-\u0943\u0946-\u0948\u094A-\u094D\u0982\u0983\u0985-\u098B\u098F\u0990\u0994-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BE-\u09C3\u09C7\u09C8\u09CB-\u09CD\u09D7\u0A02\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A14-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A82\u0A83\u0A85-\u0A8B\u0A8F\u0A90\u0A94-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABE-\u0AC3\u0AC7\u0AC8\u0ACB-\u0ACD\u0B02\u0B03\u0B05-\u0B0B\u0B0F\u0B10\u0B14-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3E-\u0B43\u0B47\u0B48\u0B4B-\u0B4D\u0B57\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB5\u0BB7-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0C02\u0C03\u0C05-\u0C0B\u0C0E-\u0C10\u0C12\u0C14-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3E-\u0C43\u0C46-\u0C48\u0C4A-\u0C4D\u0C82\u0C83\u0C85-\u0C8B\u0C8E-\u0C90\u0C92\u0C94-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBE-\u0CC3\u0CC6-\u0CC8\u0CCA-\u0CCD\u0D02\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D28\u0D2A-\u0D39\u0D3E-\u0D43\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0D60\u0D61\u0D7A-\u0D7F\u1F00-\u1F07\u1F10-\u1F15\u1F20-\u1F27\u1F30-\u1F37\u1F40-\u1F45\u1F50-\u1F57\u1F60-\u1F67\u1F70-\u1F7D\u1F80-\u1F87\u1F90-\u1F97\u1FA0-\u1FA7\u1FB2-\u1FB4\u1FB6\u1FB7\u1FBD\u1FBF\u1FC2-\u1FC4\u1FC6\u1FC7\u1FD2\u1FD3\u1FD6\u1FD7\u1FE2-\u1FE7\u1FF2-\u1FF4\u1FF6\u1FF7\u200D\u2019]+)/g
)
for (var i = 0; i < words.length; i += 1) {
if (words[i].indexOf('/') !== -1) {
// Don't insert a zero width space if the slash is at the beginning or end
// of the text, or right after or before a space.
if (i !== 0 && i !== words.length - 1 && !/\s+\/|\/\s+/.test(words[i])) {
words[i] += '\u200B'
}
} else if (words[i].length > minLength) {
words[i] = this.hyphenate(words[i]).join('\u00AD')
}
}
return words.join('')
}
/**
* Hyphenates a word.
*
* @param {!string} word The word to hyphenate
* @return {!Array.<!string>} An array of word fragments indicating valid hyphenation points.
*/
Hypher.prototype.hyphenate = function (word) {
var characters,
characterPoints = [],
originalCharacters,
i,
j,
k,
node,
points = [],
wordLength,
lowerCaseWord = word.toLowerCase(),
nodePoints,
nodePointsLength,
m = Math.max,
trie = this.trie,
result = ['']
if (this.exceptions.hasOwnProperty(lowerCaseWord)) {
return word.match(this.exceptions[lowerCaseWord]).slice(1)
}
if (word.indexOf('\u00AD') !== -1) {
return [word]
}
word = '_' + word + '_'
characters = word.toLowerCase().split('')
originalCharacters = word.split('')
wordLength = characters.length
for (i = 0; i < wordLength; i += 1) {
points[i] = 0
characterPoints[i] = characters[i].charCodeAt(0)
}
for (i = 0; i < wordLength; i += 1) {
node = trie
for (j = i; j < wordLength; j += 1) {
node = node[characterPoints[j]]
if (node) {
nodePoints = node._points
if (nodePoints) {
for (k = 0, nodePointsLength = nodePoints.length; k < nodePointsLength; k += 1) {
points[i + k] = m(points[i + k], nodePoints[k])
}
}
} else {
break
}
}
}
for (i = 1; i < wordLength - 1; i += 1) {
if (i > this.leftMin && i < wordLength - this.rightMin && points[i] % 2) {
result.push(originalCharacters[i])
} else {
result[result.length - 1] += originalCharacters[i]
}
}
return result
}
module.exports = Hypher
window['Hypher'] = module.exports
window['Hypher']['languages'] = {}
})()
;(function ($) {
$.fn.hyphenate = function (language) {
if (window['Hypher']['languages'][language]) {
return this.each(function () {
var i = 0,
len = this.childNodes.length
for (; i < len; i += 1) {
if (this.childNodes[i].nodeType === 3) {
this.childNodes[i].nodeValue = window['Hypher']['languages'][language].hyphenateText(
this.childNodes[i].nodeValue
)
}
}
})
}
}
})(jQuery);

10364
lib/3rdparty/jquery.js vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

27
lib/_menu.js Normal file
View File

@ -0,0 +1,27 @@
const mapping = {
'lib.Application': './app.html',
'lib.Capabilities': './capabilities.html',
'lib.Card': './card/index.html',
'lib.Pixi': './pixi/index.html',
'pixi.App': './pixi/app.html'
}
function menu(event) {
let key = event.target.innerText
let html = ''
for (let k of Object.keys(mapping)) {
if (k.startsWith(key)) {
let rest = k.slice(key.length)
let url = mapping[k]
html += `<a href="${url}">${rest}</a>`
}
}
event.preventDefault()
let contextMenu = document.createElement('div')
contextMenu.id = 'ctxmenu'
contextMenu.style = `top:${event.pageY - 10}px;left:${event.pageX - 40}px`
contextMenu.onmouseleave = () => (contextMenu.outerHTML = '')
contextMenu.innerHTML = html
document.body.appendChild(contextMenu)
}

View File

@ -3,6 +3,7 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>App</title>
<link rel="stylesheet" href="./3rdparty/highlight/styles/default.css">
<link rel="stylesheet" href="../css/doctest.css">
<script src="./3rdparty/highlight/highlight.pack.js"></script>
@ -12,7 +13,7 @@
<body onload="Doctest.run()">
<h1>
Application
<a href="index.html">lib.</a>Application
</h1>
<p>
IWM Browser Applications follow a common three phase pattern, shared by many programming environments as diverse as Processing, Arduino, Intern, etc.

View File

@ -9,16 +9,20 @@ export class IApp extends Interface {
/** Build the app by registering event handlers,
* adding DOM elements, instanciating templates, etc...
*/
setup() { return this }
setup() {
return this
}
/** Run the application by starting a main loop, ...
*/
run() { return this }
run() {
return this
}
}
export default class App extends Object {
/** Override this method to build your app.
*/
*/
setup() {
return this
}
@ -48,8 +52,7 @@ export default class App extends Object {
this.allTests()
var end = performance.now()
return ['ok', end - start]
}
catch(e) {
} catch (e) {
console.trace()
return ['Tests failed', e.message]
}

400
lib/bootstrap.babel.js vendored
View File

@ -1,175 +1,275 @@
'use strict';
'use strict'
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _createClass = (function() {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i]
descriptor.enumerable = descriptor.enumerable || false
descriptor.configurable = true
if ('value' in descriptor) descriptor.writable = true
Object.defineProperty(target, descriptor.key, descriptor)
}
}
return function(Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps)
if (staticProps) defineProperties(Constructor, staticProps)
return Constructor
}
})()
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError('Cannot call a class as a function')
}
}
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError(
"this hasn't been initialised - super() hasn't been called"
)
}
return call && (typeof call === 'object' || typeof call === 'function')
? call
: self
}
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
function _inherits(subClass, superClass) {
if (typeof superClass !== 'function' && superClass !== null) {
throw new TypeError(
'Super expression must either be null or a function, not ' +
typeof superClass
)
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
})
if (superClass)
Object.setPrototypeOf
? Object.setPrototypeOf(subClass, superClass)
: (subClass.__proto__ = superClass)
}
var Bootstrap = function (_Object) {
_inherits(Bootstrap, _Object);
var Bootstrap = (function(_Object) {
_inherits(Bootstrap, _Object)
function Bootstrap() {
_classCallCheck(this, Bootstrap);
_classCallCheck(this, Bootstrap)
return _possibleConstructorReturn(this, (Bootstrap.__proto__ || Object.getPrototypeOf(Bootstrap)).apply(this, arguments));
return _possibleConstructorReturn(
this,
(Bootstrap.__proto__ || Object.getPrototypeOf(Bootstrap)).apply(
this,
arguments
)
)
}
_createClass(Bootstrap, null, [{
key: 'import',
value: function _import(src) {
var _this2 = this;
_createClass(Bootstrap, null, [
{
key: 'import',
value: function _import(src) {
var _this2 = this
var callback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
var callback =
arguments.length > 1 && arguments[1] !== undefined
? arguments[1]
: null
if (src.endsWith('babel.js')) {
this.load(this.baseUrl + '/3rdparty/polyfills/babel-polyfill.js', function () {
_this2.load(src, null, null);
}, null);
} else if (this.isModernSafari || this.isModernChrome) {
this.load(src, callback);
} else {
this.load(this.baseUrl + '/3rdparty/systemjs/system.js', function () {
SystemJS.config(_this2.systemjsConfig);
SystemJS.import(src);
}, 'script');
}
}
}, {
key: 'load',
value: function load(src, callback) {
var _this3 = this;
var type = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'module';
var script = document.createElement('script');
if (type === 'module') {
script.setAttribute('type', 'module');
script.setAttribute('crossorigin', 'use-credentials');
}
script.onload = function () {
if (callback) {
callback.call(_this3, script);
}
};
script.src = src;
document.head.appendChild(script);
}
}, {
key: 'require',
value: function require(src) {
console.log('Dummy require');
}
}, {
key: 'renderFont',
value: function renderFont() {
var font = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'Open Sans';
var _arr = [300, 400, 600, 700, 800];
for (var _i = 0; _i < _arr.length; _i++) {
var weight = _arr[_i];var _arr2 = ['normal', 'italic'];
for (var _i2 = 0; _i2 < _arr2.length; _i2++) {
var style = _arr2[_i2];
var p = document.createElement('p');
p.innerHTML = '.';
document.body.appendChild(p);
p.setAttribute('style', 'font-family: \'' + font + '\'; font-weight: ' + weight + '; font-style: \'' + style + '\'; position: absolute; top: -10000px;');
if (src.endsWith('babel.js')) {
this.load(
this.baseUrl + '/3rdparty/polyfills/babel-polyfill.js',
function() {
_this2.load(src, null, null)
},
null
)
} else if (this.isModernSafari || this.isModernChrome) {
this.load(src, callback)
} else {
this.load(
this.baseUrl + '/3rdparty/systemjs/system.js',
function() {
SystemJS.config(_this2.systemjsConfig)
SystemJS.import(src)
},
'script'
)
}
}
}
}, {
key: 'isSafari',
get: function get() {
return (/Safari/.test(navigator.userAgent) && /Apple Computer, Inc/.test(navigator.vendor)
);
}
}, {
key: 'isModernSafari',
get: function get() {
if (!this.isSafari) return false;
var agent = navigator.appVersion;
var offset = agent.indexOf('Version');
if (offset != -1) {
var version = parseFloat(agent.substring(offset + 8));
return version >= 10.1;
}
return false;
}
}, {
key: 'isChrome',
get: function get() {
var isChromium = window.chrome;
var winNav = window.navigator;
var vendorName = winNav.vendor;
var isOpera = winNav.userAgent.indexOf('OPR') > -1;
var isIEedge = winNav.userAgent.indexOf('Edge') > -1;
var isIOSChrome = winNav.userAgent.match('CriOS');
},
{
key: 'load',
value: function load(src, callback) {
var _this3 = this
if (isIOSChrome) {
return true;
} else if (isChromium !== null && isChromium !== undefined && vendorName === 'Google Inc.' && isOpera == false && isIEedge == false) {
return true;
} else {
return false;
}
}
}, {
key: 'isModernChrome',
get: function get() {
if (!this.isChrome) {
return false;
}
var raw = navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./);
var version = raw ? parseInt(raw[2], 10) : false;
return version > 62;
}
}, {
key: 'systemjsConfig',
get: function get() {
var type =
arguments.length > 2 && arguments[2] !== undefined
? arguments[2]
: 'module'
var baseUrl = this.baseUrl;
var script = document.createElement('script')
if (type === 'module') {
script.setAttribute('type', 'module')
script.setAttribute('crossorigin', 'use-credentials')
}
script.onload = function() {
if (callback) {
callback.call(_this3, script)
}
}
script.src = src
document.head.appendChild(script)
}
},
{
key: 'require',
value: function require(src) {
console.log('Dummy require')
}
},
{
key: 'renderFont',
value: function renderFont() {
var font =
arguments.length > 0 && arguments[0] !== undefined
? arguments[0]
: 'Open Sans'
var _arr = [300, 400, 600, 700, 800]
return {
baseURL: baseUrl,
map: {
'plugin-babel': baseUrl + '/3rdparty/systemjs/plugin-babel.js',
'systemjs-babel-build': baseUrl + '/3rdparty/systemjs/systemjs-babel-browser.js'
},
transpiler: 'plugin-babel',
meta: {
'*.js': {
authorization: true,
babelOptions: {
es2015: false
for (var _i = 0; _i < _arr.length; _i++) {
var weight = _arr[_i]
var _arr2 = ['normal', 'italic']
for (var _i2 = 0; _i2 < _arr2.length; _i2++) {
var style = _arr2[_i2]
var p = document.createElement('p')
p.innerHTML = '.'
document.body.appendChild(p)
p.setAttribute(
'style',
"font-family: '" +
font +
"'; font-weight: " +
weight +
"; font-style: '" +
style +
"'; position: absolute; top: -10000px;"
)
}
}
}
},
{
key: 'isSafari',
get: function get() {
return (
/Safari/.test(navigator.userAgent) &&
/Apple Computer, Inc/.test(navigator.vendor)
)
}
},
{
key: 'isModernSafari',
get: function get() {
if (!this.isSafari) return false
var agent = navigator.appVersion
var offset = agent.indexOf('Version')
if (offset != -1) {
var version = parseFloat(agent.substring(offset + 8))
return version >= 10.1
}
return false
}
},
{
key: 'isChrome',
get: function get() {
var isChromium = window.chrome
var winNav = window.navigator
var vendorName = winNav.vendor
var isOpera = winNav.userAgent.indexOf('OPR') > -1
var isIEedge = winNav.userAgent.indexOf('Edge') > -1
var isIOSChrome = winNav.userAgent.match('CriOS')
if (isIOSChrome) {
return true
} else if (
isChromium !== null &&
isChromium !== undefined &&
vendorName === 'Google Inc.' &&
isOpera == false &&
isIEedge == false
) {
return true
} else {
return false
}
}
},
{
key: 'isModernChrome',
get: function get() {
if (!this.isChrome) {
return false
}
var raw = navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)
var version = raw ? parseInt(raw[2], 10) : false
return version > 62
}
},
{
key: 'systemjsConfig',
get: function get() {
var baseUrl = this.baseUrl
return {
baseURL: baseUrl,
map: {
'plugin-babel':
baseUrl + '/3rdparty/systemjs/plugin-babel.js',
'systemjs-babel-build':
baseUrl +
'/3rdparty/systemjs/systemjs-babel-browser.js'
},
transpiler: 'plugin-babel',
meta: {
'*.js': {
authorization: true,
babelOptions: {
es2015: false
}
}
}
}
};
}
}, {
key: 'baseUrl',
get: function get() {
var baseUrl = './';
var scripts = document.getElementsByTagName('script');
for (var i = 0; i < scripts.length; i++) {
var script = scripts[i];
var src = script.getAttribute('src');
var re = /\/bootstrap(.babel)?\.js$/;
if (re.test(src)) {
baseUrl = src.replace(re, '');
}
}
},
{
key: 'baseUrl',
get: function get() {
var baseUrl = './'
var scripts = document.getElementsByTagName('script')
return baseUrl;
for (var i = 0; i < scripts.length; i++) {
var script = scripts[i]
var src = script.getAttribute('src')
var re = /\/bootstrap(.babel)?\.js$/
if (re.test(src)) {
baseUrl = src.replace(re, '')
}
}
return baseUrl
}
}
}]);
])
return Bootstrap;
}(Object);
return Bootstrap
})(Object)
window.Bootstrap = Bootstrap;
window.Bootstrap = Bootstrap

67
lib/bootstrap.js vendored
View File

@ -1,13 +1,10 @@
class Bootstrap extends Object {
static get isSafari() {
return /Safari/.test(navigator.userAgent) && /Apple Computer, Inc/.test(navigator.vendor)
}
static get isModernSafari() {
if (!this.isSafari)
return false
if (!this.isSafari) return false
let agent = navigator.appVersion
let offset = agent.indexOf('Version')
if (offset != -1) {
@ -27,7 +24,13 @@ class Bootstrap extends Object {
if (isIOSChrome) {
return true
} else if (isChromium !== null && isChromium !== undefined && vendorName === 'Google Inc.' && isOpera == false && isIEedge == false) {
} else if (
isChromium !== null &&
isChromium !== undefined &&
vendorName === 'Google Inc.' &&
isOpera == false &&
isIEedge == false
) {
return true
} else {
return false
@ -45,7 +48,6 @@ class Bootstrap extends Object {
}
static get isFirefox() {
if (window.navigator.userAgent.toLowerCase().indexOf('firefox') > -1) {
return true
}
@ -54,7 +56,6 @@ class Bootstrap extends Object {
}
static get isModernFirefox() {
if (!this.isFirefox) {
return false
}
@ -67,26 +68,31 @@ class Bootstrap extends Object {
static import(src, callback = null) {
if (src.endsWith('babel.js')) {
this.load(this.baseUrl + '/3rdparty/polyfills/babel-polyfill.js',
this.load(
this.baseUrl + '/3rdparty/polyfills/babel-polyfill.js',
() => {
this.load(src, callback, null)
},
null)
}
else if (this.isModernSafari || this.isModernChrome || this.isModernFirefox) {
null
)
} else if (this.isModernSafari || this.isModernChrome || this.isModernFirefox) {
this.load(src, callback)
} else {
this.load(this.baseUrl + '/3rdparty/systemjs/system.js', () => {
SystemJS.config(this.systemjsConfig)
let promise = SystemJS.import(src)
if (promise) {
promise.then(() => {
if (callback) {
callback.call(this)
}
})
}
}, 'script')
this.load(
this.baseUrl + '/3rdparty/systemjs/system.js',
() => {
SystemJS.config(this.systemjsConfig)
let promise = SystemJS.import(src)
if (promise) {
promise.then(() => {
if (callback) {
callback.call(this)
}
})
}
},
'script'
)
}
}
@ -110,29 +116,27 @@ class Bootstrap extends Object {
}
static get systemjsConfig() {
const baseUrl = this.baseUrl
return {
baseURL: baseUrl,
map: {
'plugin-babel': baseUrl + '/3rdparty/systemjs/plugin-babel.js',
'systemjs-babel-build': baseUrl + '/3rdparty/systemjs/systemjs-babel-browser.js'
'systemjs-babel-build': baseUrl + '/3rdparty/systemjs/systemjs-babel-browser.js',
},
transpiler: 'plugin-babel',
meta: {
'*.js': {
authorization: true,
babelOptions: {
es2015: false
}
}
}
es2015: false,
},
},
},
}
}
static get baseUrl() {
let baseUrl = './'
let scripts = document.getElementsByTagName('script')
@ -154,7 +158,10 @@ class Bootstrap extends Object {
let p = document.createElement('p')
p.innerHTML = '.'
document.body.appendChild(p)
p.setAttribute('style', `font-family: '${font}'; font-weight: ${weight}; font-style: '${style}'; position: absolute; top: -10000px;`)
p.setAttribute(
'style',
`font-family: '${font}'; font-weight: ${weight}; font-style: '${style}'; position: absolute; top: -10000px;`
)
}
}
}

View File

@ -2,23 +2,65 @@ import App from './app.js'
import Doctest from './doctest.js'
import Errors from './errors.js'
import Events from './events.js'
import {DOMFlip, DOMFlippable, CardLoader, PDFLoader, ImageLoader, FrameLoader, HTMLLoader} from './flippable.js'
import { DOMFlip, DOMFlippable, CardLoader, PDFLoader, ImageLoader, FrameLoader, HTMLLoader } from './flippable.js'
import Index from './index.js'
import Interface from './interface.js'
import Logging from './logging.js'
import Poppable from './poppable.js'
import PopupMenu from './popupmenu.js'
import Popup from './popup.js'
import {IApp} from './app.js'
import {Capabilities, CapabilitiesTests} from './capabilities.js'
import {EventRecorder} from './events.js'
import {FrameContainer, FrameTarget} from './frames.js'
import {Inspect} from './inspect.js'
import {PointMap, InteractionPoints, Interaction, IInteractionTarget, InteractionDelta, InteractionMapper, InteractionDelegate, IInteractionMapperTarget} from './interaction.js'
import {ResizeEvent, DOMScatterContainer, AbstractScatter, DOMScatter, ScatterEvent, BaseEvent} from './scatter.js'
import {Cycle, Colors, Elements, Angle, Dates, Points, Polygon, Rect, Sets, Strings, isEmpty, getId, lerp, debounce, randomInt, randomFloat} from './utils.js'
import { IApp } from './app.js'
import { Capabilities, CapabilitiesTests } from './capabilities.js'
import { EventRecorder } from './events.js'
import { FrameContainer, FrameTarget } from './frames.js'
import { Inspect } from './inspect.js'
import {
PointMap,
InteractionPoints,
Interaction,
IInteractionTarget,
InteractionDelta,
InteractionMapper,
InteractionDelegate,
IInteractionMapperTarget,
} from './interaction.js'
import {
ITapDelegate,
ResizeEvent,
DOMScatterContainer,
AbstractScatter,
DOMScatter,
ScatterEvent,
BaseEvent,
} from './scatter.js'
import {
Cycle,
Colors,
Elements,
Angle,
Dates,
Points,
Polygon,
Rect,
Sets,
Strings,
isEmpty,
getId,
lerp,
debounce,
randomInt,
randomFloat,
LowPassFilter,
} from './utils.js'
import UITest from './uitest.js'
import Card from './card/card.js'
import CardWrapper from './card/wrapper.js'
import Highlight from './card/highlight.js'
import ScatterCard from './card/scatter.js'
import { CardPlugin, CardPluginBase } from './card/plugin.js'
import Theme from './card/theme.js'
/* Needed to ensure that rollup.js includes class definitions and the classes
are visible inside doctests.
*/
@ -53,6 +95,7 @@ window.FrameTarget = FrameTarget
window.IApp = IApp
window.IInteractionMapperTarget = IInteractionMapperTarget
window.IInteractionTarget = IInteractionTarget
window.ITapDelegate = ITapDelegate
window.Index = Index
window.Inspect = Inspect
window.Interaction = Interaction
@ -62,6 +105,7 @@ window.InteractionMapper = InteractionMapper
window.InteractionPoints = InteractionPoints
window.Interface = Interface
window.Logging = Logging
window.LowPassFilter = LowPassFilter
window.PointMap = PointMap
window.Rect = Rect
window.Points = Points
@ -80,3 +124,11 @@ window.lerp = lerp
window.debounce = debounce
window.randomInt = randomInt
window.randomFloat = randomFloat
window.CardWrapper = CardWrapper
window.Card = Card
window.CardPlugin = CardPlugin
window.CardPluginBase = CardPluginBase
window.ScatterCard = ScatterCard
window.Highlight = Highlight
window.Theme = Theme

View File

@ -1,75 +1,56 @@
<!doctype html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Doctests Capabilities</title>
<link rel="stylesheet" href="./3rdparty/highlight/styles/default.css">
<link rel="stylesheet" href="../css/doctest.css">
<script src="./3rdparty/highlight/highlight.pack.js"></script>
<script type="text/javascript" src="../dist/iwmlib.js"></script>
</head>
<body onload="Doctest.run(); CapabilitiesTests.testAll()">
<main>
<h1>
Capabilities
</h1>
<p>Browsers differ in many aspects, from touch support, support of CSS and HTML5 standards, to
javascript versions. This page collects some of these differences.
<h3>
User Agent
</h3>
<p id="user_agent">
</p>
<h3>
Device Pixel Ratio
</h3>
<p id="device_pixel_ratio">
</p>
<h3>
Multi Touch Table
</h3>
<p id="multi_touch_table">
</p>
<h3>
Supported Events
</h3>
<p id="supported_events">
</p>
<script class="doctest">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Doctests Capabilities</title>
<link rel="stylesheet" href="./3rdparty/highlight/styles/default.css" />
<link rel="stylesheet" href="../css/doctest.css" />
<script src="./3rdparty/highlight/highlight.pack.js"></script>
<script type="text/javascript" src="../dist/iwmlib.js"></script>
</head>
<body onload="Doctest.run(); CapabilitiesTests.testAll()">
<main>
<h1><a href="index.html">lib.</a>Capabilities</h1>
<p>
Browsers differ in many aspects, from touch support, support of CSS and HTML5 standards, to javascript
versions. This page collects some of these differences.
</p>
Doctest.expect(Capabilities.supportsMouseEvents(), true)
<h3>User Agent</h3>
<p id="user_agent"></p>
<h3>Device Pixel Ratio</h3>
<p id="device_pixel_ratio"></p>
<h3>Multi Touch Table</h3>
<p id="multi_touch_table"></p>
<h3>Supported Events</h3>
<p id="supported_events"></p>
<script class="doctest">
Doctest.expect(Capabilities.supportsMouseEvents(), true)
if (Capabilities.supportsTouchEvents()) {
Doctest.expect(Capabilities.supportsTouchEvents(), true)
}
if (Capabilities.supportsTouchEvents()) {
Doctest.expect(Capabilities.supportsTouchEvents(), true)
}
if (Capabilities.supportsPointerEvents()) {
Doctest.expect(Capabilities.supportsPointerEvents(), true)
}
</script>
<h3>
Interactive Alerts
</h3>
<p>
Standard alerts are displayed quite differently, on Windows 10, for instance
the browser URL is encluded, and a checkbox that allows to hide the
alert dialogs.
</p>
<button onclick="alert('Ok'); console.log('Alert')">Alert</button>
<button onclick="CapabilitiesTests.testConfirm()">Confirm</button>
<button onclick="CapabilitiesTests.testPrompt()">Prompt</button>
<p id="demo">
Result
</p>
<hr />
if (Capabilities.supportsPointerEvents()) {
Doctest.expect(Capabilities.supportsPointerEvents(), true)
}
</script>
<h3>Interactive Alerts</h3>
<p>
Standard alerts are displayed quite differently, on Windows 10, for instance the browser URL is
encluded, and a checkbox that allows to hide the alert dialogs.
</p>
<button onclick="alert('Ok'); console.log('Alert')">Alert</button>
<button onclick="CapabilitiesTests.testConfirm()">Confirm</button>
<button onclick="CapabilitiesTests.testPrompt()">Prompt</button>
<p id="demo">Result</p>
<hr />
<h2>
References
</h2>
<ul>
<li><a href="http://caniuse.com">Can I use</a></li>
<li><a href="http://webglreport.com">WebGL Report</a></li>
</ul>
</main>
</body>
<h2>References</h2>
<ul>
<li><a href="http://caniuse.com">Can I use</a></li>
<li><a href="http://webglreport.com">WebGL Report</a></li>
</ul>
</main>
</body>
</html>

View File

@ -1,7 +1,6 @@
/** Report capabilities with guaranteed values.
*/
export class Capabilities {
/** Returns the browser userAgent.
@return {string}
*/
@ -14,7 +13,7 @@ export class Capabilities {
@return {boolean}
*/
static get isMobile() {
return (/Mobi/.test(navigator.userAgent))
return /Mobi/.test(navigator.userAgent)
}
/** Tests whether the app is running on a iOS device.
@ -22,7 +21,7 @@ export class Capabilities {
@return {boolean}
*/
static get isIOS() {
return (/iPad|iPhone|iPod/.test(navigator.userAgent)) && !window.MSStream
return /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream
}
/** Tests whether the app is running in a Safari environment.
@ -31,16 +30,20 @@ export class Capabilities {
@return {boolean}
*/
static get isSafari() {
return navigator.vendor && navigator.vendor.indexOf('Apple') > -1 && navigator.userAgent && !navigator.userAgent.match('CriOS')
return (
navigator.vendor &&
navigator.vendor.indexOf('Apple') > -1 &&
navigator.userAgent &&
!navigator.userAgent.match('CriOS')
)
}
/**
* Distincts if the app is running inside electron or not.
*
*
* source: https://github.com/cheton/is-electron
*/
static get isElectron() {
// Renderer process
if (typeof window !== 'undefined' && typeof window.process === 'object' && window.process.type === 'renderer') {
return true
@ -52,7 +55,11 @@ export class Capabilities {
}
// Detect the user agent when the `nodeIntegration` option is set to true
if (typeof navigator === 'object' && typeof navigator.userAgent === 'string' && navigator.userAgent.indexOf('Electron') >= 0) {
if (
typeof navigator === 'object' &&
typeof navigator.userAgent === 'string' &&
navigator.userAgent.indexOf('Electron') >= 0
) {
return true
}
@ -70,52 +77,54 @@ export class Capabilities {
@return {boolean}
*/
static get isMultiTouchTable() {
return Capabilities.devicePixelRatio > 2 && Capabilities.isMobile === false && /Windows/i.test(Capabilities.userAgent)
return (
Capabilities.devicePixelRatio > 2 &&
Capabilities.isMobile === false &&
/Windows/i.test(Capabilities.userAgent)
)
}
/** Returns true if mouse events are supported
@return {boolean}
*/
static supportsMouseEvents() {
return typeof(window.MouseEvent) != 'undefined'
return typeof window.MouseEvent != 'undefined'
}
/** Returns true if touch events are supported
@return {boolean}
*/
static supportsTouchEvents() {
return typeof(window.TouchEvent) != 'undefined'
return typeof window.TouchEvent != 'undefined'
}
/** Returns true if pointer events are supported
@return {boolean}
*/
static supportsPointerEvents() {
return typeof(window.PointerEvent) != 'undefined'
return typeof window.PointerEvent != 'undefined'
}
/** Returns true if DOM templates are supported
@return {boolean}
*/
static supportsTemplate() {
return 'content' in document.createElement('template');
return 'content' in document.createElement('template')
}
}
/** Basic tests for Capabilities.
*/
export class CapabilitiesTests {
static testConfirm() {
let bool = confirm('Please confirm')
document.getElementById('demo').innerHTML = (bool) ? 'Confirmed' : 'Not confirmed'
document.getElementById('demo').innerHTML = bool ? 'Confirmed' : 'Not confirmed'
}
static testPrompt() {
let person = prompt('Please enter your name', 'Harry Potter')
if (person != null) {
demo.innerHTML =
'Hello ' + person + '! How are you today?'
demo.innerHTML = 'Hello ' + person + '! How are you today?'
}
}

2113
lib/card/card.js Normal file

File diff suppressed because it is too large Load Diff

383
lib/card/highlight.js Normal file
View File

@ -0,0 +1,383 @@
/* eslint-disable no-console */
let _HighlightEnabled = true
let _CircleIds = 0
/** Helper method to round values with one digit precision */
function round(value) {
return Math.round(parseFloat(value) * 10) / 10
}
/**
* A namespace with static functions to expand and shrink highlighted image regions.
* Assumes an SVG image with the following structure:
*
* <svg viewbox="0 0 100 100">
* <!-- The defs section must be defined and cannot be generated in JavaScript -->
* <defs>
* </defs>
* <image width="100" height="100" xlink:href="../assets/chess.jpg"/>
* <circle onclick="Highlight.animateZoom(event)" cx="47" cy="18" r="8" stroke-width="0.5" />
* <circle onclick="Highlight.animateZoom(event)" cx="60" cy="67" r="8" stroke-width="0.5" />
* </svg>
*
* The SVG root element should use a viewbox with 0 0 100 100 to ensure that the positions and size of the
* circles can be represented in percent.
*
* @class Highlight
* @extends {Object}
*/
const SCALE = 1.5
export default class Highlight extends Object {
static disableAnimations() {
_HighlightEnabled = false
let expanded = document.querySelectorAll('.' + this.expandedClass)
for (let obj of expanded) {
this.shrink(obj)
}
}
static enableAnimations() {
_HighlightEnabled = true
}
static removeAnimations(svgRoot) {
let expanded = svgRoot.querySelectorAll('.' + this.expandedClass)
for (let obj of expanded) {
TweenLite.set(obj, { scale: 1 })
obj.classList.remove('zooming')
obj.classList.remove(this.expandedClass)
}
let defs = svgRoot.querySelector('defs')
while (defs.firstChild) {
defs.firstChild.remove()
}
let maskImages = svgRoot.querySelectorAll('.addedImage')
for (let m of maskImages) {
m.remove()
}
let circles = svgRoot.querySelectorAll('circle')
for (let circle of circles) {
if (circle.classList.length == 0) {
circle.removeAttribute('class')
}
if (circle.hasAttribute('id') && circle.getAttribute('id').startsWith('@@')) {
circle.removeAttribute('id')
}
circle.removeAttribute('data-svg-origin')
circle.removeAttribute('transform')
circle.removeAttribute('style')
let cx = circle.getAttribute('cx')
let cy = circle.getAttribute('cy')
let r = circle.getAttribute('r')
circle.setAttribute('cx', round(cx))
circle.setAttribute('cy', round(cy))
circle.setAttribute('r', round(r))
}
}
static expand(obj, { scale = SCALE, duration = 3, stroke = 2, onComplete = null } = {}) {
if (obj == null) return
//console.log("expand")
obj.classList.add('zooming')
TweenLite.to(obj, duration, {
scale,
onUpdate: () => {
let scale = obj._gsTransform.scaleX
obj.setAttribute('stroke-width', stroke / scale)
},
onComplete: () => {
console.log('expand complete')
obj.classList.remove('zooming')
obj.classList.add(this.expandedClass)
obj.setAttribute('stroke-width', stroke / scale)
if (onComplete) onComplete()
},
})
}
static shrink(obj, { duration = 0.5, stroke = 2 } = {}) {
//console.log("shrink")
if (obj == null) return
obj.classList.add('zooming')
TweenLite.to(obj, duration, {
scale: 1,
onUpdate: () => {
let scale = obj._gsTransform.scaleX
obj.setAttribute('stroke-width', stroke / scale)
},
onComplete: () => {
//console.log("shrink complete")
obj.classList.remove('zooming')
obj.classList.remove(this.expandedClass)
obj.setAttribute('stroke-width', stroke)
},
})
}
static animateCircle(target, callback) {
console.log('ANIMATE CIRCLE', this)
// ** DEBUG OUTPUTS **
let circle = target
// We need a unique id to ensure correspondence between circle, mask, and maskImage
if (!circle.hasAttribute('id')) {
_CircleIds += 1
circle.setAttribute('id', '@@' + _CircleIds)
}
let id = circle.getAttribute('id')
TweenLite.set(circle, { transformOrigin: '50% 50%' })
/*if (circle.classList.contains('zooming')) {
console.log("already zooming")
return
}*/
let svgRoot = circle.closest('svg')
let circleGroup = circle.parentNode
let image = svgRoot.querySelector('image')
let stroke = parseFloat(circleGroup.getAttribute('stroke-width') || 6)
let defs = svgRoot.querySelector('defs')
if (defs == null) {
defs = document.createElementNS(svgRoot, 'defs')
svgRoot.insertBefore(defs, image)
}
// // We need direct children, therefore we cannot use querySelectorAll
let maskImageId = 'maskImage' + id
let maskImage = svgRoot.getElementById(maskImageId)
if (circle.classList.contains(this.expandedClass)) {
if (!circle.classList.contains('zooming')) {
this.shrink(circle, { stroke })
this.shrink(maskImage, { stroke })
return
}
//console.log("animate called while zooming out -> expand")
} else if (circle.classList.contains('zooming')) {
//console.log("animate called while zooming in -> shrink")
this.shrink(circle, { stroke })
this.shrink(maskImage, { stroke })
return
}
let circles = Array.from(circleGroup.children).filter((e) => e.tagName == 'circle')
for (let c of circles) {
//console.log("shrinking all circles")
this.shrink(c, { stroke })
}
let maskImages = circleGroup.querySelectorAll('.addedImage')
for (let m of maskImages) {
this.shrink(m, { stroke })
}
this._createSVGMask(svgRoot, image, id)
// TweenLite.set(maskImage, { transformOrigin: `${tx}% ${ty}%` })
this.expand(circle, { stroke, onComplete: callback })
this.expand(maskImage)
return false
}
static openHighlight(target, { animation = 0.5, scale = SCALE, onExpanded = null } = {}) {
if (this._isExpanded(target)) {
console.log('Target is already expanded!')
return
} else {
let targetId = target.getAttribute('id')
if (targetId && targetId.startsWith('@@')) {
let id = targetId.slice(2)
const imageId = '#maskImage' + id
const parent = target.parentNode
if (parent != null) {
let image = parent.querySelector(imageId)
if (image) {
this._bringToFront(image)
} else console.error('Could not find corresponding image element.')
} else console.log('Element was no parent:', target)
}
this._bringToFront(target)
let svgRoot = target.closest('svg')
if (svgRoot == null) {
return
}
let image = svgRoot.querySelector('image')
// eslint-disable-next-line no-unused-vars
let [mask, maskImage] = this._getSVGMask(target, {
svgRoot,
image,
})
let center = this._calculateCenterRelativeTo(target, image)
TweenLite.set(maskImage, {
transformOrigin: `${center.x} ${center.y}`,
})
TweenLite.set(target, { transformOrigin: '50% 50%' })
TweenLite.to([target, maskImage], animation, {
scale,
onComplete: onExpanded,
})
target.classList.add(this.expandedClass)
}
}
static toggleHighlight(node, options = {}) {
console.log('toggleHighlight', this._isExpanded(node))
if (this._isExpanded(node)) {
this.closeHighlight(node, options)
} else {
this.openHighlight(node, options)
}
}
static _bringToFront(target) {
const parent = target.parentNode
if (target && parent) {
parent.removeChild(target)
parent.appendChild(target)
} else console.error('Could not bring to front. Either no target or no parent.', target, parent)
}
static _getSVGMask(circle, { svgRoot = null, image = null } = {}) {
const id = this._retrieveId(circle)
const maskId = 'mask' + id
const maskImageId = 'maskImage' + id
if (!svgRoot) svgRoot = circle.closest('svg')
let mask = svgRoot.getElementById(maskId)
let maskImage = svgRoot.getElementById(maskImageId)
if (!mask || !maskImage)
[mask, maskImage] = this._createSVGMask(circle, {
svgRoot,
image,
id,
})
return [mask, maskImage]
}
/**
* Creates an SVG mask for a provided svgElement.
*
* @static
* @param {SVGElement} element - Element that should be masked.
* @param {object} opts - Optional parameters to avoid unnecessary fetching of elements.
* @param {SVGElement} opts.svgRoot - The root <svg> element of the element.
* @param {SVGImageElement} opts.image - The image that is used in the mask.
* @param {number} opts.id - The id of the mask.
* @returns
* @memberof Highlight
*/
static _createSVGMask(element, { svgRoot = null, image = null, id = null } = {}) {
// We can fetch these values here, but it's more efficient to
// simply pass them in, as it's likely they were already retrieved beforehand.
if (svgRoot == null) svgRoot = element.closest('svg')
if (image == null) image = svgRoot.querySelector('image')
if (id == null) id = this._retrieveId(element)
let svg = 'http://www.w3.org/2000/svg'
let xlink = 'http://www.w3.org/1999/xlink'
let svgGroup = element.parentNode
let src = image.getAttributeNS(xlink, 'href')
let maskId = 'mask' + id
let maskImageId = 'maskImage' + id
let mask = svgRoot.getElementById(maskId)
let maskImage = svgRoot.getElementById(maskImageId)
let defs = svgRoot.querySelector('defs')
if (defs == null) {
defs = document.createElementNS(svgRoot, 'defs')
svgRoot.insertBefore(defs, image)
}
if (mask == null) {
mask = document.createElementNS(svg, 'mask')
mask.setAttribute('id', maskId)
let maskCircle = element.cloneNode(true)
mask.appendChild(maskCircle)
defs.appendChild(mask)
}
let bbox = svgRoot.getElementsByTagName('image')[0].getBBox()
let width = bbox.width
let height = bbox.height
if (maskImage == null) {
maskImage = document.createElementNS(svg, 'image')
maskImage.style.pointerEvents = 'none'
maskImage.setAttribute('id', maskImageId)
maskImage.setAttributeNS(xlink, 'href', src)
maskImage.setAttribute('width', width)
maskImage.setAttribute('height', height)
maskImage.setAttribute('class', 'addedImage')
TweenLite.set(maskImage, { scale: 1 })
maskImage.style.mask = 'url(#' + maskId + ')'
}
element.insertAdjacentElement('beforebegin', maskImage) // image.nextSibling)
// svgGroup.appendChild(element)
return [mask, maskImage]
}
static _calculateCenterRelativeTo(target, image) {
let bbox = image.getBBox()
let width = bbox.width
let height = bbox.height
let cx = target.getAttribute('cx')
let cy = target.getAttribute('cy')
let x = cx.endsWith('%') ? cx : round((cx / width) * 100) + '%'
let y = cy.endsWith('%') ? cy : round((cy / height) * 100) + '%'
return { x, y }
}
static _isExpanded(target) {
return target.classList.contains(this.expandedClass)
}
static closeHighlight(target, { animation = 0.5 } = {}) {
target.classList.remove(this.expandedClass)
// eslint-disable-next-line no-unused-vars
let [mask, maskImage] = this._getSVGMask(target)
// console.log('Close Highlight', maskImage)
TweenLite.to([target, maskImage], animation, {
scale: 1,
})
}
static animate(event) {
if (!_HighlightEnabled) return
event.stopPropagation()
this.animateCircle(event.target)
return false
}
static _retrieveId(target) {
let id = target.getAttribute('id')
// We need a unique id to ensure correspondence between circle, mask, and maskImage
if (!id) {
_CircleIds += 1
target.setAttribute('id', '@@' + _CircleIds)
id = _CircleIds
} else {
id = parseInt(id.substring(2))
}
return id
}
}
Highlight.expandedClass = 'expanded'

125
lib/card/index.html Normal file
View File

@ -0,0 +1,125 @@
<!doctype html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Doctests Cards</title>
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css">
<link rel="stylesheet" href="../../css/doctest.css">
<link rel="stylesheet" href="../../css/highlight.css">
<link rel="stylesheet" href="../../css/popup.css">
<script src="../3rdparty/highlight/highlight.pack.js"></script>
<script src="../../dist/iwmlib.3rdparty.js"></script>
<script src="../../dist/iwmlib.js"></script>
</head>
<body onload="Doctest.run();">
<h1>
<a href="../index.html">lib.</a><a href="index.html">card.</a>Cards
</h1>
<p>
Cards implement a central UI metaphor for multiuser applications. They allow users to explore information spaces
independently from each other. Most of the time a card lives within a scatter and can be moved, rotated, and
scaled.
The scatter and it's interaction mapper are also responsible to detect and distinguish tap events form other
interactions.
But in preview programs and editors this is not necessary. Therefore we provide a central CardWrapper class that
turns any DOM node into a card.
</p>
<p>
The wrapper's main task is to handle tap events and trigger the corresponding actions. There are three main
ways to define these actions.
<ol>
<li>Define onclick handlers in HTML and SVG, e.g. <code>&lt;a onclick="alert(1)"&gt;link&lt;a&gt;</code>
</li>
<li>Use onTap with a DOM node as event target, e.g. <code>wrapper.onTap(node, event => {})</code></li>
<li>Use onTap with a CSS selector, e.g. <code>wrapper.onTap('.link', event => {})</code></li>
</li>
</ol>
The order in which these possibilities are testet is 1, 2, 3.
</p>
<p>
Note that the objects can also be actived by clicking nearby and not directly on the DOM node.
This solves a major problem on large tabletops with a parallaxis in the display.
</p>
<div class="interactive grayBorder" style="position: relative;">
<article id="demoCardWithOnClick"
style="position: relative; left: 0%; padding: 16px; margin: 16px; border: 1px solid gray; width: 320px; height: 240px;">
<h1 style="color: gray;">A Demo Card with onclick</h1>
<figure style="position: relative;">
<img width="75%" src="../examples/women.jpeg">
<svg class="overlayBase" style="position: absolute; left: 0px; top: 0px; width: 100%; height: 100%;"
viewBox="0 0 100 100" preserveAspectRatio="xMidYMid meet">
<circle cx="35" cy="50" r="35" class="highlight" onclick="alert('Highlight clicked')" stroke="white"
fill="transparent" stroke-width="1" />
</svg>
</figure>
<p>Lorem ipsum <a class="link" style="color:blue;" onclick="alert('Link clicked')">dolor</a> sit amet,
consetetur sadipscing elitr.</p>
</article>
<article id="demoCardWithSelector"
style="position: absolute; left: 50%; top: 0%; padding: 16px; margin: 16px; border: 1px solid gray; width: 320px; height: 240px;">
<div class="info-card" style="text-align: center">
<h1 style="color: gray;">A Demo Card with selectors</h1>
<!-- Grr... The viewBox must reflect the width & height, using 0, 0, 100,
100 leads to blank spaces -->
<svg class="overlayBase" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 268 188"
style="width: 180px;" preserveAspectRatio="xMidYMid meet">
<defs>
</defs>
<image xlink:href="../examples/king.jpeg" x="0" y="0" height="188" width="268" />
<g>
<circle xlink:href="./popup.html" cx="50%" cy="30%" r="25%" class="highlight" stroke="white" fill="transparent"
stroke-width="4" />
</g>
</svg>
<p>Lorem ipsum <a class="link" href="javascript:alert('Link clicked via href')"
style="color:blue;">dolor</a> sit
amet,
consetetur sadipscing elitr.</p>
</div>
</article>
</div>
<script class="doctest">
Doctest.expect(ITapDelegate.implementedBy(CardWrapper), true)
const wrapper1 = new CardWrapper(demoCardWithOnClick)
wrapper1.handleClicksAsTaps()
const wrapper2 = new CardWrapper(demoCardWithSelector)
wrapper2.handleClicksAsTaps()
wrapper2.onTap('circle', (event, node) => {
Card.loadHighlightPopup(event, node)
})
wrapper2.onTap('a', event => {
alert('a clicked')
})
</script>
<h2>
Using Cards within Scatters
</h2>
<p>Cards can be used within scatters. Since the <code>CardWrapper</code> implements the <code>ITapDelegate</code>
protocol they can simply
be attached to a DOMScatter object. See the <a href="../scatter.html">Scatter Doctest</a>.
</p>
<div class="interactive grayBorder" style="position: relative;">
</div>
<h2>
References
</h2>
<ul>
<li><a href="https://uicookies.com/css-card-design/">30 Visually Stunning CSS Cards Inspirations For Every Type
Of Websites 2019</a></li>
</ul>
</body>

612
lib/card/plugin.js Normal file
View File

@ -0,0 +1,612 @@
export var CardPlugin = CardPlugin || {}
export class CardPluginBase {
apply(context) {
this.context = context
if (this.verify(context)) {
this.append(context)
console.log('Plugin ' + this.name + ' was verified successfully.')
return true
} else console.error('Could not verify module ' + this.name + '.')
return false
}
get name() {
return this.constructor.name
}
verify(context) {
let funcs = this._getVerificationFunctions(context)
for (let func of funcs) {
if (!func()) return false
}
return true
}
_verifyElementsExist(context, ...selectors) {
let missing = []
for (let selector of selectors) {
let requiredElement = context.querySelector(selector)
if (requiredElement == null) {
missing.push(selector)
}
}
const valid = missing.length == 0
if (!valid) console.error('Elements were missing: ', missing.join(', '))
return valid
}
/**
* Appends the Plugin to the context.
*
* @memberof CardPlugin
*/
append(context) {
console.error(
'Call of abstract method CardPlugin.prototype.append(context). Plugins need to overwrite the append method!'
)
}
_getVerificationFunctions(context) {
return [this._verifyContext.bind(this, context), this._verifyRequirements.bind(this, context)]
}
_verifyContext(context) {
if (!(context instanceof HTMLElement)) {
console.error('Context is not of type HTML Element.', context)
return false
} else return true
}
_verifyRequirements(context) {
let requirements = this._collectAllRequirements()
let missing = []
requirements.forEach((module) => {
if (context.modules.indexOf(module.name) == -1) {
missing.push(module.name)
}
})
const valid = missing.length == 0
if (!valid)
console.error(
"Could not apply module '" +
this.name +
"'. Following modules are required but were missing: " +
missing.join(',')
)
else console.log('All requirements were met! Well done!')
return valid
}
_collectAllRequirements() {
let requirements = []
let klass = this.__proto__
while (klass) {
if (klass.require != null) {
requirements = requirements.concat(klass.require)
}
klass = klass.__proto__
}
return requirements
}
/**
* Called when the card is removed.
* Can be used to cleanup the plugin.
*
* @memberof CardPluginBase
*/
remove() {}
}
CardPlugin.LightBox = class LightBox extends CardPluginBase {
constructor(className, style = {}) {
super()
this.className = className
this.style = style
}
append(context) {
let wrapper = document.createElement('div')
wrapper.className = this.className
Object.assign(
wrapper.style,
{
zIndex: 1000,
// backgroundColor: "black",
top: 0,
left: 0,
width: '100%',
height: '100%',
},
this.style,
{
display: 'none',
position: 'absolute',
}
)
context.appendChild(wrapper)
}
}
/**
* The Enlargeable Overlay module allows the user to click on the thumbnail image,
* and the images gets enlarged inside the card.
*
* @class EnlargeableThumbnail
* @extends {CardPlugin}
*/
CardPlugin.EnlargeableThumbnail = class EnlargeableThumbnail extends CardPluginBase {
constructor(
wrapperSelector,
overlaySelector = null,
{ zoomAnimationDuration = 0.4, fadeAnimationDuration = 0.4, interactionType = 'tap' } = {}
) {
super()
this.wrapperSelector = wrapperSelector
this.overlaySelector = overlaySelector
this.zoomAnimationDuration = zoomAnimationDuration
this.fadeAnimationDuration = fadeAnimationDuration
this.interactionType = interactionType
}
get require() {
return [CardPlugin.LightBox]
}
_getVerificationFunctions(context) {
let arr = super._getVerificationFunctions(context)
let funcs = [this._verifyElementsExist.bind(this, context, this.wrapperSelector, this.overlaySelector)]
return arr.concat(funcs)
}
append(context) {
let source = this._retrieveSource(context)
this.setupEnlargeableThumbnail(context, source)
}
/**
* Get the preview image.
*
* It depends on the fact, that the thumbnail image is in the same directory
*
*
* @param {*} context
* @returns
* @memberof EnlargeableThumbnail
*/
_retrieveSource(context) {
let img = context.querySelector(this.wrapperSelector + ' img')
let src = img.getAttribute('src')
let parts = src.split('/')
parts.pop()
parts.push(parts[parts.length - 1])
let imagePath = parts.join('/') + '.jpg'
return imagePath
}
setupEnlargeableThumbnail(context, src) {
let wrapper = context.querySelector(this.wrapperSelector)
let overlay = context.querySelector(this.overlaySelector)
let icon = document.createElement('div')
icon.className = 'button corner-button bottom-right icon zoom'
wrapper.appendChild(icon)
Object.assign(wrapper.style, {
cursor: 'pointer',
})
InteractionMapper.on(this.interactionType, wrapper, () => {
this.openThumbnailDetail(context, src)
})
InteractionMapper.on(this.interactionType, overlay, () => {
this.closeThumnailDetail(context)
})
}
openThumbnailDetail(context, src) {
let overlay = context.querySelector('.img-overlay')
overlay.innerHTML = ''
let source = context.querySelector(this.wrapperSelector)
let sourceStyle = window.getComputedStyle(source)
let imageWrapper = source.cloneNode(true)
let image = imageWrapper.querySelector('img')
Object.assign(imageWrapper.style, {
maxWidth: 'none',
maxHeight: 'none',
})
Object.assign(image.style, {
width: '100%',
height: '100%',
objectFit: 'cover',
})
this._replaceIcon(imageWrapper)
image.onload = () => {
let header = context.querySelector('header')
let headerStlye = window.getComputedStyle(header)
/**
* First the maxFillRatio is considered.
* It describes how much the image is allowed to exceed the context element.
*/
const maxFillRatio = 1.5
/**
* The minor side should not exceed the height of the context window.
*/
const maxMinorSize =
context.offsetHeight - 2 * parseInt(headerStlye.paddingTop) - 2 * parseInt(headerStlye.marginTop)
const max = {
width: context.offsetWidth * maxFillRatio,
height: context.offsetHeight * maxFillRatio,
}
let majorSide
let minorSide
const _width = { name: 'width', axis: 'x' }
const _height = { name: 'height', axis: 'y' }
if (image.naturalHeight > image.naturalWidth) {
majorSide = _height
minorSide = _width
} else {
majorSide = _width
minorSide = _height
}
function capitalize(string) {
return string.charAt(0).toUpperCase() + string.slice(1)
}
function getImageSize(side) {
return image['natural' + capitalize(side.name)]
}
const majorImageSize = getImageSize(majorSide)
// const minorImageSize = getImageSize(minorSide)
let ratio = getImageSize(minorSide) / getImageSize(majorSide)
let size = majorImageSize > max[majorSide.name] ? max[majorSide.name] : majorImageSize
if (size * ratio > maxMinorSize) {
size = maxMinorSize / ratio
}
let targetDimensions = {
width: 0,
height: 0,
}
let position = Points.fromPageToNode(context, Points.fromNodeToPage(source, { x: 0, y: 0 }))
let targetOffset = {
x: 0,
y: 0,
}
targetDimensions[majorSide.name] = size
targetDimensions[minorSide.name] = size * ratio
targetOffset[majorSide.axis] =
(context['offset' + capitalize(majorSide.name)] - targetDimensions[majorSide.name]) / 2
targetOffset[minorSide.axis] =
(context['offset' + capitalize(minorSide.name)] - targetDimensions[minorSide.name]) / 2
overlay.appendChild(imageWrapper)
TweenMax.set(imageWrapper, {
left: 0,
top: 0,
x: position.x,
y: position.y,
position: 'absolute',
width: parseInt(sourceStyle.width),
height: parseInt(sourceStyle.height),
})
TweenMax.set(overlay, {
display: 'flex',
autoAlpha: 0,
})
TweenMax.to(imageWrapper, this.zoomAnimationDuration, {
x: targetOffset.x,
y: targetOffset.y,
width: targetDimensions.width,
height: targetDimensions.height,
})
TweenMax.to(overlay, this.fadeAnimationTime, {
autoAlpha: 1,
})
}
image.src = src
}
_replaceIcon(clone) {
let zoomIcon = clone.querySelector('.icon.zoom')
zoomIcon.classList.remove('zoom')
zoomIcon.classList.add('close')
}
getBorderHeight(style) {
const borderWidth = parseInt(style.borderTopWidth) + parseInt(style.borderBottomWidth)
const padding = parseInt(style.paddingTop) + parseInt(style.paddingBottom)
return parseInt(style.width) + borderWidth + padding
}
getBorderWidth(style) {
const borderWidth = parseInt(style.borderLeftWidth) + parseInt(style.borderRightWidth)
const padding = parseInt(style.paddingLeft) + parseInt(style.paddingRight)
return parseInt(style.width) + borderWidth + padding
}
closeThumnailDetail(context) {
let overlay = context.querySelector('.img-overlay')
let timeline = new TimelineLite()
timeline
.to(overlay, this.fadeAnimationDuration, {
autoAlpha: 0,
})
.set(overlay, {
display: 'none',
})
}
}
CardPlugin.Ui = class UiPlugin extends CardPluginBase {
constructor(className, parent = null) {
super()
this.parent = parent
this.className = className
}
_getVerificationFunctions(context) {
let arr = super._getVerificationFunctions(context)
let func = [this._doesParentExist.bind(this, context, this.parent)]
return arr.concat(func)
}
_doesParentExist(context, parent) {
if (parent == null) return true
let valid = context.querySelector(parent) != null
if (!valid) console.error('Could not find parent on context.', context, parent)
return valid
}
append(context) {
parent = this.parent == null ? context : context.querySelector(this.parent).appendChild(container)
let container = document.createElement('div')
container.className = this.className
parent.appendChild(container)
}
}
CardPlugin.Speech = class SpeechPlugin extends CardPluginBase {
constructor(parentSelector, className, interactionType = 'tap') {
super()
this.className = className
this.parentSelector = parentSelector
this.interactionType = interactionType
// We directly overwriting the function with a version that has a binded
// reference to itself. Doing so provides an easy and reliable way to remove
// the event listener using this function. - SO
this._domWasChanged = this._domWasChanged.bind(this)
/*
Speech doesn't stop when page is navigated.
Therefore we do it manually here.
*/
window.addEventListener('beforeunload', () => {
window.speechSynthesis.cancel()
})
// Binding the function beforehand ensures, that the end function is always the same.
this._end = this._end.bind(this)
this._setupUtterance()
this.utterance.addEventListener('end', (event) => {
this._end()
})
}
get require() {
return [CardPlugin.Ui]
}
subcardChanged(closed) {
if (this.cardActive) {
this._updateText(closed)
}
}
get cardActive() {
return this.activeUtterance == this.utterance
}
_updateText(ignoreSubcard = false) {
let node = this.context
let subcard = node.querySelector('.mainview > .subcard')
if (ignoreSubcard) {
if (subcard != null) {
let clone = node.cloneNode(true)
let clonedSubcard = clone.querySelector('.mainview > .subcard')
clonedSubcard.parentNode.removeChild(clonedSubcard)
node = clone
}
} else {
if (subcard) {
let clone = subcard.cloneNode(true)
clone.querySelectorAll('figure').forEach((figure) => {
figure.parentNode.removeChild(figure)
})
node = clone
}
}
let id = this.context.getAttribute('data-id')
let src = this.context.getAttribute('data-source')
let subcardSource = null
if (subcard != null) {
subcardSource = subcard.getAttribute('data-source')
}
if (!window.speechSynthesis.speaking) {
this._start(node)
Logging.log(`Started speech on card: id:${id} - source: ${src} - subcard: ${subcardSource}`)
} else if (this.cardActive && this._sameText(node)) {
Logging.log(`Stopped speech on card: id:${id} - source: ${src} - subcard: ${subcardSource}`)
this._stop()
} else {
Logging.log(`Updated Text on card: id:${id} - source: ${src} - subcard: ${subcardSource}`)
this._stop()
.then(() => {
this._start(node)
})
.catch(console.error)
}
}
_sameText(node) {
return this.utterance.text == this._cleanupText(node)
}
_setupUtterance() {
this.utterance = new SpeechSynthesisUtterance()
this.utterance.lang = 'de-DE'
}
get require() {
return [CardPlugin.Ui]
}
remove() {
this.button = null
this._stopThisSpeechIfPlaying()
this.context.removeEventListener('DOMNodeRemoved', this._domWasChanged)
super.remove()
}
append(context) {
let container = context.querySelector(this.parentSelector)
this.button = document.createElement('div')
this.button.className = 'icon button ' + this.className
container.appendChild(this.button)
InteractionMapper.on(this.interactionType, this.button, () => {
this.speak()
})
context.addEventListener('DOMNodeRemoved', this._domWasChanged)
}
/**
* Don't remember why this was required - SO 20-11-2019
*/
_domWasChanged(event) {
if (event.target == this.context) this._stopThisSpeechIfPlaying()
}
/**
* Stops the module if it is set in the context.
*/
_stopThisSpeechIfPlaying() {
if (this.context == null || this.context['lastSpeechNode'] == window.speechSynthesis['speechPluginNode']) {
this._stop()
}
}
_isSameNode(node) {
return this.currentText == node.textContent
}
speak() {
/**
* This is a little bit ugly, but imho the most elegant of all dirty solutions.
*
5ht * Within the plugins we have no knowledge of other cards and such. But must differentiate the
* clicks by their corresponding owner. The SpeechUtterance just takes a text and has no knowledge
* about the node that is currently read to the user.
*
* This means, that we can identify same text, but not differentiate same text on different nodes.
* To account for that, we add the node to the speechSynthesis object (#benefitsOfJavaScript) and
* have access to the node, by - let's say - expanding the functionality of the SpeechSynthesis object.
*
* SO -17.07.19
*/
this._updateText()
}
async _stop() {
return new Promise((resolve) => {
if (this.activeUtterance) {
this.activeUtterance.addEventListener('end', resolve, {
once: true,
})
}
window.speechSynthesis.cancel()
})
}
get activeUtterance() {
return window.speechSynthesis['speechPluginUtterance']
}
_end() {
window.speechSynthesis['speechPluginNode'] = null
window.speechSynthesis['speechPluginUtterance'] = null
this._deactivateButton()
this.context.classList.remove('speech-plugin-is-reading')
}
_start(node) {
window.speechSynthesis.cancel()
window.speechSynthesis['speechPluginUtterance'] = this.utterance
window.speechSynthesis['speechPluginNode'] = node
this.context['lastSpeechNode'] = node
let cleanText = this._cleanupText(node)
this.utterance.text = cleanText
window.speechSynthesis.speak(this.utterance)
this._activateButton()
this.context.classList.add('speech-plugin-is-reading')
}
closed() {}
_cleanupText(node) {
let text = node.textContent
text = this._removeShy(text)
return text
}
_removeShy(text) {
return text.replace(/\u00AD/g, '')
}
_activateButton() {
if (this.button) this.button.classList.add('active')
}
_deactivateButton() {
if (this.button) this.button.classList.remove('active')
}
}

10
lib/card/popup.html Normal file
View File

@ -0,0 +1,10 @@
<div class="popupHtml">
<h1>
Popup
</h1>
<p>
Lorem ipsum...
</p>
</div>

162
lib/card/scatter.js Normal file
View File

@ -0,0 +1,162 @@
import Card from './card.js'
/**
* Extends the card with scatter functionality.
*
* @class ScatterCard
*/
export default class ScatterCard extends Card {
/**
* TODO: Find a more suitable name.
* Adjusts the HTML to work in the new context.
*
* @static
* @param {*} domElement
* @param {*} htmlString
* @param {*} basePath
* @param {*} [opts={}]
* @memberof ScatterCard
*/
static setup(context, htmlString, { basePath = './', modules = [] } = {}) {
if (typeof context.scatter == 'undefined') {
console.error(
"You need to wrap the context inside a DOMScatter before executing the ScatterCard's setup function."
)
}
/**
* This is required for the callback functions to work properly
*/
window.ScatterCard = ScatterCard
context.classList.add('info-card')
this.relativePath = basePath
htmlString = this._adjustRelativeLinks(htmlString)
let parser = new DOMParser()
let html = parser.parseFromString(htmlString, 'text/html')
/**
* Conflicts with the FindTarget method of the Abstract scatter.
*/
this._replaceAttributes(context, html, 'onclick', this._replaceCallback)
let content = html.querySelector('.mainview')
context.appendChild(content)
super.setup(context, modules)
return context
}
/**
* Creates a scatter for the card and applies the card to it,
*
* @static
* @param {*} html
* @param {*} scatterContainer
* @param {string} [basePath=""]
* @param {*} [opts={}]
* @returns
* @memberof ScatterCard
*/
static createCardScatter(html, scatterContainer, { basePath = './', modules = [] } = {}) {
let element = document.createElement('div')
scatterContainer.element.appendChild(element)
new DOMScatter(element, scatterContainer, {
width: 1400,
height: 1200,
})
this.setup(element, html, {
basePath,
modules,
})
return element
}
/**
* Closes but NOT removes the scatter element.
*
* The remove must be called separately, it may be used in the close callback
* of the scatter.
*/
static close(context) {
if (typeof context.scatter != 'undefined') context.scatter.close()
else {
console.error('Expected a scatter element to close!', this)
}
// Card.close(context)
// if (context['scatter']) {
// console.error('CLOSED CARD')
// context.scatter.close()
// } else {
// console.error('Expected a scatter element to close!', this)
// }
}
/**
* Cleans up the card.
*
* @static
* @override
* @memberof ScatterCard
*/
static remove(context) {
if (context['scatter']) {
context.scatter = null
} else {
console.error('Expected a scatter element to remove!', this)
}
Card.remove(context)
}
/**
*Utility function to create a fully functional card scatter.
*
* @static
* @param {*} scatterContainer
* @param {*} path
* @param {string} [basePath="."]
* @param {*} opts
* @returns
* @memberof CardScatter
*/
static loadAndCreateScatterCard(scatterContainer, item, { basePath = '../', modules = [] } = {}) {
console.log(basePath)
return new Promise((resolve, reject) => {
let url = basePath + '/' + item + '/index.html'
console.log('Loading', url)
this.loadHTML(url)
.then((html) => {
console.log('Received', html)
let element = this.createCardScatter(html, scatterContainer, {
basePath,
modules,
})
resolve(element)
})
.catch((e) => reject(e))
})
}
static _setLanguage(context, language) {
context.language = language
}
static _getLanguage(context) {
return context.language
}
}
ScatterCard.selectedLanguage = 0
ScatterCard.languages = ['Deutsch', 'English']
ScatterCard.languageTags = {
Deutsch: 'de',
English: 'en',
}
ScatterCard.scatterContainer = null

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8" ?>
<data>
<header>
<!-- Thumbnail of artwork with 512px large side -->
<thumbnail>01/thumbnail.jpg</thumbnail>
<!-- <artist> </artist>-->
<title>Das Rathaus</title>
<!-- <misc>erbaut 1435</misc>-->
<description>
Das Rathaus ist das wichtigste Gebäude auf dem Marktplatz. Mit dem Bau wurde 1435 begonnen, seitdem wurde es immer wieder verändert, sodass es Merkmale vieler Baustile vom Spätmittelalter bis zum 21. Jahrhundert aufweist. Die auffällige Fassadengestaltung stammt aus dem 19. Jahrhundert.
</description>
</header>
<card src="01/01_baugeschichte.xml"/>
<card src="01/01_funktiondamals.xml"/>
<card src="01/01_funktionheute.xml"/>
<card src="01/01_besonderheiten.xml"/>
<card src="01/01_besonderheiten2.xml"/>
<card src="01/01_besonderheiten3.xml"/>
</data>

View File

@ -0,0 +1,42 @@
<!DOCTYPE html><html lang="en"><head>
<meta charset="utf-8">
<title data-innerhtml="title">Article with 50% Columns</title>
<link rel="stylesheet" href="../_theme/css/bulma.css">
<link rel="stylesheet" href="../_theme/css/card.css">
<link rel="stylesheet" href="../_theme/css/article.css">
<link rel="stylesheet" href="../_theme/css/highlight.css">
<link rel="stylesheet" href="../_theme/css/popup.css">
<!-- disable zooming -->
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, minimum-scale=1, maximum-scale=1">
<script src="../_theme/js/all.js"></script>
<script src="../_theme/js/3rdparty/all.js"></script>
<script src="../_theme/js/card.js"></script>
<script src="../_theme/js/highlight.js"></script>
</head>
<body>
<article>
<div class="columns">
<div class="column content" data-link="Popup" tabindex=""><h2 contenteditable="false">Tübingen wird Stadt</h2> <p contenteditable="false" data-link="Popup">Bereits 1191 wurden in Tübingen Kaufleute erwähnt ein Beweis für einen Handelsplatz und der erste Schritt hin zur Stadt. Schon damals dürfte Tübingen städtischen Charakter besessen haben, es wurde jedoch erst 1231 urkundlich als Stadt erwähnt. Das daraufhin erstarkte städtische Selbstbewusstsein und die erhebliche Wirtschaftskraft Tübingens ebneten den Weg für den Bau eines Rathauses, das in mehreren Bauphasen errichtet wurde.</p><h2 contenteditable="false">Bauphasen</h2> <p contenteditable="false" data-link="Popup">1435 Erster Rathausbau</p> <p contenteditable="false" data-link="Popup">1495 Erweiterung um ein Stockwerk</p> <p contenteditable="false" data-link="Popup">1510/11 Einbau der <a href="../01/astronomischeuhr.html" data-highlight-id="" onclick="Card.loadPopup(event)">Astronomischen Uhr</a></p> <p contenteditable="false" data-link="Popup">1543 Erster Rathausanbau an der Haaggasse</p> <p contenteditable="false" data-link="Popup">1598 Einbau des <a href="../01/ziergiebel.html" data-highlight-id="" onclick="Card.loadPopup(event)">Ziergiebels</a></p> <p contenteditable="false" data-link="Popup">1692 Erneute Renovierung</p> <p contenteditable="false" data-link="Popup">1876/77 Anbringung der <a href="../01/vorderheutigenfassade.html" data-highlight-id="" onclick="Card.loadPopup(event)">heutigen Fassade</a></p> <p contenteditable="false" data-link="Popup">1910 Erneuerung des Anbaus an der Haaggasse</p> <p contenteditable="false" data-link="Popup">1965 Grundlegende Sanierungen</p> <p contenteditable="false" data-link="Popup">2016 Grundlegende Sanierungen</p></div>
<div class="column content" data-link="Popup" tabindex=""><div class="zoomable-wrapper column" ondragstart="Card.dragStart(event)">
<figure style="display: block;" class="zoomable singlefig" id="zoomable1">
<div style="position:relative;" class="svg-wrapper">
<svg draggable="false" class="mainimg" onclick="Card.openPopupOrZoomable(event)" viewBox="0 0 345 387.5" width="345" height="387.5" contenteditable="false">
<!-- The defs section must be defined and cannot be generated in JavaScript-->
<defs></defs>
<image width="345" height="387.5" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="../01/rathauszweigeschossig.png"></image>
<g stroke-width="3"></g>
</svg>
<div class="icon button corner-button bottom-right zoom zoomable-icon" onclick="Card.openZoomable(event)"></div>
</div>
<figcaption contenteditable="false" class="cap">Erster Rathausbau 15. Jh.</figcaption>
<figcaption contenteditable="false" class="zoomcap">Rekonstruktion des Rathauses im 15. Jahrhundert, Stadtarchiv Tübingen</figcaption>
</figure>
</div><h2 contenteditable="false">Der erste Rathausbau</h2> <p contenteditable="false" data-link="Popup">Um am Marktplatz ein großes <a href="../glossar/rathaus.html" data-highlight-id="" onclick="Card.loadPopup(event)">Rathaus</a> zu errichten, wurden dort wohl mehrere staatliche Bürgerhäuser abgerissen. Der erste Rathausbau 1435 war ein <a href="../glossar/fachwerk.html" data-highlight-id="" onclick="Card.loadPopup(event)">Fachwerkbau</a> mit drei Markthallen im Erdgeschoss und zwei Obergeschossen (siehe Abbildung). Im Erdgeschoss waren Verkaufsstände von Bäckern und Metzgern untergebracht, die sich bis dahin ohne Überdachung im Süden des Platzes befanden. Die Obergeschosse boten Raum für eine Verkaufshalle, die auch für Versammlungen und Feiern benutzt wurde, das Stadtgericht, das bis dahin ebenfalls auf dem Platz „direkt unter den Wolken“ tagte, sowie den Stadtrat.</p></div>
</div>
</article>
</body></html>

View File

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8" ?>
<card type="artist">
<!-- <card type="thema"> -->
<!-- <card type="details"> -->
<!-- <card type="leben des kunstwerks"> -->
<!-- <card type="komposition"> -->
<!-- <card type="licht und farbe"> -->
<!-- <card type="extra info"> -->
<h1>Das wichtigste &lt;br/&gt;städtische Gebäude</h1>
<preview>
<text>
Nach 200 Jahren &lt;br/&gt;endlich ein Rathaus
</text>
</preview>
<content template="1">
<column>
<text><![CDATA[
<h2>Tübingen wird Stadt</h2>
<p>Bereits 1191 wurden in Tübingen Kaufleute erwähnt ein Beweis für einen Handelsplatz und der erste Schritt hin zur Stadt. Schon damals dürfte Tübingen städtischen Charakter besessen haben, es wurde jedoch erst 1231 urkundlich als Stadt erwähnt. Das daraufhin erstarkte städtische Selbstbewusstsein und die erhebliche Wirtschaftskraft Tübingens ebneten den Weg für den Bau eines Rathauses, das in mehreren Bauphasen errichtet wurde.</p>
]]></text>
<text><![CDATA[
<h2>Bauphasen</h2>
<p>1435 Erster Rathausbau</p>
<p>1495 Erweiterung um ein Stockwerk</p>
<p>1510/11 Einbau der <a href="01/astronomischeuhr.xml" >Astronomischen Uhr</a></p>
<p>1543 Erster Rathausanbau an der Haaggasse</p>
<p>1598 Einbau des <a href="01/ziergiebel.xml" >Ziergiebels</a> </p>
<p>1692 Erneute Renovierung</p>
<p>1876/77 Anbringung der <a href="01/vorderheutigenfassade.xml" >heutigen Fassade</a></p>
<p>1910 Erneuerung des Anbaus an der Haaggasse</p>
<p>1965 Grundlegende Sanierungen</p>
<p>2016 Grundlegende Sanierungen</p>
]]></text>
</column>
<column>
<img src="01/rathauszweigeschossig.png" maxHeight="310" caption="Erster Rathausbau 15. Jh." allowZoom="true" zoomCaption="Rekonstruktion des Rathauses im 15. Jahrhundert, Stadtarchiv Tübingen"/>
<text><![CDATA[
<h2>Der erste Rathausbau</h2>
<p>Um am Marktplatz ein großes <a href="glossar/rathaus.xml" >Rathaus</a> zu errichten, wurden dort wohl mehrere staatliche Bürgerhäuser abgerissen. Der erste Rathausbau 1435 war ein <a href="glossar/fachwerk.xml" >Fachwerkbau</a> mit drei Markthallen im Erdgeschoss und zwei Obergeschossen (siehe Abbildung). Im Erdgeschoss waren Verkaufsstände von Bäckern und Metzgern untergebracht, die sich bis dahin ohne Überdachung im Süden des Platzes befanden. Die Obergeschosse boten Raum für eine Verkaufshalle, die auch für Versammlungen und Feiern benutzt wurde, das Stadtgericht, das bis dahin ebenfalls auf dem Platz „direkt unter den Wolken“ tagte, sowie den Stadtrat.</p>
]]></text>
</column>
</content>
</card>

View File

@ -0,0 +1,51 @@
<!DOCTYPE html><html lang="en"><head>
<meta charset="utf-8">
<title data-innerhtml="title">Article with 50% Columns</title>
<link rel="stylesheet" href="../_theme/css/bulma.css">
<link rel="stylesheet" href="../_theme/css/card.css">
<link rel="stylesheet" href="../_theme/css/article.css">
<link rel="stylesheet" href="../_theme/css/highlight.css">
<link rel="stylesheet" href="../_theme/css/popup.css">
<!-- disable zooming -->
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, minimum-scale=1, maximum-scale=1">
<script src="../_theme/js/all.js"></script>
<script src="../_theme/js/3rdparty/all.js"></script>
<script src="../_theme/js/card.js"></script>
<script src="../_theme/js/highlight.js"></script>
</head>
<body>
<article>
<div class="columns">
<div class="column content" data-link="Popup" tabindex=""><h2 contenteditable="false">Die drei Schichten der Fassade</h2> <p contenteditable="false" data-link="Popup">Unter der heutigen Bemalung der Rathausfassade (siehe Abbildung) liegen <a href="../01/malschichten.html" data-highlight-id="" onclick="Card.loadPopup(event)">zwei ältere Malschichten</a>: eine einfache Ausfüllung der Fachwerkfelder und darüber eine <a href="../01/grisaillemalerei.html" data-highlight-id="" onclick="Card.loadPopup(event)">Grisaillemalerei</a>. Sein heutiges Aussehen erhielt das Rathaus 1876 zum 400. Universitätsjubiläum. Nach Entwürfen des Stuttgarter Hochschulprofessors Konrad Dollinger wurde die Fassade von Ludwig Lesker mit <a href="../glossar/sgraffittomalerei.html" data-highlight-id="" onclick="Card.loadPopup(event)">Sgraffittomalerei</a> im Neorenaissance-Stil versehen. Die aufwändige Gestaltung erinnert in Farben und Ornamentik vor allem an das 16. Jahrhundert, eine Blütezeit der Stadt und der Universität.</p> <div style="height: undefinedpx">&nbsp;</div><div class="zoomable-wrapper column" ondragstart="Card.dragStart(event)">
<figure style="display: block;" class="zoomable singlefig" id="zoomable1">
<div style="position:relative;" class="svg-wrapper">
<svg draggable="false" class="mainimg" onclick="Card.openPopupOrZoomable(event)" viewBox="0 0 594 337.5" width="594" height="337.5" contenteditable="false">
<!-- The defs section must be defined and cannot be generated in JavaScript-->
<defs></defs>
<image width="594" height="337.5" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="../01/fassadeneu.jpg"></image>
<g stroke-width="3"><circle xlink:href="../01/eberhardfassade.html" data-highlight-id="01.fassadeneu.jpg.h1" onclick="Card.loadHighlightPopup(event)" cx="320" cy="62" r="59"></circle>
<circle xlink:href="../01/breuning.html" data-highlight-id="01.fassadeneu.jpg.h2" onclick="Card.loadHighlightPopup(event)" cx="48" cy="199" r="30"></circle>
<circle xlink:href="../01/osiander.html" data-highlight-id="01.fassadeneu.jpg.h3" onclick="Card.loadHighlightPopup(event)" cx="155" cy="199" r="30"></circle>
<circle xlink:href="../01/dann.html" data-highlight-id="01.fassadeneu.jpg.h4" onclick="Card.loadHighlightPopup(event)" cx="250" cy="199" r="30"></circle>
<circle xlink:href="../01/huber.html" data-highlight-id="01.fassadeneu.jpg.h5" onclick="Card.loadHighlightPopup(event)" cx="348" cy="199" r="30"></circle>
<circle xlink:href="../01/cotta.html" data-highlight-id="01.fassadeneu.jpg.h6" onclick="Card.loadHighlightPopup(event)" cx="446" cy="199" r="30"></circle>
<circle xlink:href="../01/uhland.html" data-highlight-id="01.fassadeneu.jpg.h7" onclick="Card.loadHighlightPopup(event)" cx="541" cy="199" r="30"></circle>
<circle xlink:href="../01/gerechtigkeit.html" data-highlight-id="01.fassadeneu.jpg.h8" onclick="Card.loadHighlightPopup(event)" cx="106" cy="275" r="42"></circle>
<circle xlink:href="../01/wohlstand.html" data-highlight-id="01.fassadeneu.jpg.h9" onclick="Card.loadHighlightPopup(event)" cx="211" cy="275" r="42"></circle>
<circle xlink:href="../01/wissenschaft.html" data-highlight-id="01.fassadeneu.jpg.h10" onclick="Card.loadHighlightPopup(event)" cx="490" cy="275" r="42"></circle></g>
</svg>
<div class="icon button corner-button bottom-right zoom zoomable-icon" onclick="Card.openZoomable(event)"></div>
</div>
<figcaption contenteditable="false" class="cap">Die Fassade des Rathauses</figcaption>
<figcaption contenteditable="false" class="zoomcap">Die Fassade des Rathauses, Foto: Christoph Jäckle</figcaption>
</figure>
</div></div>
<div class="column content" data-link="Popup" tabindex=""><h2 contenteditable="false">Mutige Männer, allegorische Frauen</h2> <p contenteditable="false" data-link="Popup"><a href="../01/eberhardfassade.html" data-highlight-id="01.fassadeneu.jpg.h1" onclick="Card.loadPopup(event)">Graf Eberhard im Bart</a>, der Gründer der Universität, der für seine Verdienste um die politische Einheit Württembergs in den Herzogsstand erhoben wurde, ist im obersten Geschoss abgebildet. Er wacht als echter Ritter über Stadt und Bürger, das Herzogsschwert und die Gründungsurkunde der Universität in den Händen.</p> <p contenteditable="false" data-link="Popup">Unter ihm sind in sechs Medaillons Porträts wichtiger Männer der Tübinger Stadtgeschichte zu sehen, die sich alle in besonderer Weise um bürgerliche Rechte und Freiheiten verdient gemacht hatten, wie sie bereits im <a href="../glossar/tuebingervertrag.html" data-highlight-id="" onclick="Card.loadPopup(event)">Tübinger Vertrag</a> von 1514 festgelegt wurden. Es handelt sich um den Vogt <a href="../01/breuning.html" data-highlight-id="01.fassadeneu.jpg.h2" onclick="Card.loadPopup(event)">Konrad Breuning</a>, den Diplomaten <a href="../01/osiander.html" data-highlight-id="01.fassadeneu.jpg.h3" onclick="Card.loadPopup(event)">Johannes Osiander</a>, den Bürgermeister <a href="../01/dann.html" data-highlight-id="01.fassadeneu.jpg.h4" onclick="Card.loadPopup(event)">Jakob Heinrich Dann</a>, den Oberamtmann <a href="../01/huber.html" data-highlight-id="01.fassadeneu.jpg.h5" onclick="Card.loadPopup(event)">Johann Ludwig Huber</a>, den Verleger <a href="../01/cotta.html" data-highlight-id="01.fassadeneu.jpg.h6" onclick="Card.loadPopup(event)">Johann Friedrich Cotta</a> und den Politiker <a href="../01/uhland.html" data-highlight-id="01.fassadeneu.jpg.h7" onclick="Card.loadPopup(event)">Ludwig Uhland</a>.</p> <p contenteditable="false" data-link="Popup">Die drei allegorischen Frauenfiguren im untersten Stock symbolisieren die <a href="../01/gerechtigkeit.html" data-highlight-id="01.fassadeneu.jpg.h8" onclick="Card.loadPopup(event)">Gerechtigkeit</a>, den <a href="../01/wohlstand.html" data-highlight-id="01.fassadeneu.jpg.h9" onclick="Card.loadPopup(event)">wirtschaftlichen Wohlstand</a> und die <a href="../01/wissenschaft.html" data-highlight-id="01.fassadeneu.jpg.h10" onclick="Card.loadPopup(event)">Wissenschaft</a>. Während die ersten beiden allgemein städtisch­bürgerliche Tugenden verkörpern, betont die dritte den Charakter Tübingens als Universitätsstadt.</p></div>
</div>
</article>
</body></html>

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- <card type="artist"> -->
<!-- <card type="thema"> -->
<card type="details">
<!-- <card type="leben des kunstwerks"> -->
<!-- <card type="komposition"> -->
<!-- <card type="licht und farbe"> -->
<!-- <card type="extra info"> -->
<h1>Fassadenmalerei</h1>
<preview>
<text>
Fassade aus &lt;br/&gt;Geist und Politik
</text>
</preview>
<content template="1">
<column>
<text><![CDATA[
<h2>Die drei Schichten der Fassade</h2>
<p>Unter der heutigen Bemalung der Rathausfassade (siehe Abbildung) liegen <a href="01/malschichten.xml">zwei ältere Malschichten</a>: eine einfache Ausfüllung der Fachwerkfelder und darüber eine <a href="01/grisaillemalerei.xml">Grisaillemalerei</a>. Sein heutiges Aussehen erhielt das Rathaus 1876 zum 400. Universitätsjubiläum. Nach Entwürfen des Stuttgarter Hochschulprofessors Konrad Dollinger wurde die Fassade von Ludwig Lesker mit <a href="glossar/sgraffittomalerei.xml" >Sgraffittomalerei</a> im Neorenaissance-Stil versehen. Die aufwändige Gestaltung erinnert in Farben und Ornamentik vor allem an das 16. Jahrhundert, eine Blütezeit der Stadt und der Universität.</p>
]]></text>
<space lines="1"/>
<img src="01/fassadeneu.jpg" maxHeight="270" caption="Die Fassade des Rathauses" allowZoom="true" zoomCaption="Die Fassade des Rathauses, Foto: Christoph Jäckle">
<highlight x="0.44" y="0.01" radius="0.1" href="01/eberhardfassade.xml" id="01.fassadeneu.jpg.h1"/>
<highlight x="0.03" y="0.5" radius="0.05" href="01/breuning.xml" id="01.fassadeneu.jpg.h2"/>
<highlight x="0.21" y="0.5" radius="0.05" href="01/osiander.xml" id="01.fassadeneu.jpg.h3"/>
<highlight x="0.37" y="0.5" radius="0.05" href="01/dann.xml" id="01.fassadeneu.jpg.h4"/>
<highlight x="0.535" y="0.5" radius="0.05" href="01/huber.xml" id="01.fassadeneu.jpg.h5"/>
<highlight x="0.7" y="0.5" radius="0.05" href="01/cotta.xml" id="01.fassadeneu.jpg.h6"/>
<highlight x="0.86" y="0.5" radius="0.05" href="01/uhland.xml" id="01.fassadeneu.jpg.h7"/>
<highlight x="0.107" y="0.69" radius="0.07" href="01/gerechtigkeit.xml" id="01.fassadeneu.jpg.h8"/>
<highlight x="0.285" y="0.69" radius="0.07" href="01/wohlstand.xml" id="01.fassadeneu.jpg.h9"/>
<highlight x="0.754" y="0.69" radius="0.07" href="01/wissenschaft.xml" id="01.fassadeneu.jpg.h10"/>
</img>
</column>
<column>
<text><![CDATA[
<h2>Mutige Männer, allegorische Frauen</h2>
<p><a href="01/eberhardfassade.xml" imageHighlightId="01.fassadeneu.jpg.h1">Graf Eberhard im Bart</a>, der Gründer der Universität, der für seine Verdienste um die politische Einheit Württembergs in den Herzogsstand erhoben wurde, ist im obersten Geschoss abgebildet. Er wacht als echter Ritter über Stadt und Bürger, das Herzogsschwert und die Gründungsurkunde der Universität in den Händen.</p>
<p>Unter ihm sind in sechs Medaillons Porträts wichtiger Männer der Tübinger Stadtgeschichte zu sehen, die sich alle in besonderer Weise um bürgerliche Rechte und Freiheiten verdient gemacht hatten, wie sie bereits im <a href="glossar/tuebingervertrag.xml">Tübinger Vertrag</a> von 1514 festgelegt wurden. Es handelt sich um den Vogt <a href="01/breuning.xml" imageHighlightId="01.fassadeneu.jpg.h2">Konrad Breuning</a>, den Diplomaten <a href="01/osiander.xml" imageHighlightId="01.fassadeneu.jpg.h3">Johannes Osiander</a>, den Bürgermeister <a href="01/dann.xml" imageHighlightId="01.fassadeneu.jpg.h4">Jakob Heinrich Dann</a>, den Oberamtmann <a href="01/huber.xml" imageHighlightId="01.fassadeneu.jpg.h5">Johann Ludwig Huber</a>, den Verleger <a href="01/cotta.xml" imageHighlightId="01.fassadeneu.jpg.h6">Johann Friedrich Cotta</a> und den Politiker <a href="01/uhland.xml" imageHighlightId="01.fassadeneu.jpg.h7">Ludwig Uhland</a>.</p>
<p>Die drei allegorischen Frauenfiguren im untersten Stock symbolisieren die <a href="01/gerechtigkeit.xml" imageHighlightId="01.fassadeneu.jpg.h8">Gerechtigkeit</a>, den <a href="01/wohlstand.xml" imageHighlightId="01.fassadeneu.jpg.h9">wirtschaftlichen Wohlstand</a> und die <a href="01/wissenschaft.xml" imageHighlightId="01.fassadeneu.jpg.h10">Wissenschaft</a>. Während die ersten beiden allgemein städtisch-bürgerliche Tugenden verkörpern, betont die dritte den Charakter Tübingens als Universitätsstadt.</p>
]]></text>
</column>
</content>
</card>

View File

@ -0,0 +1,44 @@
<!DOCTYPE html><html lang="en"><head>
<meta charset="utf-8">
<title data-innerhtml="title">Article with 50% Columns</title>
<link rel="stylesheet" href="../_theme/css/bulma.css">
<link rel="stylesheet" href="../_theme/css/card.css">
<link rel="stylesheet" href="../_theme/css/article.css">
<link rel="stylesheet" href="../_theme/css/highlight.css">
<link rel="stylesheet" href="../_theme/css/popup.css">
<!-- disable zooming -->
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, minimum-scale=1, maximum-scale=1">
<script src="../_theme/js/all.js"></script>
<script src="../_theme/js/3rdparty/all.js"></script>
<script src="../_theme/js/card.js"></script>
<script src="../_theme/js/highlight.js"></script>
</head>
<body>
<article>
<div class="columns">
<div class="column content" data-link="Popup" tabindex=""><h2 contenteditable="false">Wer ist das Rebmännle am Rathaus?</h2> <p contenteditable="false" data-link="Popup">Die kleine Skulptur „Rebmännle“, die um 1600 an der <a href="../01/rebmaennle.html" data-highlight-id="" onclick="Card.loadPopup(event)">Südostecke des Rathauses</a> angebracht wurde, stellt eindeutig eine unbekleidete weibliche Figur dar (siehe Abbildung). Sie tanzt auf einer <a href="../01/weintraube.html" data-highlight-id="01.rebmaennleneu.jpg.h1" onclick="Card.loadPopup(event)">vollen Weintraube</a>, um ihren Körper ist eine <a href="../01/girlandeausweinblaettern.html" data-highlight-id="01.rebmaennleneu.jpg.h2" onclick="Card.loadPopup(event)">Girlande aus Weinblättern</a> geschlungen und ihr nach hinten geworfener <a href="../01/umhang.html" data-highlight-id="01.rebmaennleneu.jpg.h4" onclick="Card.loadPopup(event)">Umhang</a> erinnert an ein Weinblatt. Es handelt sich um eine Frau aus dem Gefolge des Weingottes <a href="../glossar/bacchus.html" data-highlight-id="" onclick="Card.loadPopup(event)">Bacchus</a>, eine sogenannte Bacchantin. Die Platzierung an der prominenten Stelle soll die Bedeutung des Weinbaus für Tübingen symbolisieren.</p> <div style="height: undefinedpx">&nbsp;</div><h2 contenteditable="false">Nackte Frau im öffentlichen Raum</h2> <p contenteditable="false" data-link="Popup">Um 1600 konnte nur eine Figur aus der antiken Mythologie nackt im öffentlichen Raum aufgestellt werden, ohne Scham und Anstand zu verletzen. Zudem bot das Personal der antiken Götterwelt den Künstlern der frühen Neuzeit zum ersten Mal die Möglichkeit, nackte Figuren zu repräsentieren. Das Aussehen des „Rebmännles“ mit den stämmigen Beinen, dem üppigen Bauch und dem lachenden Gesicht entspricht der Vorstellung von <a href="../01/schoenheitsideal.html" data-highlight-id="" onclick="Card.loadPopup(event)">weiblicher Schönheit</a> zwischen Renaissance und Frühbarock.</p></div>
<div class="column content" data-link="Popup" tabindex=""><div class="zoomable-wrapper column" ondragstart="Card.dragStart(event)">
<figure style="display: block;" class="zoomable singlefig" id="zoomable1">
<div style="position:relative;" class="svg-wrapper">
<svg draggable="false" class="mainimg" onclick="Card.openPopupOrZoomable(event)" viewBox="0 0 467 875" width="467" height="875" contenteditable="false">
<!-- The defs section must be defined and cannot be generated in JavaScript-->
<defs></defs>
<image width="467" height="875" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="../01/rebmaennleneu.jpg"></image>
<g stroke-width="3"><circle xlink:href="../01/weintraube.html" data-highlight-id="01.rebmaennleneu.jpg.h1" onclick="Card.loadHighlightPopup(event)" cx="228" cy="767" r="93"></circle>
<circle xlink:href="../01/umhang.html" data-highlight-id="01.rebmaennleneu.jpg.h4" onclick="Card.loadHighlightPopup(event)" cx="182" cy="68" r="42"></circle>
<circle xlink:href="../01/girlandeausweinblaettern.html" data-highlight-id="01.rebmaennleneu.jpg.h2" onclick="Card.loadHighlightPopup(event)" cx="243" cy="406" r="56"></circle></g>
</svg>
<div class="icon button corner-button bottom-right zoom zoomable-icon" onclick="Card.openZoomable(event)"></div>
</div>
<figcaption contenteditable="false" class="cap">Tübinger Rebmännle</figcaption>
<figcaption contenteditable="false" class="zoomcap">Tübinger Rebmännle, Foto: Rose Hajdu, Stadtarchiv Tübingen</figcaption>
</figure>
</div></div>
</div>
</article>
</body></html>

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- <card type="artist"> -->
<!-- <card type="thema"> -->
<card type="details">
<!-- <card type="leben des kunstwerks"> -->
<!-- <card type="komposition"> -->
<!-- <card type="licht und farbe"> -->
<!-- <card type="extra info"> -->
<h1>Tübinger Rebmännle</h1>
<preview>
<text>
Eine unbekleidete Frau?
</text>
</preview>
<content template="1">
<column>
<text><![CDATA[
<h2>Wer ist das Rebmännle am Rathaus?</h2>
<p>Die kleine Skulptur „Rebmännle“, die um 1600 an der <a href="01/rebmaennle.xml" >Südostecke des Rathauses</a> angebracht wurde, stellt eindeutig eine unbekleidete weibliche Figur dar (siehe Abbildung). Sie tanzt auf einer <a href="01/weintraube.xml" imageHighlightId="01.rebmaennleneu.jpg.h1">vollen Weintraube</a>, um ihren Körper ist eine <a href="01/girlandeausweinblaettern.xml" imageHighlightId="01.rebmaennleneu.jpg.h2">Girlande aus Weinblättern</a> geschlungen und ihr nach hinten geworfener <a href="01/umhang.xml" imageHighlightId="01.rebmaennleneu.jpg.h4">Umhang</a> erinnert an ein Weinblatt. Es handelt sich um eine Frau aus dem Gefolge des Weingottes <a href="glossar/bacchus.xml">Bacchus</a>, eine sogenannte Bacchantin. Die Platzierung an der prominenten Stelle soll die Bedeutung des Weinbaus für Tübingen symbolisieren.</p>
]]></text>
<space lines="2"/>
<text><![CDATA[
<h2>Nackte Frau im öffentlichen Raum</h2>
<p>Um 1600 konnte nur eine Figur aus der antiken Mythologie nackt im öffentlichen Raum aufgestellt werden, ohne Scham und Anstand zu verletzen. Zudem bot das Personal der antiken Götterwelt den Künstlern der frühen Neuzeit zum ersten Mal die Möglichkeit, nackte Figuren zu repräsentieren. Das Aussehen des „Rebmännles“ mit den stämmigen Beinen, dem üppigen Bauch und dem lachenden Gesicht entspricht der Vorstellung von <a href="01/schoenheitsideal.xml" >weiblicher Schönheit</a> zwischen Renaissance und Frühbarock.</p>
]]></text>
<!-- <text><![CDATA[
<h2>Symbol des Tübinger Weinbaus</h2>
<p>Die Platzierung an der prominenten Stelle soll die Bedeutung des Weinbaus für Tübingen symbolisieren. Um 1600 konnte eigentlich nur eine Figur aus der antiken Mythologie nackt im öffentlichen Raum aufgestellt werden, ohne Scham und Anstand zu ver-letzen. Zudem bot das Personal der antiken Götter-welt den Künstlern der frühen Neuzeit auch neue Möglichkeiten künstlerischen Ausdrucks, wie sie bei den Heiligenfiguren des Mittelalters kaum möglich gewesen waren: An der Bacchantin fallen die stäm-migen Beine, der üppige Bauch und das lachende Gesicht als besonders <a href="01/lebensnahundrealistisch.xml" >lebensnah und realistisch</a> auf.</p>
]]></text> -->
</column>
<column>
<img src="01/rebmaennleneu.jpg" maxHeight="700" caption="Tübinger Rebmännle" allowZoom="true" zoomCaption="Tübinger Rebmännle, Foto: Rose Hajdu, Stadtarchiv Tübingen">
<highlight x="0.29" y="0.77" radius="0.2" href="01/weintraube.xml" id="01.rebmaennleneu.jpg.h1"/>
<highlight x="0.3" y="0.03" radius="0.09" href="01/umhang.xml" id="01.rebmaennleneu.jpg.h4"/>
<!-- <highlight x="0.39" y="0.12" radius="0.12" href="01/gesicht.xml" id="01.rebmaennle2.jpg.h3"/> -->
<highlight x="0.4" y="0.4" radius="0.12" href="01/girlandeausweinblaettern.xml" id="01.rebmaennleneu.jpg.h2"/>
</img>
</column>
</content>
</card>

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