tiddlywiki 5.3.1 → 5.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (364) hide show
  1. package/.github/workflows/ci.yml +9 -2
  2. package/bin/build-site.sh +25 -5
  3. package/bin/ci-test.sh +16 -0
  4. package/boot/boot.js +12 -0
  5. package/core/language/en-GB/Exporters.multids +1 -1
  6. package/core/language/en-GB/Help/commands.tid +1 -1
  7. package/core/language/en-GB/Help/savewikifolder.tid +2 -2
  8. package/core/language/en-GB/Help/server.tid +1 -1
  9. package/core/language/en-GB/Types/image_svg_xml.tid +1 -1
  10. package/core/language/en-GB/Types/image_x-icon.tid +1 -1
  11. package/core/modules/commands/savetiddlers.js +1 -1
  12. package/core/modules/editor/engines/framed.js +1 -1
  13. package/core/modules/editor/engines/simple.js +1 -1
  14. package/core/modules/filters/all.js +5 -5
  15. package/core/modules/filters/encodings.js +6 -2
  16. package/core/modules/filters/json-ops.js +95 -1
  17. package/core/modules/filters/listops.js +1 -0
  18. package/core/modules/parsers/textparser.js +5 -4
  19. package/core/modules/parsers/wikiparser/rules/conditional.js +120 -0
  20. package/core/modules/parsers/wikiparser/wikiparser.js +31 -8
  21. package/core/modules/savers/github.js +1 -1
  22. package/core/modules/startup/windows.js +2 -1
  23. package/core/modules/syncer.js +160 -122
  24. package/core/modules/utils/dom/dom.js +3 -3
  25. package/core/modules/utils/dom/http.js +1 -1
  26. package/core/modules/utils/fakedom.js +5 -1
  27. package/core/modules/utils/utils.js +27 -4
  28. package/core/modules/widgets/browse.js +10 -0
  29. package/core/modules/widgets/button.js +15 -3
  30. package/core/modules/widgets/checkbox.js +11 -0
  31. package/core/modules/widgets/draggable.js +16 -5
  32. package/core/modules/widgets/droppable.js +14 -2
  33. package/core/modules/widgets/image.js +19 -14
  34. package/core/modules/widgets/link.js +12 -2
  35. package/core/modules/widgets/list.js +176 -19
  36. package/core/modules/widgets/radio.js +4 -0
  37. package/core/modules/widgets/range.js +4 -0
  38. package/core/modules/widgets/scrollable.js +66 -1
  39. package/core/modules/widgets/select.js +34 -26
  40. package/core/modules/widgets/transclude.js +19 -6
  41. package/core/modules/widgets/widget.js +35 -19
  42. package/core/modules/wiki.js +2 -2
  43. package/core/templates/html-json-skinny-tiddler.tid +0 -1
  44. package/core/templates/html-json-tiddler.tid +1 -1
  45. package/core/templates/store.area.template.html.tid +4 -4
  46. package/core/ui/ControlPanel/Basics.tid +2 -2
  47. package/core/ui/EditTemplate/body/default.tid +12 -8
  48. package/core/ui/EditTemplate/fields.tid +2 -2
  49. package/core/ui/EditTemplate/type.tid +1 -1
  50. package/core/ui/EditorToolbar/preview.tid +6 -0
  51. package/core/ui/PageTemplate.tid +1 -1
  52. package/core/ui/ViewTemplate/subtitle.tid +2 -5
  53. package/core/wiki/config/OfficialPluginLibrary.tid +1 -1
  54. package/core/wiki/macros/colour-picker.tid +6 -6
  55. package/core/wiki/macros/image-picker.tid +5 -5
  56. package/core/wiki/macros/list.tid +95 -78
  57. package/core/wiki/macros/tabs.tid +9 -1
  58. package/core/wiki/macros/tag-picker.tid +2 -2
  59. package/core/wiki/macros/tag.tid +2 -1
  60. package/core/wiki/macros/toc.tid +2 -2
  61. package/editions/de-AT/tiddlers/HelloThere.tid +2 -2
  62. package/editions/de-AT/tiddlers/community/Fur_Entwickler.tid +1 -1
  63. package/editions/de-AT-server/tiddlers/system/favicon.png +0 -0
  64. package/editions/{es-ES-server/tiddlers/system/favicon.ico.meta → de-AT-server/tiddlers/system/favicon.png.meta} +1 -1
  65. package/editions/dev/tiddlers/images/favicon.png +0 -0
  66. package/editions/{de-AT-server/tiddlers/system/favicon.ico.meta → dev/tiddlers/images/favicon.png.meta} +1 -1
  67. package/editions/dev/tiddlers/new/HookMechanism.tid +28 -3
  68. package/editions/empty/tiddlywiki.info +5 -2
  69. package/editions/es-ES/tiddlers/Forums.tid +4 -5
  70. package/editions/es-ES/tiddlers/HelloThere.tid +2 -2
  71. package/editions/es-ES/tiddlers/Typography.tid +1 -1
  72. package/editions/es-ES/tiddlers/images/favicon.png +0 -0
  73. package/editions/{dev/tiddlers/images/favicon.ico.meta → es-ES/tiddlers/images/favicon.png.meta} +1 -1
  74. package/editions/es-ES/tiddlers/images/green_favicon.png +0 -0
  75. package/editions/es-ES/tiddlers/images/{green_favicon.ico.meta → green_favicon.png.meta} +1 -1
  76. package/editions/es-ES-server/tiddlers/system/favicon.png +0 -0
  77. package/editions/{es-ES/tiddlers/images/favicon.ico.meta → es-ES-server/tiddlers/system/favicon.png.meta} +1 -1
  78. package/editions/fr-FR/tiddlers/images/favicon.png +0 -0
  79. package/editions/fr-FR/tiddlers/images/favicon.png.meta +2 -0
  80. package/editions/fr-FR/tiddlers/images/green_favicon.png +0 -0
  81. package/editions/fr-FR/tiddlers/images/{green_favicon.ico.meta → green_favicon.png.meta} +1 -1
  82. package/editions/fr-FR-server/tiddlers/system/favicon.png +0 -0
  83. package/editions/fr-FR-server/tiddlers/system/favicon.png.meta +2 -0
  84. package/editions/highlightdemo/tiddlywiki.info +1 -1
  85. package/editions/ja-JP/tiddlers/images/favicon.png +0 -0
  86. package/editions/ja-JP/tiddlers/images/favicon.png.meta +2 -0
  87. package/editions/ja-JP/tiddlers/images/green_favicon.png +0 -0
  88. package/editions/ja-JP/tiddlers/images/{green_favicon.ico.meta → green_favicon.png.meta} +1 -1
  89. package/editions/katexdemo/tiddlywiki.info +1 -1
  90. package/editions/ko-KR/tiddlers/images/favicon.png +0 -0
  91. package/editions/ko-KR/tiddlers/images/favicon.png.meta +2 -0
  92. package/editions/ko-KR/tiddlers/images/green_favicon.png +0 -0
  93. package/editions/ko-KR/tiddlers/images/{green_favicon.ico.meta → green_favicon.png.meta} +1 -1
  94. package/editions/ko-KR-server/tiddlers/system/favicon.png +0 -0
  95. package/editions/ko-KR-server/tiddlers/system/favicon.png.meta +2 -0
  96. package/editions/pluginlibrary/tiddlywiki.info +2 -2
  97. package/editions/prerelease/tiddlers/{Release 5.3.2.tid → Release 5.3.3.tid } +23 -25
  98. package/editions/prerelease/tiddlers/system/PrereleaseLocalPluginLibrary.tid +1 -1
  99. package/editions/prerelease/tiddlers/system/PrereleaseOfficialPluginLibrary.tid +1 -1
  100. package/editions/prerelease/tiddlers/system/favicon.png +0 -0
  101. package/editions/prerelease/tiddlers/system/favicon.png.meta +2 -0
  102. package/editions/prerelease/tiddlers/system/temp-my-scroll-position.tid +3 -0
  103. package/editions/resumebuilder/tiddlywiki.info +1 -1
  104. package/editions/server/tiddlywiki.info +1 -1
  105. package/editions/server-external-js/tiddlywiki.info +1 -1
  106. package/editions/test/playwright.spec.js +25 -0
  107. package/editions/test/tiddlers/tests/data/conditionals/Basic.tid +26 -0
  108. package/editions/test/tiddlers/tests/data/conditionals/BlockMode.tid +37 -0
  109. package/editions/test/tiddlers/tests/data/conditionals/Else.tid +26 -0
  110. package/editions/test/tiddlers/tests/data/conditionals/Elseif.tid +32 -0
  111. package/editions/test/tiddlers/tests/data/conditionals/MissingEndIf.tid +26 -0
  112. package/editions/test/tiddlers/tests/data/conditionals/MultipleResults.tid +12 -0
  113. package/editions/test/tiddlers/tests/data/conditionals/Nested.tid +38 -0
  114. package/editions/test/tiddlers/tests/data/conditionals/NestedElseif.tid +60 -0
  115. package/editions/test/tiddlers/tests/data/list-widget/WithExplicitTemplates.tid +29 -0
  116. package/editions/test/tiddlers/tests/data/list-widget/WithExplicitTemplatesInBlockMode.tid +32 -0
  117. package/editions/test/tiddlers/tests/data/list-widget/WithExplicitTemplatesOverriddenByAttributes.tid +33 -0
  118. package/editions/test/tiddlers/tests/data/list-widget/WithJoinTemplate.tid +30 -0
  119. package/editions/test/tiddlers/tests/data/list-widget/WithJoinTemplateInBlockMode.tid +32 -0
  120. package/editions/test/tiddlers/tests/data/list-widget/WithLimit.tid +25 -0
  121. package/editions/test/tiddlers/tests/data/list-widget/WithMissingTemplate.tid +26 -0
  122. package/editions/test/tiddlers/tests/data/transclude/CustomWidget-CodeblockOverride-TextParser.tid +20 -0
  123. package/editions/test/tiddlers/tests/data/transclude/Variable-Refreshing.tid +27 -0
  124. package/editions/test/tiddlers/tests/data/transclude/Variable-Static.tid +15 -0
  125. package/editions/test/tiddlers/tests/data/widgets/DataAttributes/ButtonWidget-DataAttributes.tid +27 -0
  126. package/editions/test/tiddlers/tests/data/widgets/DataAttributes/CheckboxWidget-DataAttributes.tid +22 -0
  127. package/editions/test/tiddlers/tests/data/widgets/DataAttributes/DraggableWidget-DataAttributes.tid +27 -0
  128. package/editions/test/tiddlers/tests/data/widgets/DataAttributes/DroppableWidget-DataAttributes.tid +27 -0
  129. package/editions/test/tiddlers/tests/data/widgets/DataAttributes/LinkWidget-DataAttributes.tid +27 -0
  130. package/editions/test/tiddlers/tests/data/widgets/DataAttributes/OrderedStyleAttributes.tid +15 -0
  131. package/editions/test/tiddlers/tests/data/widgets/DataAttributes/SelectWidget-DataAttributes.tid +27 -0
  132. package/editions/test/tiddlers/tests/data/widgets/ElementWidgetEventAttributes.tid +15 -0
  133. package/editions/test/tiddlers/tests/data/widgets/ElementWidgetStyleAttributes.tid +15 -0
  134. package/editions/test/tiddlers/tests/test-filters.js +1 -0
  135. package/editions/test/tiddlers/tests/test-json-filters.js +40 -0
  136. package/editions/test/tiddlers/tests/test-utils.js +23 -0
  137. package/editions/test/tiddlers/tests/test-widget.js +62 -0
  138. package/editions/tw.org/tiddlers/$__favicon.ico.png +0 -0
  139. package/editions/tw.org/tiddlywiki.info +1 -1
  140. package/editions/tw5.com/tiddlers/_tw_shared/favicons/classic.tiddlywiki.com.png +0 -0
  141. package/editions/tw5.com/tiddlers/_tw_shared/favicons/{classic.tiddlywiki.com.ico.meta → classic.tiddlywiki.com.png.meta} +1 -1
  142. package/editions/tw5.com/tiddlers/_tw_shared/favicons/links.tiddlywiki.org.png +0 -0
  143. package/editions/tw5.com/tiddlers/_tw_shared/favicons/{links.tiddlywiki.org.ico.meta → links.tiddlywiki.org.png.meta} +1 -1
  144. package/editions/tw5.com/tiddlers/_tw_shared/favicons/tiddlywiki.com.dev.png +0 -0
  145. package/editions/tw5.com/tiddlers/_tw_shared/favicons/{tiddlywiki.com.dev.ico.meta → tiddlywiki.com.dev.png.meta} +1 -1
  146. package/editions/tw5.com/tiddlers/_tw_shared/favicons/tiddlywiki.com.png +0 -0
  147. package/editions/tw5.com/tiddlers/_tw_shared/favicons/{tiddlywiki.com.ico.meta → tiddlywiki.com.png.meta} +1 -1
  148. package/editions/tw5.com/tiddlers/_tw_shared/favicons/tiddlywiki.com.prerelease.png +0 -0
  149. package/editions/tw5.com/tiddlers/_tw_shared/favicons/{tiddlywiki.com.prerelease.ico.meta → tiddlywiki.com.prerelease.png.meta} +1 -1
  150. package/editions/tw5.com/tiddlers/_tw_shared/favicons/tiddlywiki.com.upgrade.png +0 -0
  151. package/editions/tw5.com/tiddlers/_tw_shared/favicons/{tiddlywiki.com.upgrade.ico.meta → tiddlywiki.com.upgrade.png.meta} +1 -1
  152. package/editions/tw5.com/tiddlers/_tw_shared/favicons/tiddlywiki.org.png +0 -0
  153. package/editions/tw5.com/tiddlers/about/Archive.tid +82 -0
  154. package/editions/tw5.com/tiddlers/community/Chinese Community.tid +20 -0
  155. package/editions/tw5.com/tiddlers/community/editions/Tidme by oflg.tid +16 -0
  156. package/editions/tw5.com/tiddlers/community/plugins/FSRS4TW by oflg.tid +10 -0
  157. package/editions/tw5.com/tiddlers/community/resources/_Timimi_ Extension and executable by Riz.tid +3 -1
  158. package/editions/tw5.com/tiddlers/concepts/Macros.tid +7 -3
  159. package/editions/tw5.com/tiddlers/concepts/Title List.tid +5 -1
  160. package/editions/tw5.com/tiddlers/filters/decodebase64 Operator.tid +6 -1
  161. package/editions/tw5.com/tiddlers/filters/encodebase64 Operator.tid +6 -1
  162. package/editions/tw5.com/tiddlers/filters/examples/jsonset.tid +59 -0
  163. package/editions/tw5.com/tiddlers/filters/examples/jsonstringify Operator (Examples).tid +7 -5
  164. package/editions/tw5.com/tiddlers/filters/examples/stringify_Operator_(Examples).tid +5 -3
  165. package/editions/tw5.com/tiddlers/filters/jsonextract.tid +8 -0
  166. package/editions/tw5.com/tiddlers/filters/jsonget.tid +8 -0
  167. package/editions/tw5.com/tiddlers/filters/jsonset.tid +64 -0
  168. package/editions/tw5.com/tiddlers/filters/jsonstringify Operator.tid +14 -15
  169. package/editions/tw5.com/tiddlers/filters/jsontype.tid +8 -0
  170. package/editions/tw5.com/tiddlers/filters/stringify_Operator.tid +12 -15
  171. package/editions/tw5.com/tiddlers/filters/syntax/Filter Expression.tid +1 -1
  172. package/editions/tw5.com/tiddlers/hellothere/HelloThere.tid +6 -1
  173. package/editions/tw5.com/tiddlers/howtos/Constructing JSON tiddlers.tid +3 -3
  174. package/editions/tw5.com/tiddlers/images/Favicon template.svg +296 -0
  175. package/editions/tw5.com/tiddlers/images/Favicon template.svg.meta +3 -0
  176. package/editions/tw5.com/tiddlers/images/New Release Banner.png +0 -0
  177. package/editions/tw5.com/tiddlers/images/favicon.png +0 -0
  178. package/editions/tw5.com/tiddlers/images/favicon.png.meta +2 -0
  179. package/editions/tw5.com/tiddlers/images/green_favicon.png +0 -0
  180. package/editions/tw5.com/tiddlers/images/green_favicon.png.meta +2 -0
  181. package/editions/tw5.com/tiddlers/macros/CoreMacros.tid +1 -1
  182. package/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-open-window.tid +12 -5
  183. package/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-permalink.tid +1 -1
  184. package/editions/tw5.com/tiddlers/pragmas/Pragma_ _whitespace.tid +7 -3
  185. package/editions/tw5.com/tiddlers/procedures/Procedure Definitions.tid +3 -1
  186. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.0.tid +1 -0
  187. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.1.tid +1 -0
  188. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.10.tid +1 -0
  189. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.11.tid +1 -0
  190. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.12.tid +1 -0
  191. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.13.tid +1 -0
  192. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.14.tid +1 -0
  193. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.15.tid +1 -0
  194. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.16.tid +1 -0
  195. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.17.tid +1 -0
  196. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.18.tid +1 -0
  197. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.19.tid +1 -0
  198. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.2.tid +1 -0
  199. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.20.tid +1 -0
  200. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.21.tid +1 -0
  201. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.22.tid +1 -0
  202. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.23.tid +1 -0
  203. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.3.tid +1 -0
  204. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.4.tid +1 -0
  205. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.5.tid +1 -0
  206. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.6.tid +1 -0
  207. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.7.tid +1 -0
  208. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.8.tid +1 -0
  209. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.9.tid +1 -0
  210. package/editions/tw5.com/tiddlers/releasenotes/Release 5.2.0.tid +1 -0
  211. package/editions/tw5.com/tiddlers/releasenotes/Release 5.2.1.tid +1 -0
  212. package/editions/tw5.com/tiddlers/releasenotes/Release 5.2.2.tid +1 -0
  213. package/editions/tw5.com/tiddlers/releasenotes/Release 5.2.3.tid +1 -0
  214. package/editions/tw5.com/tiddlers/releasenotes/Release 5.2.4.tid +1 -0
  215. package/editions/tw5.com/tiddlers/releasenotes/Release 5.2.5.tid +1 -0
  216. package/editions/tw5.com/tiddlers/releasenotes/Release 5.2.6.tid +1 -0
  217. package/editions/tw5.com/tiddlers/releasenotes/Release 5.2.7.tid +1 -0
  218. package/editions/tw5.com/tiddlers/releasenotes/Release 5.3.0.tid +1 -0
  219. package/editions/tw5.com/tiddlers/releasenotes/Release 5.3.1.tid +8 -1
  220. package/editions/tw5.com/tiddlers/releasenotes/Release 5.3.2.tid +184 -0
  221. package/editions/tw5.com/tiddlers/releasenotes/Releases.tid +3 -1
  222. package/editions/tw5.com/tiddlers/system/tw5.com-styles.tid +5 -0
  223. package/editions/tw5.com/tiddlers/widgets/BrowseWidget.tid +3 -1
  224. package/editions/tw5.com/tiddlers/widgets/ButtonWidget.tid +3 -1
  225. package/editions/tw5.com/tiddlers/widgets/CheckboxWidget.tid +3 -1
  226. package/editions/tw5.com/tiddlers/widgets/Custom Widgets.tid +3 -1
  227. package/editions/tw5.com/tiddlers/widgets/DraggableWidget.tid +3 -2
  228. package/editions/tw5.com/tiddlers/widgets/DroppableWidget.tid +3 -1
  229. package/editions/tw5.com/tiddlers/widgets/GenesisWidget.tid +1 -1
  230. package/editions/tw5.com/tiddlers/widgets/ImageWidget.tid +2 -1
  231. package/editions/tw5.com/tiddlers/widgets/LinkWidget.tid +3 -1
  232. package/editions/tw5.com/tiddlers/widgets/ListWidget.tid +25 -2
  233. package/editions/tw5.com/tiddlers/widgets/RadioWidget.tid +3 -1
  234. package/editions/tw5.com/tiddlers/widgets/RangeWidget.tid +3 -1
  235. package/editions/tw5.com/tiddlers/widgets/ScrollableWidget.tid +27 -2
  236. package/editions/tw5.com/tiddlers/widgets/SelectWidget.tid +4 -1
  237. package/editions/tw5.com/tiddlers/widgets/SetWidget.tid +17 -1
  238. package/editions/tw5.com/tiddlers/widgets/TranscludeWidget.tid +2 -2
  239. package/editions/tw5.com/tiddlers/wikitext/Conditional Shortcut Syntax.tid +62 -0
  240. package/editions/tw5.com/tiddlers/wikitext/Transclusion and Substitution.tid +3 -3
  241. package/editions/tw5.com/tiddlywiki.info +9 -3
  242. package/editions/tw5.com-server/tiddlers/system/tiddlywiki.com.server.png +0 -0
  243. package/editions/tw5.com-server/tiddlers/system/tiddlywiki.com.server.png.meta +2 -0
  244. package/editions/zh-Hans/tiddlers/images/favicon.png +0 -0
  245. package/editions/zh-Hans/tiddlers/images/favicon.png.meta +2 -0
  246. package/editions/zh-Hans/tiddlers/images/green_favicon.png +0 -0
  247. package/editions/zh-Hans/tiddlers/images/green_favicon.png.meta +2 -0
  248. package/editions/zh-Hant/tiddlers/images/favicon.png +0 -0
  249. package/editions/zh-Hant/tiddlers/images/favicon.png.meta +2 -0
  250. package/editions/zh-Hant/tiddlers/images/green_favicon.png +0 -0
  251. package/editions/zh-Hant/tiddlers/images/green_favicon.png.meta +2 -0
  252. package/languages/de-DE/Exporters.multids +1 -1
  253. package/languages/de-DE/Help/commands.tid +2 -2
  254. package/languages/de-DE/Help/server.tid +1 -1
  255. package/languages/de-DE/Types/image_x-icon.tid +1 -1
  256. package/languages/es-ES/Buttons.multids +2 -0
  257. package/languages/es-ES/Fields.multids +4 -0
  258. package/languages/es-ES/Help/listen.tid +1 -1
  259. package/languages/es-ES/Help/savewikifolder.tid +16 -1
  260. package/languages/es-ES/Help/server.tid +1 -1
  261. package/languages/es-ES/Misc.multids +3 -0
  262. package/languages/es-ES/SiteTitle.tid +1 -1
  263. package/languages/pl-PL/Exporters.multids +1 -1
  264. package/languages/pl-PL/Help/commands.tid +1 -1
  265. package/languages/pl-PL/Help/savewikifolder.tid +3 -1
  266. package/languages/pl-PL/Help/server.tid +1 -1
  267. package/languages/zh-Hans/Exporters.multids +1 -1
  268. package/languages/zh-Hans/Help/commands.tid +1 -1
  269. package/languages/zh-Hans/Help/server.tid +1 -1
  270. package/languages/zh-Hans/Types/image_svg_xml.tid +1 -1
  271. package/languages/zh-Hans/Types/image_x-icon.tid +1 -1
  272. package/languages/zh-Hant/Exporters.multids +1 -1
  273. package/languages/zh-Hant/Help/commands.tid +1 -1
  274. package/languages/zh-Hant/Help/server.tid +1 -1
  275. package/languages/zh-Hant/Types/image_svg_xml.tid +1 -1
  276. package/languages/zh-Hant/Types/image_x-icon.tid +1 -1
  277. package/licenses/cla-individual.md +10 -0
  278. package/package.json +4 -1
  279. package/playwright.config.js +46 -0
  280. package/plugins/tiddlywiki/codemirror/styles.tid +5 -0
  281. package/plugins/tiddlywiki/comments/styles.tid +8 -8
  282. package/plugins/tiddlywiki/dynannotate/docs/readme.tid +1 -0
  283. package/plugins/tiddlywiki/dynannotate/modules/dynannotate.js +28 -27
  284. package/plugins/tiddlywiki/evernote/modules/enex-deserializer.js +82 -23
  285. package/plugins/tiddlywiki/evernote/readme.tid +1 -0
  286. package/plugins/tiddlywiki/evernote/samples/sample-enex-with-image.xml.enex +2 -2
  287. package/plugins/tiddlywiki/jasmine/run-wiki-based-tests.js +1 -1
  288. package/plugins/tiddlywiki/qrcode/barcodereader.js +90 -0
  289. package/plugins/tiddlywiki/qrcode/docs/barcodereader.tid +44 -0
  290. package/plugins/tiddlywiki/qrcode/{doc/usage.tid → docs/makeqr.tid} +4 -4
  291. package/plugins/tiddlywiki/qrcode/docs.tid +3 -0
  292. package/plugins/tiddlywiki/qrcode/{MakeContactQR.tid → examples/make/MakeContactQR.tid} +1 -1
  293. package/plugins/tiddlywiki/qrcode/{MakeGenericQR.tid → examples/make/MakeGenericQR.tid} +1 -1
  294. package/plugins/tiddlywiki/qrcode/{MakeWifiQR.tid → examples/make/MakeWifiQR.tid} +1 -1
  295. package/plugins/tiddlywiki/qrcode/examples/make/make.tid +5 -0
  296. package/plugins/tiddlywiki/qrcode/examples/read/BarCodeReader.tid +17 -0
  297. package/plugins/tiddlywiki/qrcode/examples/read/read.tid +5 -0
  298. package/plugins/tiddlywiki/qrcode/examples.tid +3 -0
  299. package/plugins/tiddlywiki/qrcode/files/html5-qrcode/LICENSE +201 -0
  300. package/plugins/tiddlywiki/qrcode/files/html5-qrcode/README.md +398 -0
  301. package/plugins/tiddlywiki/qrcode/files/html5-qrcode/html5-qrcode.min.js +1 -0
  302. package/plugins/tiddlywiki/qrcode/files/tiddlywiki.files +20 -4
  303. package/plugins/tiddlywiki/qrcode/makeqr.js +1 -1
  304. package/plugins/tiddlywiki/qrcode/plugin.info +1 -1
  305. package/plugins/tiddlywiki/qrcode/readme.tid +15 -0
  306. package/plugins/tiddlywiki/tiddlyweb/html-json-skinny-tiddler.tid +0 -1
  307. package/plugins/tiddlywiki/tiddlyweb/html-json-tiddler.tid +1 -2
  308. package/plugins/tiddlywiki/upgrade/UpgradeWizard.tid +2 -2
  309. package/plugins/tiddlywiki/upgrade/favicon.png +0 -0
  310. package/plugins/tiddlywiki/upgrade/favicon.png.meta +2 -0
  311. package/readme.md +1 -1
  312. package/themes/tiddlywiki/vanilla/base.tid +37 -7
  313. package/themes/tiddlywiki/vanilla/settings.multids +1 -1
  314. package/editions/de-AT-server/tiddlers/system/favicon.ico +0 -0
  315. package/editions/dev/tiddlers/images/favicon.ico +0 -0
  316. package/editions/es-ES/tiddlers/images/favicon.ico +0 -0
  317. package/editions/es-ES/tiddlers/images/green_favicon.ico +0 -0
  318. package/editions/es-ES-server/tiddlers/system/favicon.ico +0 -0
  319. package/editions/fr-FR/tiddlers/images/favicon.ico +0 -0
  320. package/editions/fr-FR/tiddlers/images/favicon.ico.meta +0 -2
  321. package/editions/fr-FR/tiddlers/images/green_favicon.ico +0 -0
  322. package/editions/fr-FR-server/tiddlers/system/favicon.ico +0 -0
  323. package/editions/fr-FR-server/tiddlers/system/favicon.ico.meta +0 -2
  324. package/editions/ja-JP/tiddlers/images/favicon.ico +0 -0
  325. package/editions/ja-JP/tiddlers/images/favicon.ico.meta +0 -2
  326. package/editions/ja-JP/tiddlers/images/green_favicon.ico +0 -0
  327. package/editions/ko-KR/tiddlers/images/favicon.ico +0 -0
  328. package/editions/ko-KR/tiddlers/images/favicon.ico.meta +0 -2
  329. package/editions/ko-KR/tiddlers/images/green_favicon.ico +0 -0
  330. package/editions/ko-KR-server/tiddlers/system/favicon.ico +0 -0
  331. package/editions/ko-KR-server/tiddlers/system/favicon.ico.meta +0 -2
  332. package/editions/prerelease/tiddlers/system/favicon.ico +0 -0
  333. package/editions/prerelease/tiddlers/system/favicon.ico.meta +0 -2
  334. package/editions/tw5.com/tiddlers/_tw_shared/favicons/classic.tiddlywiki.com.ico +0 -0
  335. package/editions/tw5.com/tiddlers/_tw_shared/favicons/links.tiddlywiki.org.ico +0 -0
  336. package/editions/tw5.com/tiddlers/_tw_shared/favicons/tiddlywiki.com.dev.ico +0 -0
  337. package/editions/tw5.com/tiddlers/_tw_shared/favicons/tiddlywiki.com.ico +0 -0
  338. package/editions/tw5.com/tiddlers/_tw_shared/favicons/tiddlywiki.com.prerelease.ico +0 -0
  339. package/editions/tw5.com/tiddlers/_tw_shared/favicons/tiddlywiki.com.upgrade.ico +0 -0
  340. package/editions/tw5.com/tiddlers/_tw_shared/favicons/tiddlywiki.org.ico +0 -0
  341. package/editions/tw5.com/tiddlers/community/editions/TiddlyMemo by oflg.tid +0 -16
  342. package/editions/tw5.com/tiddlers/community/tutorials/Install and run TiddlyWiki on a CentOS 6 VPS using Nginx.tid +0 -16
  343. package/editions/tw5.com/tiddlers/images/favicon.ico +0 -0
  344. package/editions/tw5.com/tiddlers/images/favicon.ico.meta +0 -2
  345. package/editions/tw5.com/tiddlers/images/green_favicon.ico +0 -0
  346. package/editions/tw5.com/tiddlers/images/green_favicon.ico.meta +0 -2
  347. package/editions/tw5.com-server/tiddlers/system/favicon.ico +0 -0
  348. package/editions/tw5.com-server/tiddlers/system/favicon.ico.meta +0 -2
  349. package/editions/zh-Hans/tiddlers/images/favicon.ico +0 -0
  350. package/editions/zh-Hans/tiddlers/images/favicon.ico.meta +0 -2
  351. package/editions/zh-Hans/tiddlers/images/green_favicon.ico +0 -0
  352. package/editions/zh-Hans/tiddlers/images/green_favicon.ico.meta +0 -2
  353. package/editions/zh-Hant/tiddlers/images/favicon.ico +0 -0
  354. package/editions/zh-Hant/tiddlers/images/favicon.ico.meta +0 -2
  355. package/editions/zh-Hant/tiddlers/images/green_favicon.ico +0 -0
  356. package/editions/zh-Hant/tiddlers/images/green_favicon.ico.meta +0 -2
  357. package/plugins/tiddlywiki/qrcode/doc/examples.tid +0 -3
  358. package/plugins/tiddlywiki/qrcode/doc/readme.tid +0 -13
  359. package/plugins/tiddlywiki/upgrade/favicon.ico +0 -0
  360. package/plugins/tiddlywiki/upgrade/favicon.ico.meta +0 -2
  361. /package/editions/tw5.com/tiddlers/_tw_shared/favicons/{tiddlywiki.org.ico.meta → tiddlywiki.org.png.meta} +0 -0
  362. /package/plugins/tiddlywiki/qrcode/files/{LICENSE → qrcode/LICENSE} +0 -0
  363. /package/plugins/tiddlywiki/qrcode/files/{README.md → qrcode/README.md} +0 -0
  364. /package/plugins/tiddlywiki/qrcode/files/{qrcode.js → qrcode/qrcode.js} +0 -0
