tiddlywiki 5.3.1 → 5.3.3

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 (372) 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 +33 -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 +179 -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 +1 -2
  44. package/core/templates/html-json-tiddler.tid +1 -1
  45. package/core/templates/store.area.template.html.tid +6 -8
  46. package/core/ui/ControlPanel/Basics.tid +2 -2
  47. package/core/ui/EditTemplate/body/default.tid +9 -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 +5 -8
  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.4.tid } +26 -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/WithEmptyParagraphTemplate.tid +13 -0
  116. package/editions/test/tiddlers/tests/data/list-widget/WithExplicitTemplates.tid +29 -0
  117. package/editions/test/tiddlers/tests/data/list-widget/WithExplicitTemplatesInBlockMode.tid +32 -0
  118. package/editions/test/tiddlers/tests/data/list-widget/WithExplicitTemplatesOverriddenByAttributes.tid +33 -0
  119. package/editions/test/tiddlers/tests/data/list-widget/WithJoinTemplate.tid +30 -0
  120. package/editions/test/tiddlers/tests/data/list-widget/WithJoinTemplateInBlockMode.tid +32 -0
  121. package/editions/test/tiddlers/tests/data/list-widget/WithLimit.tid +25 -0
  122. package/editions/test/tiddlers/tests/data/list-widget/WithMissingTemplate.tid +26 -0
  123. package/editions/test/tiddlers/tests/data/pragmas/WhitespaceAfterPragma.tid +64 -0
  124. package/editions/test/tiddlers/tests/data/pragmas/WhitespaceNoPragma.tid +32 -0
  125. package/editions/test/tiddlers/tests/data/transclude/CustomWidget-CodeblockOverride-TextParser.tid +20 -0
  126. package/editions/test/tiddlers/tests/data/transclude/Variable-Refreshing.tid +27 -0
  127. package/editions/test/tiddlers/tests/data/transclude/Variable-Static.tid +15 -0
  128. package/editions/test/tiddlers/tests/data/widgets/DataAttributes/ButtonWidget-DataAttributes.tid +27 -0
  129. package/editions/test/tiddlers/tests/data/widgets/DataAttributes/CheckboxWidget-DataAttributes.tid +22 -0
  130. package/editions/test/tiddlers/tests/data/widgets/DataAttributes/DraggableWidget-DataAttributes.tid +27 -0
  131. package/editions/test/tiddlers/tests/data/widgets/DataAttributes/DroppableWidget-DataAttributes.tid +27 -0
  132. package/editions/test/tiddlers/tests/data/widgets/DataAttributes/LinkWidget-DataAttributes.tid +27 -0
  133. package/editions/test/tiddlers/tests/data/widgets/DataAttributes/OrderedStyleAttributes.tid +15 -0
  134. package/editions/test/tiddlers/tests/data/widgets/DataAttributes/SelectWidget-DataAttributes.tid +27 -0
  135. package/editions/test/tiddlers/tests/data/widgets/ElementWidgetEventAttributes.tid +15 -0
  136. package/editions/test/tiddlers/tests/data/widgets/ElementWidgetStyleAttributes.tid +15 -0
  137. package/editions/test/tiddlers/tests/test-filters.js +1 -0
  138. package/editions/test/tiddlers/tests/test-json-filters.js +40 -0
  139. package/editions/test/tiddlers/tests/test-utils.js +23 -0
  140. package/editions/test/tiddlers/tests/test-widget.js +62 -0
  141. package/editions/tw.org/tiddlers/$__favicon.ico.png +0 -0
  142. package/editions/tw.org/tiddlywiki.info +1 -1
  143. package/editions/tw5.com/tiddlers/_tw_shared/favicons/classic.tiddlywiki.com.png +0 -0
  144. package/editions/tw5.com/tiddlers/_tw_shared/favicons/{classic.tiddlywiki.com.ico.meta → classic.tiddlywiki.com.png.meta} +1 -1
  145. package/editions/tw5.com/tiddlers/_tw_shared/favicons/links.tiddlywiki.org.png +0 -0
  146. package/editions/tw5.com/tiddlers/_tw_shared/favicons/{links.tiddlywiki.org.ico.meta → links.tiddlywiki.org.png.meta} +1 -1
  147. package/editions/tw5.com/tiddlers/_tw_shared/favicons/tiddlywiki.com.dev.png +0 -0
  148. package/editions/tw5.com/tiddlers/_tw_shared/favicons/{tiddlywiki.com.dev.ico.meta → tiddlywiki.com.dev.png.meta} +1 -1
  149. package/editions/tw5.com/tiddlers/_tw_shared/favicons/tiddlywiki.com.png +0 -0
  150. package/editions/tw5.com/tiddlers/_tw_shared/favicons/{tiddlywiki.com.ico.meta → tiddlywiki.com.png.meta} +1 -1
  151. package/editions/tw5.com/tiddlers/_tw_shared/favicons/tiddlywiki.com.prerelease.png +0 -0
  152. package/editions/tw5.com/tiddlers/_tw_shared/favicons/{tiddlywiki.com.prerelease.ico.meta → tiddlywiki.com.prerelease.png.meta} +1 -1
  153. package/editions/tw5.com/tiddlers/_tw_shared/favicons/tiddlywiki.com.upgrade.png +0 -0
  154. package/editions/tw5.com/tiddlers/_tw_shared/favicons/{tiddlywiki.com.upgrade.ico.meta → tiddlywiki.com.upgrade.png.meta} +1 -1
  155. package/editions/tw5.com/tiddlers/_tw_shared/favicons/tiddlywiki.org.png +0 -0
  156. package/editions/tw5.com/tiddlers/about/Archive.tid +82 -0
  157. package/editions/tw5.com/tiddlers/community/Chinese Community.tid +20 -0
  158. package/editions/tw5.com/tiddlers/community/editions/Tidme by oflg.tid +16 -0
  159. package/editions/tw5.com/tiddlers/community/plugins/FSRS4TW by oflg.tid +10 -0
  160. package/editions/tw5.com/tiddlers/community/resources/_Timimi_ Extension and executable by Riz.tid +3 -1
  161. package/editions/tw5.com/tiddlers/concepts/Macros.tid +7 -3
  162. package/editions/tw5.com/tiddlers/concepts/Title List.tid +5 -1
  163. package/editions/tw5.com/tiddlers/filters/decodebase64 Operator.tid +6 -1
  164. package/editions/tw5.com/tiddlers/filters/encodebase64 Operator.tid +6 -1
  165. package/editions/tw5.com/tiddlers/filters/examples/jsonset.tid +59 -0
  166. package/editions/tw5.com/tiddlers/filters/examples/jsonstringify Operator (Examples).tid +7 -5
  167. package/editions/tw5.com/tiddlers/filters/examples/stringify_Operator_(Examples).tid +5 -3
  168. package/editions/tw5.com/tiddlers/filters/jsonextract.tid +8 -0
  169. package/editions/tw5.com/tiddlers/filters/jsonget.tid +8 -0
  170. package/editions/tw5.com/tiddlers/filters/jsonset.tid +64 -0
  171. package/editions/tw5.com/tiddlers/filters/jsonstringify Operator.tid +14 -15
  172. package/editions/tw5.com/tiddlers/filters/jsontype.tid +8 -0
  173. package/editions/tw5.com/tiddlers/filters/stringify_Operator.tid +12 -15
  174. package/editions/tw5.com/tiddlers/filters/syntax/Filter Expression.tid +1 -1
  175. package/editions/tw5.com/tiddlers/hellothere/HelloThere.tid +6 -1
  176. package/editions/tw5.com/tiddlers/howtos/Constructing JSON tiddlers.tid +3 -3
  177. package/editions/tw5.com/tiddlers/images/Favicon template.svg +296 -0
  178. package/editions/tw5.com/tiddlers/images/Favicon template.svg.meta +3 -0
  179. package/editions/tw5.com/tiddlers/images/New Release Banner.png +0 -0
  180. package/editions/tw5.com/tiddlers/images/favicon.png +0 -0
  181. package/editions/tw5.com/tiddlers/images/favicon.png.meta +2 -0
  182. package/editions/tw5.com/tiddlers/images/green_favicon.png +0 -0
  183. package/editions/tw5.com/tiddlers/images/green_favicon.png.meta +2 -0
  184. package/editions/tw5.com/tiddlers/macros/CoreMacros.tid +1 -1
  185. package/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-delete-tiddler.tid +3 -1
  186. package/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-open-window.tid +12 -5
  187. package/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-permalink.tid +1 -1
  188. package/editions/tw5.com/tiddlers/pragmas/Pragma_ _define.tid +3 -1
  189. package/editions/tw5.com/tiddlers/pragmas/Pragma_ _whitespace.tid +7 -3
  190. package/editions/tw5.com/tiddlers/procedures/Procedure Definitions.tid +3 -1
  191. package/editions/tw5.com/tiddlers/releasenotes/BetaReleases.tid +2 -2
  192. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.0.tid +1 -0
  193. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.1.tid +1 -0
  194. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.10.tid +1 -0
  195. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.11.tid +1 -0
  196. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.12.tid +1 -0
  197. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.13.tid +1 -0
  198. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.14.tid +1 -0
  199. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.15.tid +1 -0
  200. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.16.tid +1 -0
  201. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.17.tid +1 -0
  202. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.18.tid +1 -0
  203. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.19.tid +1 -0
  204. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.2.tid +1 -0
  205. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.20.tid +1 -0
  206. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.21.tid +1 -0
  207. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.22.tid +1 -0
  208. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.23.tid +1 -0
  209. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.3.tid +1 -0
  210. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.4.tid +1 -0
  211. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.5.tid +1 -0
  212. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.6.tid +1 -0
  213. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.7.tid +1 -0
  214. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.8.tid +1 -0
  215. package/editions/tw5.com/tiddlers/releasenotes/Release 5.1.9.tid +1 -0
  216. package/editions/tw5.com/tiddlers/releasenotes/Release 5.2.0.tid +1 -0
  217. package/editions/tw5.com/tiddlers/releasenotes/Release 5.2.1.tid +1 -0
  218. package/editions/tw5.com/tiddlers/releasenotes/Release 5.2.2.tid +1 -0
  219. package/editions/tw5.com/tiddlers/releasenotes/Release 5.2.3.tid +1 -0
  220. package/editions/tw5.com/tiddlers/releasenotes/Release 5.2.4.tid +1 -0
  221. package/editions/tw5.com/tiddlers/releasenotes/Release 5.2.5.tid +1 -0
  222. package/editions/tw5.com/tiddlers/releasenotes/Release 5.2.6.tid +1 -0
  223. package/editions/tw5.com/tiddlers/releasenotes/Release 5.2.7.tid +1 -0
  224. package/editions/tw5.com/tiddlers/releasenotes/Release 5.3.0.tid +1 -0
  225. package/editions/tw5.com/tiddlers/releasenotes/Release 5.3.1.tid +8 -1
  226. package/editions/tw5.com/tiddlers/releasenotes/Release 5.3.2.tid +184 -0
  227. package/editions/tw5.com/tiddlers/releasenotes/Release 5.3.3.tid +30 -0
  228. package/editions/tw5.com/tiddlers/releasenotes/Releases.tid +3 -1
  229. package/editions/tw5.com/tiddlers/releasenotes/alpha/AlphaReleases.tid +2 -2
  230. package/editions/tw5.com/tiddlers/system/tw5.com-styles.tid +5 -0
  231. package/editions/tw5.com/tiddlers/widgets/BrowseWidget.tid +3 -1
  232. package/editions/tw5.com/tiddlers/widgets/ButtonWidget.tid +3 -1
  233. package/editions/tw5.com/tiddlers/widgets/CheckboxWidget.tid +3 -1
  234. package/editions/tw5.com/tiddlers/widgets/Custom Widgets.tid +3 -1
  235. package/editions/tw5.com/tiddlers/widgets/DraggableWidget.tid +3 -2
  236. package/editions/tw5.com/tiddlers/widgets/DroppableWidget.tid +3 -1
  237. package/editions/tw5.com/tiddlers/widgets/GenesisWidget.tid +3 -2
  238. package/editions/tw5.com/tiddlers/widgets/ImageWidget.tid +2 -1
  239. package/editions/tw5.com/tiddlers/widgets/LinkWidget.tid +3 -1
  240. package/editions/tw5.com/tiddlers/widgets/ListWidget.tid +25 -2
  241. package/editions/tw5.com/tiddlers/widgets/RadioWidget.tid +3 -1
  242. package/editions/tw5.com/tiddlers/widgets/RangeWidget.tid +3 -1
  243. package/editions/tw5.com/tiddlers/widgets/ScrollableWidget.tid +27 -2
  244. package/editions/tw5.com/tiddlers/widgets/SelectWidget.tid +4 -1
  245. package/editions/tw5.com/tiddlers/widgets/SetWidget.tid +17 -1
  246. package/editions/tw5.com/tiddlers/widgets/TranscludeWidget.tid +2 -2
  247. package/editions/tw5.com/tiddlers/wikitext/Conditional Shortcut Syntax.tid +62 -0
  248. package/editions/tw5.com/tiddlers/wikitext/Transclusion and Substitution.tid +3 -3
  249. package/editions/tw5.com/tiddlywiki.info +9 -3
  250. package/editions/tw5.com-server/tiddlers/system/tiddlywiki.com.server.png +0 -0
  251. package/editions/tw5.com-server/tiddlers/system/tiddlywiki.com.server.png.meta +2 -0
  252. package/editions/zh-Hans/tiddlers/images/favicon.png +0 -0
  253. package/editions/zh-Hans/tiddlers/images/favicon.png.meta +2 -0
  254. package/editions/zh-Hans/tiddlers/images/green_favicon.png +0 -0
  255. package/editions/zh-Hans/tiddlers/images/green_favicon.png.meta +2 -0
  256. package/editions/zh-Hant/tiddlers/images/favicon.png +0 -0
  257. package/editions/zh-Hant/tiddlers/images/favicon.png.meta +2 -0
  258. package/editions/zh-Hant/tiddlers/images/green_favicon.png +0 -0
  259. package/editions/zh-Hant/tiddlers/images/green_favicon.png.meta +2 -0
  260. package/languages/de-DE/Exporters.multids +1 -1
  261. package/languages/de-DE/Help/commands.tid +2 -2
  262. package/languages/de-DE/Help/server.tid +1 -1
  263. package/languages/de-DE/Types/image_x-icon.tid +1 -1
  264. package/languages/es-ES/Buttons.multids +2 -0
  265. package/languages/es-ES/Fields.multids +4 -0
  266. package/languages/es-ES/Help/listen.tid +1 -1
  267. package/languages/es-ES/Help/savewikifolder.tid +16 -1
  268. package/languages/es-ES/Help/server.tid +1 -1
  269. package/languages/es-ES/Misc.multids +3 -0
  270. package/languages/es-ES/SiteTitle.tid +1 -1
  271. package/languages/pl-PL/Exporters.multids +1 -1
  272. package/languages/pl-PL/Help/commands.tid +1 -1
  273. package/languages/pl-PL/Help/savewikifolder.tid +3 -1
  274. package/languages/pl-PL/Help/server.tid +1 -1
  275. package/languages/zh-Hans/Exporters.multids +1 -1
  276. package/languages/zh-Hans/Help/commands.tid +1 -1
  277. package/languages/zh-Hans/Help/server.tid +1 -1
  278. package/languages/zh-Hans/Types/image_svg_xml.tid +1 -1
  279. package/languages/zh-Hans/Types/image_x-icon.tid +1 -1
  280. package/languages/zh-Hant/Exporters.multids +1 -1
  281. package/languages/zh-Hant/Help/commands.tid +1 -1
  282. package/languages/zh-Hant/Help/server.tid +1 -1
  283. package/languages/zh-Hant/Types/image_svg_xml.tid +1 -1
  284. package/languages/zh-Hant/Types/image_x-icon.tid +1 -1
  285. package/licenses/cla-individual.md +12 -0
  286. package/package.json +4 -1
  287. package/playwright.config.js +46 -0
  288. package/plugins/tiddlywiki/codemirror/styles.tid +5 -0
  289. package/plugins/tiddlywiki/comments/styles.tid +8 -8
  290. package/plugins/tiddlywiki/dynannotate/docs/readme.tid +1 -0
  291. package/plugins/tiddlywiki/dynannotate/modules/dynannotate.js +28 -27
  292. package/plugins/tiddlywiki/evernote/modules/enex-deserializer.js +82 -23
  293. package/plugins/tiddlywiki/evernote/readme.tid +1 -0
  294. package/plugins/tiddlywiki/evernote/samples/sample-enex-with-image.xml.enex +2 -2
  295. package/plugins/tiddlywiki/jasmine/run-wiki-based-tests.js +1 -1
  296. package/plugins/tiddlywiki/qrcode/barcodereader.js +90 -0
  297. package/plugins/tiddlywiki/qrcode/docs/barcodereader.tid +44 -0
  298. package/plugins/tiddlywiki/qrcode/{doc/usage.tid → docs/makeqr.tid} +4 -4
  299. package/plugins/tiddlywiki/qrcode/docs.tid +3 -0
  300. package/plugins/tiddlywiki/qrcode/{MakeContactQR.tid → examples/make/MakeContactQR.tid} +1 -1
  301. package/plugins/tiddlywiki/qrcode/{MakeGenericQR.tid → examples/make/MakeGenericQR.tid} +1 -1
  302. package/plugins/tiddlywiki/qrcode/{MakeWifiQR.tid → examples/make/MakeWifiQR.tid} +1 -1
  303. package/plugins/tiddlywiki/qrcode/examples/make/make.tid +5 -0
  304. package/plugins/tiddlywiki/qrcode/examples/read/BarCodeReader.tid +17 -0
  305. package/plugins/tiddlywiki/qrcode/examples/read/read.tid +5 -0
  306. package/plugins/tiddlywiki/qrcode/examples.tid +3 -0
  307. package/plugins/tiddlywiki/qrcode/files/html5-qrcode/LICENSE +201 -0
  308. package/plugins/tiddlywiki/qrcode/files/html5-qrcode/README.md +398 -0
  309. package/plugins/tiddlywiki/qrcode/files/html5-qrcode/html5-qrcode.min.js +1 -0
  310. package/plugins/tiddlywiki/qrcode/files/tiddlywiki.files +20 -4
  311. package/plugins/tiddlywiki/qrcode/makeqr.js +1 -1
  312. package/plugins/tiddlywiki/qrcode/plugin.info +1 -1
  313. package/plugins/tiddlywiki/qrcode/readme.tid +15 -0
  314. package/plugins/tiddlywiki/tiddlyweb/html-json-skinny-tiddler.tid +1 -2
  315. package/plugins/tiddlywiki/tiddlyweb/html-json-tiddler.tid +1 -2
  316. package/plugins/tiddlywiki/upgrade/UpgradeWizard.tid +2 -2
  317. package/plugins/tiddlywiki/upgrade/favicon.png +0 -0
  318. package/plugins/tiddlywiki/upgrade/favicon.png.meta +2 -0
  319. package/readme.md +1 -1
  320. package/themes/tiddlywiki/vanilla/base.tid +37 -7
  321. package/themes/tiddlywiki/vanilla/settings.multids +1 -1
  322. package/editions/de-AT-server/tiddlers/system/favicon.ico +0 -0
  323. package/editions/dev/tiddlers/images/favicon.ico +0 -0
  324. package/editions/es-ES/tiddlers/images/favicon.ico +0 -0
  325. package/editions/es-ES/tiddlers/images/green_favicon.ico +0 -0
  326. package/editions/es-ES-server/tiddlers/system/favicon.ico +0 -0
  327. package/editions/fr-FR/tiddlers/images/favicon.ico +0 -0
  328. package/editions/fr-FR/tiddlers/images/favicon.ico.meta +0 -2
  329. package/editions/fr-FR/tiddlers/images/green_favicon.ico +0 -0
  330. package/editions/fr-FR-server/tiddlers/system/favicon.ico +0 -0
  331. package/editions/fr-FR-server/tiddlers/system/favicon.ico.meta +0 -2
  332. package/editions/ja-JP/tiddlers/images/favicon.ico +0 -0
  333. package/editions/ja-JP/tiddlers/images/favicon.ico.meta +0 -2
  334. package/editions/ja-JP/tiddlers/images/green_favicon.ico +0 -0
  335. package/editions/ko-KR/tiddlers/images/favicon.ico +0 -0
  336. package/editions/ko-KR/tiddlers/images/favicon.ico.meta +0 -2
  337. package/editions/ko-KR/tiddlers/images/green_favicon.ico +0 -0
  338. package/editions/ko-KR-server/tiddlers/system/favicon.ico +0 -0
  339. package/editions/ko-KR-server/tiddlers/system/favicon.ico.meta +0 -2
  340. package/editions/prerelease/tiddlers/system/favicon.ico +0 -0
  341. package/editions/prerelease/tiddlers/system/favicon.ico.meta +0 -2
  342. package/editions/tw5.com/tiddlers/_tw_shared/favicons/classic.tiddlywiki.com.ico +0 -0
  343. package/editions/tw5.com/tiddlers/_tw_shared/favicons/links.tiddlywiki.org.ico +0 -0
  344. package/editions/tw5.com/tiddlers/_tw_shared/favicons/tiddlywiki.com.dev.ico +0 -0
  345. package/editions/tw5.com/tiddlers/_tw_shared/favicons/tiddlywiki.com.ico +0 -0
  346. package/editions/tw5.com/tiddlers/_tw_shared/favicons/tiddlywiki.com.prerelease.ico +0 -0
  347. package/editions/tw5.com/tiddlers/_tw_shared/favicons/tiddlywiki.com.upgrade.ico +0 -0
  348. package/editions/tw5.com/tiddlers/_tw_shared/favicons/tiddlywiki.org.ico +0 -0
  349. package/editions/tw5.com/tiddlers/community/editions/TiddlyMemo by oflg.tid +0 -16
  350. package/editions/tw5.com/tiddlers/community/tutorials/Install and run TiddlyWiki on a CentOS 6 VPS using Nginx.tid +0 -16
  351. package/editions/tw5.com/tiddlers/images/favicon.ico +0 -0
  352. package/editions/tw5.com/tiddlers/images/favicon.ico.meta +0 -2
  353. package/editions/tw5.com/tiddlers/images/green_favicon.ico +0 -0
  354. package/editions/tw5.com/tiddlers/images/green_favicon.ico.meta +0 -2
  355. package/editions/tw5.com-server/tiddlers/system/favicon.ico +0 -0
  356. package/editions/tw5.com-server/tiddlers/system/favicon.ico.meta +0 -2
  357. package/editions/zh-Hans/tiddlers/images/favicon.ico +0 -0
  358. package/editions/zh-Hans/tiddlers/images/favicon.ico.meta +0 -2
  359. package/editions/zh-Hans/tiddlers/images/green_favicon.ico +0 -0
  360. package/editions/zh-Hans/tiddlers/images/green_favicon.ico.meta +0 -2
  361. package/editions/zh-Hant/tiddlers/images/favicon.ico +0 -0
  362. package/editions/zh-Hant/tiddlers/images/favicon.ico.meta +0 -2
  363. package/editions/zh-Hant/tiddlers/images/green_favicon.ico +0 -0
  364. package/editions/zh-Hant/tiddlers/images/green_favicon.ico.meta +0 -2
  365. package/plugins/tiddlywiki/qrcode/doc/examples.tid +0 -3
  366. package/plugins/tiddlywiki/qrcode/doc/readme.tid +0 -13
  367. package/plugins/tiddlywiki/upgrade/favicon.ico +0 -0
  368. package/plugins/tiddlywiki/upgrade/favicon.ico.meta +0 -2
  369. /package/editions/tw5.com/tiddlers/_tw_shared/favicons/{tiddlywiki.org.ico.meta → tiddlywiki.org.png.meta} +0 -0
  370. /package/plugins/tiddlywiki/qrcode/files/{LICENSE → qrcode/LICENSE} +0 -0
  371. /package/plugins/tiddlywiki/qrcode/files/{README.md → qrcode/README.md} +0 -0
  372. /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,57 @@ 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