@@ -58,24 +58,25 @@ ImageWidget.prototype.render = function(parent,nextSibling) {
58
58
  if(this.wiki.isImageTiddler(this.imageSource)) {
59
59
  var type = tiddler.fields.type,
60
60
  text = tiddler.fields.text,
61
- _canonical_uri = tiddler.fields._canonical_uri;
61
+ _canonical_uri = tiddler.fields._canonical_uri,
62
+ typeInfo = $tw.config.contentTypeInfo[type] || {},
63
+ deserializerType = typeInfo.deserializerType || type;
62
64
  // If the tiddler has body text then it doesn't need to be lazily loaded
63
65
  if(text) {
64
- // Render the appropriate element for the image type
65
- switch(type) {
66
- case "application/pdf":
66
+ // Render the appropriate element for the image type by looking up the encoding in the content type info
67
+ var encoding = typeInfo.encoding || "utf8";
68
+ if (encoding === "base64") {
69
+ // .pdf .png .jpg etc.
70
+ src = "data:" + deserializerType + ";base64," + text;
71
+ if (deserializerType === "application/pdf") {
67
72
  tag = "embed";
68
- src = "data:application/pdf;base64," + text;
69
- break;
70
- case "image/svg+xml":
71
- src = "data:image/svg+xml," + encodeURIComponent(text);
72
- break;
73
- default:
74
- src = "data:" + type + ";base64," + text;
75
- break;
73
+ }
74
+ } else {
75
+ // .svg .tid .xml etc.
76
+ src = "data:" + deserializerType + "," + encodeURIComponent(text);
76
77
  }
77
78
  } else if(_canonical_uri) {
78
- switch(type) {
79
+ switch(deserializerType) {
79
80
  case "application/pdf":
80
81
  tag = "embed";
81
82
  src = _canonical_uri;
@@ -99,6 +100,9 @@ ImageWidget.prototype.render = function(parent,nextSibling) {
99
100
  if(this.imageClass) {
100
101
  domNode.setAttribute("class",this.imageClass);
101
102
  }
103
+ if(this.imageUsemap) {
104
+ domNode.setAttribute("usemap",this.imageUsemap);
105
+ }
102
106
  if(this.imageWidth) {
103
107
  domNode.setAttribute("width",this.imageWidth);
104
108
  }
@@ -138,6 +142,7 @@ ImageWidget.prototype.execute = function() {
138
142
  this.imageWidth = this.getAttribute("width");
139
143
  this.imageHeight = this.getAttribute("height");
140
144
  this.imageClass = this.getAttribute("class");
145
+ this.imageUsemap = this.getAttribute("usemap");
141
146
  this.imageTooltip = this.getAttribute("tooltip");
142
147
  this.imageAlt = this.getAttribute("alt");
143
148
  this.lazyLoading = this.getAttribute("loading");
@@ -148,7 +153,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
148
153
  */
149
154
  ImageWidget.prototype.refresh = function(changedTiddlers) {
150
155
  var changedAttributes = this.computeAttributes();
151
- if(changedAttributes.source || changedAttributes.width || changedAttributes.height || changedAttributes["class"] || changedAttributes.tooltip || changedTiddlers[this.imageSource]) {
156
+ if(changedAttributes.source || changedAttributes.width || changedAttributes.height || changedAttributes["class"] || changedAttributes.usemap || changedAttributes.tooltip || changedTiddlers[this.imageSource]) {
152
157
  this.refreshSelf();
153
158
  return true;
154
159
  } else {
@@ -43,6 +43,11 @@ LinkWidget.prototype.render = function(parent,nextSibling) {
43
43
  } else {
44
44
  // Just insert the link text
45
45
  var domNode = this.document.createElement("span");
46
+ // Assign data- attributes
47
+ this.assignAttributes(domNode,{
48
+ sourcePrefix: "data-",
49
+ destPrefix: "data-"
50
+ });
46
51
  parent.insertBefore(domNode,nextSibling);
47
52
  this.renderChildren(domNode,null);
48
53
  this.domNodes.push(domNode);
@@ -138,6 +143,11 @@ LinkWidget.prototype.renderLink = function(parent,nextSibling) {
138
143
  widget: this
139
144
  });
140
145
  }
146
+ // Assign data- attributes
147
+ this.assignAttributes(domNode,{
148
+ sourcePrefix: "data-",
149
+ destPrefix: "data-"
150
+ });
141
151
  // Insert the link into the DOM and render any children
142
152
  parent.insertBefore(domNode,nextSibling);
143
153
  this.renderChildren(domNode,null);
@@ -207,8 +217,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
207
217
  */
208
218
  LinkWidget.prototype.refresh = function(changedTiddlers) {
209
219
  var changedAttributes = this.computeAttributes();
210
- if(changedAttributes.to || changedTiddlers[this.to] || changedAttributes["aria-label"] || changedAttributes.tooltip ||
211
- changedAttributes["class"] || changedAttributes.tabindex || changedAttributes.draggable || changedAttributes.tag) {
220
+ if($tw.utils.count(changedAttributes) > 0) {
212
221
  this.refreshSelf();
213
222
  return true;
214
223
  }
@@ -218,3 +227,4 @@ LinkWidget.prototype.refresh = function(changedTiddlers) {
218
227
  exports.link = LinkWidget;
219
228
 
220
229
  })();
230
+
@@ -28,6 +28,18 @@ Inherit from the base widget class
28
28
  */
29
29
  ListWidget.prototype = new Widget();
30
30
 
31
+ ListWidget.prototype.initialise = function(parseTreeNode,options) {
32
+ // Bail if parseTreeNode is undefined, meaning that the ListWidget constructor was called without any arguments so that it can be subclassed
33
+ if(parseTreeNode === undefined) {
34
+ return;
35
+ }
36
+ // First call parent constructor to set everything else up
37
+ Widget.prototype.initialise.call(this,parseTreeNode,options);
38
+ // Now look for <$list-template> and <$list-empty> widgets as immediate child widgets
39
+ // This is safe to do during initialization because parse trees never change after creation
40
+ this.findExplicitTemplates();
41
+ }
42
+
31
43
  /*
32
44
  Render this widget into the DOM
33
45
  */
@@ -38,8 +50,8 @@ ListWidget.prototype.render = function(parent,nextSibling) {
38
50
  $tw.modules.applyMethods("storyview",this.storyViews);
39
51
  }
40
52
  this.parentDomNode = parent;
41
- this.computeAttributes();
42
- this.execute();
53
+ var changedAttributes = this.computeAttributes();
54
+ this.execute(changedAttributes);
43
55
  this.renderChildren(parent,nextSibling);
44
56
  // Construct the storyview
45
57
  var StoryView = this.storyViews[this.storyViewName];
@@ -59,7 +71,8 @@ ListWidget.prototype.render = function(parent,nextSibling) {
59
71
  /*
60
72
  Compute the internal state of the widget
61
73
  */
62
- ListWidget.prototype.execute = function() {
74
+ ListWidget.prototype.execute = function(changedAttributes) {
75
+ var self = this;
63
76
  // Get our attributes
64
77
  this.template = this.getAttribute("template");
65
78
  this.editTemplate = this.getAttribute("editTemplate");
@@ -67,6 +80,10 @@ ListWidget.prototype.execute = function() {
67
80
  this.counterName = this.getAttribute("counter");
68
81
  this.storyViewName = this.getAttribute("storyview");
69
82
  this.historyTitle = this.getAttribute("history");
83
+ // Create join template only if needed
84
+ if(this.join === undefined || (changedAttributes && changedAttributes.join)) {
85
+ this.join = this.makeJoinTemplate();
86
+ }
70
87
  // Compose the list elements
71
88
  this.list = this.getTiddlerList();
72
89
  var members = [],
@@ -85,18 +102,54 @@ ListWidget.prototype.execute = function() {
85
102
  this.history = [];
86
103
  };
87
104
 
105
+ ListWidget.prototype.findExplicitTemplates = function() {
106
+ var self = this;
107
+ this.explicitListTemplate = null;
108
+ this.explicitEmptyTemplate = null;
109
+ this.explicitJoinTemplate = null;
110
+ this.hasTemplateInBody = false;
111
+ var searchChildren = function(childNodes) {
112
+ $tw.utils.each(childNodes,function(node) {
113
+ if(node.type === "list-template") {
114
+ self.explicitListTemplate = node.children;
115
+ } else if(node.type === "list-empty") {
116
+ self.explicitEmptyTemplate = node.children;
117
+ } else if(node.type === "list-join") {
118
+ self.explicitJoinTemplate = node.children;
119
+ } else if(node.type === "element" && node.tag === "p") {
120
+ searchChildren(node.children);
121
+ } else {
122
+ self.hasTemplateInBody = true;
123
+ }
124
+ });
125
+ };
126
+ searchChildren(this.parseTreeNode.children);
127
+ }
128
+
88
129
  ListWidget.prototype.getTiddlerList = function() {
130
+ var limit = $tw.utils.getInt(this.getAttribute("limit",""),undefined);
89
131
  var defaultFilter = "[!is[system]sort[title]]";
90
- return this.wiki.filterTiddlers(this.getAttribute("filter",defaultFilter),this);
132
+ var results = this.wiki.filterTiddlers(this.getAttribute("filter",defaultFilter),this);
133
+ if(limit !== undefined) {
134
+ if(limit >= 0) {
135
+ results = results.slice(0,limit);
136
+ } else {
137
+ results = results.slice(limit);
138
+ }
139
+ }
140
+ return results;
91
141
  };
92
142
 
93
143
  ListWidget.prototype.getEmptyMessage = function() {
94
144
  var parser,
95
- emptyMessage = this.getAttribute("emptyMessage","");
96
- // this.wiki.parseText() calls
97
- // new Parser(..), which should only be done, if needed, because it's heavy!
98
- if (emptyMessage === "") {
99
- return [];
145
+ emptyMessage = this.getAttribute("emptyMessage");
146
+ // If emptyMessage attribute is not present or empty then look for an explicit empty template
147
+ if(!emptyMessage) {
148
+ if(this.explicitEmptyTemplate) {
149
+ return this.explicitEmptyTemplate;
150
+ } else {
151
+ return [];
152
+ }
100
153
  }
101
154
  parser = this.wiki.parseText("text/vnd.tiddlywiki",emptyMessage,{parseAsInline: true});
102
155
  if(parser) {
@@ -106,6 +159,24 @@ ListWidget.prototype.getEmptyMessage = function() {
106
159
  }
107
160
  };
108
161
 
162
+ /*
163
+ Compose the template for a join between list items
164
+ */
165
+ ListWidget.prototype.makeJoinTemplate = function() {
166
+ var parser,
167
+ join = this.getAttribute("join","");
168
+ if(join) {
169
+ parser = this.wiki.parseText("text/vnd.tiddlywiki",join,{parseAsInline:true})
170
+ if(parser) {
171
+ return parser.tree;
172
+ } else {
173
+ return [];
174
+ }
175
+ } else {
176
+ return this.explicitJoinTemplate; // May be null, and that's fine
177
+ }
178
+ };
179
+
109
180
  /*
110
181
  Compose the template for a list item
111
182
  */
@@ -114,6 +185,7 @@ ListWidget.prototype.makeItemTemplate = function(title,index) {
114
185
  var tiddler = this.wiki.getTiddler(title),
115
186
  isDraft = tiddler && tiddler.hasField("draft.of"),
116
187
  template = this.template,
188
+ join = this.join,
117
189
  templateTree;
118
190
  if(isDraft && this.editTemplate) {
119
191
  template = this.editTemplate;
@@ -122,22 +194,29 @@ ListWidget.prototype.makeItemTemplate = function(title,index) {
122
194
  if(template) {
123
195
  templateTree = [{type: "transclude", attributes: {tiddler: {type: "string", value: template}}}];
124
196
  } else {
197
+ // Check for child nodes of the list widget
125
198
  if(this.parseTreeNode.children && this.parseTreeNode.children.length > 0) {
126
- templateTree = this.parseTreeNode.children;
127
- } else {
199
+ // Check for a <$list-item> widget
200
+ if(this.explicitListTemplate) {
201
+ templateTree = this.explicitListTemplate;
202
+ } else if(this.hasTemplateInBody) {
203
+ templateTree = this.parseTreeNode.children;
204
+ }
205
+ }
206
+ if(!templateTree || templateTree.length === 0) {
128
207
  // Default template is a link to the title
129
208
  templateTree = [{type: "element", tag: this.parseTreeNode.isBlock ? "div" : "span", children: [{type: "link", attributes: {to: {type: "string", value: title}}, children: [
130
- {type: "text", text: title}
209
+ {type: "text", text: title}
131
210
  ]}]}];
132
211
  }
133
212
  }
134
213
  // Return the list item
135
- var parseTreeNode = {type: "listitem", itemTitle: title, variableName: this.variableName, children: templateTree};
214
+ var parseTreeNode = {type: "listitem", itemTitle: title, variableName: this.variableName, children: templateTree, join: join};
215
+ parseTreeNode.isLast = index === this.list.length - 1;
136
216
  if(this.counterName) {
137
217
  parseTreeNode.counter = (index + 1).toString();
138
218
  parseTreeNode.counterName = this.counterName;
139
219
  parseTreeNode.isFirst = index === 0;
140
- parseTreeNode.isLast = index === this.list.length - 1;
141
220
  }
142
221
  return parseTreeNode;
143
222
  };
@@ -153,7 +232,7 @@ ListWidget.prototype.refresh = function(changedTiddlers) {
153
232
  this.storyview.refreshStart(changedTiddlers,changedAttributes);
154
233
  }
155
234
  // Completely refresh if any of our attributes have changed
156
- if(changedAttributes.filter || changedAttributes.variable || changedAttributes.counter || changedAttributes.template || changedAttributes.editTemplate || changedAttributes.emptyMessage || changedAttributes.storyview || changedAttributes.history) {
235
+ if(changedAttributes.filter || changedAttributes.variable || changedAttributes.counter || changedAttributes.template || changedAttributes.editTemplate || changedAttributes.join || changedAttributes.emptyMessage || changedAttributes.storyview || changedAttributes.history) {
157
236
  this.refreshSelf();
158
237
  result = true;
159
238
  } else {
@@ -225,6 +304,8 @@ ListWidget.prototype.handleListChanges = function(changedTiddlers) {
225
304
  // If we are providing an counter variable then we must refresh the items, otherwise we can rearrange them
226
305
  var hasRefreshed = false,t;
227
306
  if(this.counterName) {
307
+ var mustRefreshOldLast = false;
308
+ var oldLength = this.children.length;
228
309
  // Cycle through the list and remove and re-insert the first item that has changed, and all the remaining items
229
310
  for(t=0; t<this.list.length; t++) {
230
311
  if(hasRefreshed || !this.children[t] || this.children[t].parseTreeNode.itemTitle !== this.list[t]) {
@@ -232,6 +313,9 @@ ListWidget.prototype.handleListChanges = function(changedTiddlers) {
232
313
  this.removeListItem(t);
233
314
  }
234
315
  this.insertListItem(t,this.list[t]);
316
+ if(!hasRefreshed && t === oldLength) {
317
+ mustRefreshOldLast = true;
318
+ }
235
319
  hasRefreshed = true;
236
320
  } else {
237
321
  // Refresh the item we're reusing
@@ -239,6 +323,12 @@ ListWidget.prototype.handleListChanges = function(changedTiddlers) {
239
323
  hasRefreshed = hasRefreshed || refreshed;
240
324
  }
241
325
  }
326
+ // If items were inserted then we must recreate the item that used to be at the last position as it is no longer last
327
+ if(mustRefreshOldLast && oldLength > 0) {
328
+ var oldLastIdx = oldLength-1;
329
+ this.removeListItem(oldLastIdx);
330
+ this.insertListItem(oldLastIdx,this.list[oldLastIdx]);
331
+ }
242
332
  // If there are items to remove and we have not refreshed then recreate the item that will now be at the last position
243
333
  if(!hasRefreshed && this.children.length > this.list.length) {
244
334
  this.removeListItem(this.list.length-1);
@@ -246,10 +336,29 @@ ListWidget.prototype.handleListChanges = function(changedTiddlers) {
246
336
  }
247
337
  } else {
248
338
  // Cycle through the list, inserting and removing list items as needed
339
+ var mustRecreateLastItem = false;
340
+ if(this.join && this.join.length) {
341
+ if(this.children.length !== this.list.length) {
342
+ mustRecreateLastItem = true;
343
+ } else if(prevList[prevList.length-1] !== this.list[this.list.length-1]) {
344
+ mustRecreateLastItem = true;
345
+ }
346
+ }
347
+ var isLast = false, wasLast = false;
249
348
  for(t=0; t<this.list.length; t++) {
349
+ isLast = t === this.list.length-1;
250
350
  var index = this.findListItem(t,this.list[t]);
351
+ wasLast = index === this.children.length-1;
352
+ if(wasLast && (index !== t || this.children.length !== this.list.length)) {
353
+ mustRecreateLastItem = !!(this.join && this.join.length);
354
+ }
251
355
  if(index === undefined) {
252
356
  // The list item must be inserted
357
+ if(isLast && mustRecreateLastItem && t>0) {
358
+ // First re-create previosly-last item that will no longer be last
359
+ this.removeListItem(t-1);
360
+ this.insertListItem(t-1,this.list[t-1]);
361
+ }
253
362
  this.insertListItem(t,this.list[t]);
254
363
  hasRefreshed = true;
255
364
  } else {
@@ -258,9 +367,15 @@ ListWidget.prototype.handleListChanges = function(changedTiddlers) {
258
367
  this.removeListItem(n);
259
368
  hasRefreshed = true;
260
369
  }
261
- // Refresh the item we're reusing
262
- var refreshed = this.children[t].refresh(changedTiddlers);
263
- hasRefreshed = hasRefreshed || refreshed;
370
+ // Refresh the item we're reusing, or recreate if necessary
371
+ if(mustRecreateLastItem && (isLast || wasLast)) {
372
+ this.removeListItem(t);
373
+ this.insertListItem(t,this.list[t]);
374
+ hasRefreshed = true;
375
+ } else {
376
+ var refreshed = this.children[t].refresh(changedTiddlers);
377
+ hasRefreshed = hasRefreshed || refreshed;
378
+ }
264
379
  }
265
380
  }
266
381
  }
@@ -350,8 +465,17 @@ ListItemWidget.prototype.execute = function() {
350
465
  this.setVariable(this.parseTreeNode.counterName + "-first",this.parseTreeNode.isFirst ? "yes" : "no");
351
466
  this.setVariable(this.parseTreeNode.counterName + "-last",this.parseTreeNode.isLast ? "yes" : "no");
352
467
  }
468
+ // Add join if needed
469
+ var children = this.parseTreeNode.children,
470
+ join = this.parseTreeNode.join;
471
+ if(join && join.length && !this.parseTreeNode.isLast) {
472
+ children = children.slice(0);
473
+ $tw.utils.each(join,function(joinNode) {
474
+ children.push(joinNode);
475
+ })
476
+ }
353
477
  // Construct the child widgets
354
- this.makeChildWidgets();
478
+ this.makeChildWidgets(children);
355
479
  };
356
480
 
357
481
  /*
@@ -363,4 +487,37 @@ ListItemWidget.prototype.refresh = function(changedTiddlers) {
363
487
 
364
488
  exports.listitem = ListItemWidget;
365
489
 
490
+ /*
491
+ Make <$list-template> and <$list-empty> widgets that do nothing
492
+ */
493
+ var ListTemplateWidget = function(parseTreeNode,options) {
494
+ // Main initialisation inherited from widget.js
495
+ this.initialise(parseTreeNode,options);
496
+ };
497
+ ListTemplateWidget.prototype = new Widget();
498
+ ListTemplateWidget.prototype.render = function() {}
499
+ ListTemplateWidget.prototype.refresh = function() { return false; }
500
+
501
+ exports["list-template"] = ListTemplateWidget;
502
+
503
+ var ListEmptyWidget = function(parseTreeNode,options) {
504
+ // Main initialisation inherited from widget.js
505
+ this.initialise(parseTreeNode,options);
506
+ };
507
+ ListEmptyWidget.prototype = new Widget();
508
+ ListEmptyWidget.prototype.render = function() {}
509
+ ListEmptyWidget.prototype.refresh = function() { return false; }
510
+
511
+ exports["list-empty"] = ListEmptyWidget;
512
+
513
+ var ListJoinWidget = function(parseTreeNode,options) {
514
+ // Main initialisation inherited from widget.js
515
+ this.initialise(parseTreeNode,options);
516
+ };
517
+ ListJoinWidget.prototype = new Widget();
518
+ ListJoinWidget.prototype.render = function() {}
519
+ ListJoinWidget.prototype.refresh = function() { return false; }
520
+
521
+ exports["list-join"] = ListJoinWidget;
522
+
366
523
  })();
@@ -40,6 +40,10 @@ RadioWidget.prototype.render = function(parent,nextSibling) {
40
40
  );
41
41
  this.inputDomNode = this.document.createElement("input");
42
42
  this.inputDomNode.setAttribute("type","radio");
43
+ this.assignAttributes(this.inputDomNode,{
44
+ sourcePrefix: "data-",
45
+ destPrefix: "data-"
46
+ });
43
47
  if(isChecked) {
44
48
  this.inputDomNode.checked = true;
45
49
  }
@@ -50,6 +50,10 @@ RangeWidget.prototype.render = function(parent,nextSibling) {
50
50
  this.inputDomNode.setAttribute("disabled",true);
51
51
  }
52
52
  this.inputDomNode.value = this.getValue();
53
+ this.assignAttributes(this.inputDomNode,{
54
+ sourcePrefix: "data-",
55
+ destPrefix: "data-"
56
+ });
53
57
  // Add a click event handler
54
58
  $tw.utils.addEventListeners(this.inputDomNode,[
55
59
  {name:"mousedown", handlerObject:this, handlerMethod:"handleMouseDownEvent"},
@@ -12,6 +12,8 @@ Scrollable widget
12
12
  /*global $tw: false */
13
13
  "use strict";
14
14
 
15
+ var DEBOUNCE_INTERVAL = 100; // Delay after last scroll event before updating the bound tiddler
16
+
15
17
  var Widget = require("$:/core/modules/widgets/widget.js").widget;
16
18
 
17
19
  var ScrollableWidget = function(parseTreeNode,options) {
@@ -171,6 +173,53 @@ ScrollableWidget.prototype.render = function(parent,nextSibling) {
171
173
  parent.insertBefore(this.outerDomNode,nextSibling);
172
174
  this.renderChildren(this.innerDomNode,null);
173
175
  this.domNodes.push(this.outerDomNode);
176
+ // If the scroll position is bound to a tiddler
177
+ if(this.scrollableBind) {
178
+ // After a delay for rendering, scroll to the bound position
179
+ this.updateScrollPositionFromBoundTiddler();
180
+ // Set up event listener
181
+ this.currentListener = this.listenerFunction.bind(this);
182
+ this.outerDomNode.addEventListener("scroll", this.currentListener);
183
+ }
184
+ };
185
+
186
+ ScrollableWidget.prototype.listenerFunction = function(event) {
187
+ self = this;
188
+ clearTimeout(this.timeout);
189
+ this.timeout = setTimeout(function() {
190
+ var existingTiddler = self.wiki.getTiddler(self.scrollableBind),
191
+ newTiddlerFields = {
192
+ title: self.scrollableBind,
193
+ "scroll-left": self.outerDomNode.scrollLeft.toString(),
194
+ "scroll-top": self.outerDomNode.scrollTop.toString()
195
+ };
196
+ if(!existingTiddler || (existingTiddler.fields["title"] !== newTiddlerFields["title"]) || (existingTiddler.fields["scroll-left"] !== newTiddlerFields["scroll-left"] || existingTiddler.fields["scroll-top"] !== newTiddlerFields["scroll-top"])) {
197
+ self.wiki.addTiddler(new $tw.Tiddler(existingTiddler,newTiddlerFields));
198
+ }
199
+ }, DEBOUNCE_INTERVAL);
200
+ }
201
+
202
+ ScrollableWidget.prototype.updateScrollPositionFromBoundTiddler = function() {
203
+ // Bail if we're running on the fakedom
204
+ if(!this.outerDomNode.scrollTo) {
205
+ return;
206
+ }
207
+ var tiddler = this.wiki.getTiddler(this.scrollableBind);
208
+ if(tiddler) {
209
+ var scrollLeftTo = this.outerDomNode.scrollLeft;
210
+ if(parseFloat(tiddler.fields["scroll-left"]).toString() === tiddler.fields["scroll-left"]) {
211
+ scrollLeftTo = parseFloat(tiddler.fields["scroll-left"]);
212
+ }
213
+ var scrollTopTo = this.outerDomNode.scrollTop;
214
+ if(parseFloat(tiddler.fields["scroll-top"]).toString() === tiddler.fields["scroll-top"]) {
215
+ scrollTopTo = parseFloat(tiddler.fields["scroll-top"]);
216
+ }
217
+ this.outerDomNode.scrollTo({
218
+ top: scrollTopTo,
219
+ left: scrollLeftTo,
220
+ behavior: "instant"
221
+ })
222
+ }
174
223
  };
175
224
 
176
225
  /*
@@ -178,6 +227,7 @@ Compute the internal state of the widget
178
227
  */
179
228
  ScrollableWidget.prototype.execute = function() {
180
229
  // Get attributes
230
+ this.scrollableBind = this.getAttribute("bind");
181
231
  this.fallthrough = this.getAttribute("fallthrough","yes");
182
232
  this["class"] = this.getAttribute("class");
183
233
  // Make child widgets
@@ -193,7 +243,22 @@ ScrollableWidget.prototype.refresh = function(changedTiddlers) {
193
243
  this.refreshSelf();
194
244
  return true;
195
245
  }
196
- return this.refreshChildren(changedTiddlers);
246
+ // If the bound tiddler has changed, update the eventListener and update scroll position
247
+ if(changedAttributes["bind"]) {
248
+ if(this.currentListener) {
249
+ this.outerDomNode.removeEventListener("scroll", this.currentListener, false);
250
+ }
251
+ this.scrollableBind = this.getAttribute("bind");
252
+ this.currentListener = this.listenerFunction.bind(this);
253
+ this.outerDomNode.addEventListener("scroll", this.currentListener);
254
+ }
255
+ // Refresh children
256
+ var result = this.refreshChildren(changedTiddlers);
257
+ // If the bound tiddler has changed, update scroll position
258
+ if(changedAttributes["bind"] || changedTiddlers[this.getAttribute("bind")]) {
259
+ this.updateScrollPositionFromBoundTiddler();
260
+ }
261
+ return result;
197
262
  };
198
263
 
199
264
  exports.scrollable = ScrollableWidget;
@@ -40,7 +40,31 @@ SelectWidget.prototype.render = function(parent,nextSibling) {
40
40
  this.parentDomNode = parent;
41
41
  this.computeAttributes();
42
42
  this.execute();
43
- this.renderChildren(parent,nextSibling);
43
+ //Create element
44
+ var domNode = this.document.createElement("select");
45
+ if(this.selectClass) {
46
+ domNode.classname = this.selectClass;
47
+ }
48
+ // Assign data- attributes
49
+ this.assignAttributes(domNode,{
50
+ sourcePrefix: "data-",
51
+ destPrefix: "data-"
52
+ });
53
+ if(this.selectMultiple) {
54
+ domNode.setAttribute("multiple","multiple");
55
+ }
56
+ if(this.selectSize) {
57
+ domNode.setAttribute("size",this.selectSize);
58
+ }
59
+ if(this.selectTabindex) {
60
+ domNode.setAttribute("tabindex",this.selectTabindex);
61
+ }
62
+ if(this.selectTooltip) {
63
+ domNode.setAttribute("title",this.selectTooltip);
64
+ }
65
+ this.renderChildren(domNode,nextSibling);
66
+ this.parentDomNode.insertBefore(domNode,nextSibling);
67
+ this.domNodes.push(domNode);
44
68
  this.setSelectValue();
45
69
  if(this.selectFocus == "yes") {
46
70
  this.getSelectDomNode().focus();
@@ -113,7 +137,7 @@ SelectWidget.prototype.setSelectValue = function() {
113
137
  Get the DOM node of the select element
114
138
  */
115
139
  SelectWidget.prototype.getSelectDomNode = function() {
116
- return this.children[0].domNodes[0];
140
+ return this.domNodes[0];
117
141
  };
118
142
 
119
143
  // Return an array of the selected opion values
@@ -149,27 +173,7 @@ SelectWidget.prototype.execute = function() {
149
173
  this.selectTooltip = this.getAttribute("tooltip");
150
174
  this.selectFocus = this.getAttribute("focus");
151
175
  // Make the child widgets
152
- var selectNode = {
153
- type: "element",
154
- tag: "select",
155
- children: this.parseTreeNode.children
156
- };
157
- if(this.selectClass) {
158
- $tw.utils.addAttributeToParseTreeNode(selectNode,"class",this.selectClass);
159
- }
160
- if(this.selectMultiple) {
161
- $tw.utils.addAttributeToParseTreeNode(selectNode,"multiple","multiple");
162
- }
163
- if(this.selectSize) {
164
- $tw.utils.addAttributeToParseTreeNode(selectNode,"size",this.selectSize);
165
- }
166
- if(this.selectTabindex) {
167
- $tw.utils.addAttributeToParseTreeNode(selectNode,"tabindex",this.selectTabindex);
168
- }
169
- if(this.selectTooltip) {
170
- $tw.utils.addAttributeToParseTreeNode(selectNode,"title",this.selectTooltip);
171
- }
172
- this.makeChildWidgets([selectNode]);
176
+ this.makeChildWidgets();
173
177
  };
174
178
 
175
179
  /*
@@ -178,17 +182,21 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
178
182
  SelectWidget.prototype.refresh = function(changedTiddlers) {
179
183
  var changedAttributes = this.computeAttributes();
180
184
  // If we're using a different tiddler/field/index then completely refresh ourselves
181
- if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes.tooltip) {
185
+ if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes.tooltip || changedAttributes.tabindex) {
182
186
  this.refreshSelf();
183
187
  return true;
184
- // If the target tiddler value has changed, just update setting and refresh the children
185
188
  } else {
186
189
  if(changedAttributes.class) {
187
190
  this.selectClass = this.getAttribute("class");
188
191
  this.getSelectDomNode().setAttribute("class",this.selectClass);
189
192
  }
190
-
193
+ this.assignAttributes(this.getSelectDomNode(),{
194
+ changedAttributes: changedAttributes,
195
+ sourcePrefix: "data-",
196
+ destPrefix: "data-"
197
+ });
191
198
  var childrenRefreshed = this.refreshChildren(changedTiddlers);
199
+ // If the target tiddler value has changed, just update setting and refresh the children
192
200
  if(changedTiddlers[this.selectTitle] || childrenRefreshed) {
193
201
  this.setSelectValue();
194
202
  }