+ var foundInlineTemplate = false;
113
+ $tw.utils.each(childNodes,function(node) {
114
+ if(node.type === "list-template") {
115
+ self.explicitListTemplate = node.children;
116
+ } else if(node.type === "list-empty") {
117
+ self.explicitEmptyTemplate = node.children;
118
+ } else if(node.type === "list-join") {
119
+ self.explicitJoinTemplate = node.children;
120
+ } else if(node.type === "element" && node.tag === "p") {
121
+ searchChildren(node.children);
122
+ foundInlineTemplate = true;
123
+ } else {
124
+ foundInlineTemplate = true;
125
+ }
126
+ });
127
+ return foundInlineTemplate;
128
+ };
129
+ this.hasTemplateInBody = searchChildren(this.parseTreeNode.children);
130
+ }
131
+
88
132
  ListWidget.prototype.getTiddlerList = function() {
133
+ var limit = $tw.utils.getInt(this.getAttribute("limit",""),undefined);
89
134
  var defaultFilter = "[!is[system]sort[title]]";
90
- return this.wiki.filterTiddlers(this.getAttribute("filter",defaultFilter),this);
135
+ var results = this.wiki.filterTiddlers(this.getAttribute("filter",defaultFilter),this);
136
+ if(limit !== undefined) {
137
+ if(limit >= 0) {
138
+ results = results.slice(0,limit);
139
+ } else {
140
+ results = results.slice(limit);
141
+ }
142
+ }
143
+ return results;
91
144
  };
92
145
 
93
146
  ListWidget.prototype.getEmptyMessage = function() {
94
147
  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 [];
148
+ emptyMessage = this.getAttribute("emptyMessage");
149
+ // If emptyMessage attribute is not present or empty then look for an explicit empty template
150
+ if(!emptyMessage) {
151
+ if(this.explicitEmptyTemplate) {
152
+ return this.explicitEmptyTemplate;
153
+ } else {
154
+ return [];
155
+ }
100
156
  }
101
157
  parser = this.wiki.parseText("text/vnd.tiddlywiki",emptyMessage,{parseAsInline: true});
102
158
  if(parser) {
@@ -106,6 +162,24 @@ ListWidget.prototype.getEmptyMessage = function() {
106
162
  }
107
163
  };
108
164
 
165
+ /*
166
+ Compose the template for a join between list items
167
+ */
168
+ ListWidget.prototype.makeJoinTemplate = function() {
169
+ var parser,
170
+ join = this.getAttribute("join","");
171
+ if(join) {
172
+ parser = this.wiki.parseText("text/vnd.tiddlywiki",join,{parseAsInline:true})
173
+ if(parser) {
174
+ return parser.tree;
175
+ } else {
176
+ return [];
177
+ }
178
+ } else {
179
+ return this.explicitJoinTemplate; // May be null, and that's fine
180
+ }
181
+ };
182
+
109
183
  /*
110
184
  Compose the template for a list item
111
185
  */
@@ -114,6 +188,7 @@ ListWidget.prototype.makeItemTemplate = function(title,index) {
114
188
  var tiddler = this.wiki.getTiddler(title),
115
189
  isDraft = tiddler && tiddler.hasField("draft.of"),
116
190
  template = this.template,
191
+ join = this.join,
117
192
  templateTree;
118
193
  if(isDraft && this.editTemplate) {
119
194
  template = this.editTemplate;
@@ -122,22 +197,29 @@ ListWidget.prototype.makeItemTemplate = function(title,index) {
122
197
  if(template) {
123
198
  templateTree = [{type: "transclude", attributes: {tiddler: {type: "string", value: template}}}];
124
199
  } else {
200
+ // Check for child nodes of the list widget
125
201
  if(this.parseTreeNode.children && this.parseTreeNode.children.length > 0) {
126
- templateTree = this.parseTreeNode.children;
127
- } else {
202
+ // Check for a <$list-item> widget
203
+ if(this.explicitListTemplate) {
204
+ templateTree = this.explicitListTemplate;
205
+ } else if(this.hasTemplateInBody) {
206
+ templateTree = this.parseTreeNode.children;
207
+ }
208
+ }
209
+ if(!templateTree || templateTree.length === 0) {
128
210
  // Default template is a link to the title
129
211
  templateTree = [{type: "element", tag: this.parseTreeNode.isBlock ? "div" : "span", children: [{type: "link", attributes: {to: {type: "string", value: title}}, children: [
130
- {type: "text", text: title}
212
+ {type: "text", text: title}
131
213
  ]}]}];
132
214
  }
133
215
  }
134
216
  // Return the list item
135
- var parseTreeNode = {type: "listitem", itemTitle: title, variableName: this.variableName, children: templateTree};
217
+ var parseTreeNode = {type: "listitem", itemTitle: title, variableName: this.variableName, children: templateTree, join: join};
218
+ parseTreeNode.isLast = index === this.list.length - 1;
136
219
  if(this.counterName) {
137
220
  parseTreeNode.counter = (index + 1).toString();
138
221
  parseTreeNode.counterName = this.counterName;
139
222
  parseTreeNode.isFirst = index === 0;
140
- parseTreeNode.isLast = index === this.list.length - 1;
141
223
  }
142
224
  return parseTreeNode;
143
225
  };
@@ -153,7 +235,7 @@ ListWidget.prototype.refresh = function(changedTiddlers) {
153
235
  this.storyview.refreshStart(changedTiddlers,changedAttributes);
154
236
  }
155
237
  // 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) {
238
+ if(changedAttributes.filter || changedAttributes.variable || changedAttributes.counter || changedAttributes.template || changedAttributes.editTemplate || changedAttributes.join || changedAttributes.emptyMessage || changedAttributes.storyview || changedAttributes.history) {
157
239
  this.refreshSelf();
158
240
  result = true;
159
241
  } else {
@@ -225,6 +307,8 @@ ListWidget.prototype.handleListChanges = function(changedTiddlers) {
225
307
  // If we are providing an counter variable then we must refresh the items, otherwise we can rearrange them
226
308
  var hasRefreshed = false,t;
227
309
  if(this.counterName) {
310
+ var mustRefreshOldLast = false;
311
+ var oldLength = this.children.length;
228
312
  // Cycle through the list and remove and re-insert the first item that has changed, and all the remaining items
229
313
  for(t=0; t<this.list.length; t++) {
230
314
  if(hasRefreshed || !this.children[t] || this.children[t].parseTreeNode.itemTitle !== this.list[t]) {
@@ -232,6 +316,9 @@ ListWidget.prototype.handleListChanges = function(changedTiddlers) {
232
316
  this.removeListItem(t);
233
317
  }
234
318
  this.insertListItem(t,this.list[t]);
319
+ if(!hasRefreshed && t === oldLength) {
320
+ mustRefreshOldLast = true;
321
+ }
235
322
  hasRefreshed = true;
236
323
  } else {
237
324
  // Refresh the item we're reusing
@@ -239,6 +326,12 @@ ListWidget.prototype.handleListChanges = function(changedTiddlers) {
239
326
  hasRefreshed = hasRefreshed || refreshed;
240
327
  }
241
328
  }
329
+ // If items were inserted then we must recreate the item that used to be at the last position as it is no longer last
330
+ if(mustRefreshOldLast && oldLength > 0) {
331
+ var oldLastIdx = oldLength-1;
332
+ this.removeListItem(oldLastIdx);
333
+ this.insertListItem(oldLastIdx,this.list[oldLastIdx]);
334
+ }
242
335
  // If there are items to remove and we have not refreshed then recreate the item that will now be at the last position
243
336
  if(!hasRefreshed && this.children.length > this.list.length) {
244
337
  this.removeListItem(this.list.length-1);
@@ -246,10 +339,29 @@ ListWidget.prototype.handleListChanges = function(changedTiddlers) {
246
339
  }
247
340
  } else {
248
341
  // Cycle through the list, inserting and removing list items as needed
342
+ var mustRecreateLastItem = false;
343
+ if(this.join && this.join.length) {
344
+ if(this.children.length !== this.list.length) {
345
+ mustRecreateLastItem = true;
346
+ } else if(prevList[prevList.length-1] !== this.list[this.list.length-1]) {
347
+ mustRecreateLastItem = true;
348
+ }
349
+ }
350
+ var isLast = false, wasLast = false;
249
351
  for(t=0; t<this.list.length; t++) {
352
+ isLast = t === this.list.length-1;
250
353
  var index = this.findListItem(t,this.list[t]);
354
+ wasLast = index === this.children.length-1;
355
+ if(wasLast && (index !== t || this.children.length !== this.list.length)) {
356
+ mustRecreateLastItem = !!(this.join && this.join.length);
357
+ }
251
358
  if(index === undefined) {
252
359
  // The list item must be inserted
360
+ if(isLast && mustRecreateLastItem && t>0) {
361
+ // First re-create previosly-last item that will no longer be last
362
+ this.removeListItem(t-1);
363
+ this.insertListItem(t-1,this.list[t-1]);
364
+ }
253
365
  this.insertListItem(t,this.list[t]);
254
366
  hasRefreshed = true;
255
367
  } else {
@@ -258,9 +370,15 @@ ListWidget.prototype.handleListChanges = function(changedTiddlers) {
258
370
  this.removeListItem(n);
259
371
  hasRefreshed = true;
260
372
  }
261
- // Refresh the item we're reusing
262
- var refreshed = this.children[t].refresh(changedTiddlers);
263
- hasRefreshed = hasRefreshed || refreshed;
373
+ // Refresh the item we're reusing, or recreate if necessary
374
+ if(mustRecreateLastItem && (isLast || wasLast)) {
375
+ this.removeListItem(t);
376
+ this.insertListItem(t,this.list[t]);
377
+ hasRefreshed = true;
378
+ } else {
379
+ var refreshed = this.children[t].refresh(changedTiddlers);
380
+ hasRefreshed = hasRefreshed || refreshed;
381
+ }
264
382
  }
265
383
  }
266
384
  }
@@ -350,8 +468,17 @@ ListItemWidget.prototype.execute = function() {
350
468
  this.setVariable(this.parseTreeNode.counterName + "-first",this.parseTreeNode.isFirst ? "yes" : "no");
351
469
  this.setVariable(this.parseTreeNode.counterName + "-last",this.parseTreeNode.isLast ? "yes" : "no");
352
470
  }
471
+ // Add join if needed
472
+ var children = this.parseTreeNode.children,
473
+ join = this.parseTreeNode.join;
474
+ if(join && join.length && !this.parseTreeNode.isLast) {
475
+ children = children.slice(0);
476
+ $tw.utils.each(join,function(joinNode) {
477
+ children.push(joinNode);
478
+ })
479
+ }
353
480
  // Construct the child widgets
354
- this.makeChildWidgets();
481
+ this.makeChildWidgets(children);
355
482
  };
356
483
 
357
484
  /*
@@ -363,4 +490,37 @@ ListItemWidget.prototype.refresh = function(changedTiddlers) {
363
490
 
364
491
  exports.listitem = ListItemWidget;
365
492
 
493
+ /*
494
+ Make <$list-template> and <$list-empty> widgets that do nothing
495
+ */
496
+ var ListTemplateWidget = function(parseTreeNode,options) {
497
+ // Main initialisation inherited from widget.js
498
+ this.initialise(parseTreeNode,options);
499
+ };
500
+ ListTemplateWidget.prototype = new Widget();
501
+ ListTemplateWidget.prototype.render = function() {}
502
+ ListTemplateWidget.prototype.refresh = function() { return false; }
503
+
504
+ exports["list-template"] = ListTemplateWidget;
505
+
506
+ var ListEmptyWidget = function(parseTreeNode,options) {
507
+ // Main initialisation inherited from widget.js
508
+ this.initialise(parseTreeNode,options);
509
+ };
510
+ ListEmptyWidget.prototype = new Widget();
511
+ ListEmptyWidget.prototype.render = function() {}
512
+ ListEmptyWidget.prototype.refresh = function() { return false; }
513
+
514
+ exports["list-empty"] = ListEmptyWidget;
515
+
516
+ var ListJoinWidget = function(parseTreeNode,options) {
517
+ // Main initialisation inherited from widget.js
518
+ this.initialise(parseTreeNode,options);
519
+ };
520
+ ListJoinWidget.prototype = new Widget();
521
+ ListJoinWidget.prototype.render = function() {}
522
+ ListJoinWidget.prototype.refresh = function() { return false; }
523
+
524
+ exports["list-join"] = ListJoinWidget;
525
+
366
526
  })();
@@ -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.parentDomNode.insertBefore(domNode,nextSibling);
66
+ this.renderChildren(domNode,null);
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
  }