execonvert 0.4.0

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 (143) hide show
  1. package/CHANGELOG.md +79 -0
  2. package/README.md +194 -0
  3. package/THIRD_PARTY_NOTICES.md +42 -0
  4. package/bin/execonvert.js +21 -0
  5. package/dist/cli/app/public/THIRD_PARTY_NOTICES.md +32 -0
  6. package/dist/cli/app/public/base.elpx +0 -0
  7. package/dist/cli/app/public/exe_math_assets.zip +0 -0
  8. package/dist/cli/app/public/exelearning/app/common/common_i18n.js +79 -0
  9. package/dist/cli/app/public/exelearning/app/common/exe_powered_logo/exe_powered_logo.png +0 -0
  10. package/dist/cli/app/public/exelearning/app/common/i18n/common_i18n.ca.js +79 -0
  11. package/dist/cli/app/public/exelearning/app/common/i18n/common_i18n.de.js +79 -0
  12. package/dist/cli/app/public/exelearning/app/common/i18n/common_i18n.en.js +79 -0
  13. package/dist/cli/app/public/exelearning/app/common/i18n/common_i18n.eo.js +79 -0
  14. package/dist/cli/app/public/exelearning/app/common/i18n/common_i18n.es.js +79 -0
  15. package/dist/cli/app/public/exelearning/app/common/i18n/common_i18n.eu.js +79 -0
  16. package/dist/cli/app/public/exelearning/app/common/i18n/common_i18n.gl.js +79 -0
  17. package/dist/cli/app/public/exelearning/app/common/i18n/common_i18n.it.js +79 -0
  18. package/dist/cli/app/public/exelearning/app/common/i18n/common_i18n.pt.js +79 -0
  19. package/dist/cli/app/public/exelearning/app/common/i18n/common_i18n.ro.js +79 -0
  20. package/dist/cli/app/public/exelearning/app/common/i18n/common_i18n.va.js +79 -0
  21. package/dist/cli/app/public/exelearning/bundles/common.zip +0 -0
  22. package/dist/cli/app/public/exelearning/bundles/content-css.zip +0 -0
  23. package/dist/cli/app/public/exelearning/bundles/idevices.zip +0 -0
  24. package/dist/cli/app/public/exelearning/bundles/libs.zip +0 -0
  25. package/dist/cli/app/public/exelearning/bundles/manifest.json +110 -0
  26. package/dist/cli/app/public/exelearning/bundles/themes/base.zip +0 -0
  27. package/dist/cli/app/public/exelearning/bundles/themes/flux.zip +0 -0
  28. package/dist/cli/app/public/exelearning/bundles/themes/neo.zip +0 -0
  29. package/dist/cli/app/public/exelearning/bundles/themes/nova.zip +0 -0
  30. package/dist/cli/app/public/exelearning/bundles/themes/universal.zip +0 -0
  31. package/dist/cli/app/public/exelearning/bundles/themes/zen.zip +0 -0
  32. package/dist/cli/app/public/exelearning/exporters.bundle.js +12638 -0
  33. package/dist/cli/app/public/exelearning/importers.bundle.js +14061 -0
  34. package/dist/cli/app/public/exelearning/runtime-source.json +10 -0
  35. package/dist/cli/app/public/favicon.svg +11 -0
  36. package/dist/cli/app/public/idevices/text/text.css +16 -0
  37. package/dist/cli/app/public/idevices/text/text.html +3 -0
  38. package/dist/cli/app/public/idevices/text/text.js +291 -0
  39. package/dist/cli/app/public/info/cli.html +955 -0
  40. package/dist/cli/app/public/info/docx.svg +7 -0
  41. package/dist/cli/app/public/info/elpx-icon.png +0 -0
  42. package/dist/cli/app/public/info/exe-old.png +0 -0
  43. package/dist/cli/app/public/info/execonvert-cli-icon.svg +16 -0
  44. package/dist/cli/app/public/info/execonvert-icon.svg +11 -0
  45. package/dist/cli/app/public/info/index.html +723 -0
  46. package/dist/cli/app/public/info/markdown.svg +1 -0
  47. package/dist/cli/app/public/info/pdf.svg +14 -0
  48. package/dist/cli/app/public/libs/exe_math/LICENSE +202 -0
  49. package/dist/cli/app/public/libs/exe_math/a11y/assistive-mml.js +1 -0
  50. package/dist/cli/app/public/libs/exe_math/a11y/complexity.js +1 -0
  51. package/dist/cli/app/public/libs/exe_math/a11y/explorer.js +1 -0
  52. package/dist/cli/app/public/libs/exe_math/a11y/semantic-enrich.js +1 -0
  53. package/dist/cli/app/public/libs/exe_math/a11y/speech.js +1 -0
  54. package/dist/cli/app/public/libs/exe_math/a11y/sre.js +1 -0
  55. package/dist/cli/app/public/libs/exe_math/adaptors/jsdom.js +1 -0
  56. package/dist/cli/app/public/libs/exe_math/adaptors/linkedom.js +1 -0
  57. package/dist/cli/app/public/libs/exe_math/adaptors/liteDOM.js +1 -0
  58. package/dist/cli/app/public/libs/exe_math/core.js +1 -0
  59. package/dist/cli/app/public/libs/exe_math/input/asciimath.js +1 -0
  60. package/dist/cli/app/public/libs/exe_math/input/mml/entities.js +1 -0
  61. package/dist/cli/app/public/libs/exe_math/input/mml/extensions/mml3.js +1 -0
  62. package/dist/cli/app/public/libs/exe_math/input/mml/extensions/mml3.sef.json +1 -0
  63. package/dist/cli/app/public/libs/exe_math/input/mml.js +1 -0
  64. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/action.js +1 -0
  65. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/ams.js +1 -0
  66. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/amscd.js +1 -0
  67. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/autoload.js +1 -0
  68. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/bbm.js +1 -0
  69. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/bboldx.js +1 -0
  70. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/bbox.js +1 -0
  71. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/begingroup.js +1 -0
  72. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/boldsymbol.js +1 -0
  73. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/braket.js +1 -0
  74. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/bussproofs.js +1 -0
  75. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/cancel.js +1 -0
  76. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/cases.js +1 -0
  77. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/centernot.js +1 -0
  78. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/color.js +1 -0
  79. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/colortbl.js +1 -0
  80. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/colorv2.js +1 -0
  81. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/configmacros.js +1 -0
  82. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/dsfont.js +1 -0
  83. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/empheq.js +1 -0
  84. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/enclose.js +1 -0
  85. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/extpfeil.js +1 -0
  86. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/gensymb.js +1 -0
  87. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/html.js +1 -0
  88. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/mathtools.js +1 -0
  89. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/mhchem.js +34 -0
  90. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/newcommand.js +1 -0
  91. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/noerrors.js +1 -0
  92. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/noundefined.js +1 -0
  93. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/physics.js +1 -0
  94. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/require.js +1 -0
  95. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/setoptions.js +1 -0
  96. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/tagformat.js +1 -0
  97. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/texhtml.js +1 -0
  98. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/textcomp.js +1 -0
  99. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/textmacros.js +1 -0
  100. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/unicode.js +1 -0
  101. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/units.js +1 -0
  102. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/upgreek.js +1 -0
  103. package/dist/cli/app/public/libs/exe_math/input/tex/extensions/verb.js +1 -0
  104. package/dist/cli/app/public/libs/exe_math/input/tex-base.js +1 -0
  105. package/dist/cli/app/public/libs/exe_math/input/tex.js +1 -0
  106. package/dist/cli/app/public/libs/exe_math/loader.js +1 -0
  107. package/dist/cli/app/public/libs/exe_math/output/chtml.js +1 -0
  108. package/dist/cli/app/public/libs/exe_math/output/svg.js +1 -0
  109. package/dist/cli/app/public/libs/exe_math/sre/mathmaps/af.json +146 -0
  110. package/dist/cli/app/public/libs/exe_math/sre/mathmaps/base.json +137 -0
  111. package/dist/cli/app/public/libs/exe_math/sre/mathmaps/ca.json +140 -0
  112. package/dist/cli/app/public/libs/exe_math/sre/mathmaps/da.json +140 -0
  113. package/dist/cli/app/public/libs/exe_math/sre/mathmaps/de.json +146 -0
  114. package/dist/cli/app/public/libs/exe_math/sre/mathmaps/en.json +158 -0
  115. package/dist/cli/app/public/libs/exe_math/sre/mathmaps/es.json +140 -0
  116. package/dist/cli/app/public/libs/exe_math/sre/mathmaps/euro.json +32 -0
  117. package/dist/cli/app/public/libs/exe_math/sre/mathmaps/fr.json +146 -0
  118. package/dist/cli/app/public/libs/exe_math/sre/mathmaps/hi.json +146 -0
  119. package/dist/cli/app/public/libs/exe_math/sre/mathmaps/it.json +146 -0
  120. package/dist/cli/app/public/libs/exe_math/sre/mathmaps/ko.json +146 -0
  121. package/dist/cli/app/public/libs/exe_math/sre/mathmaps/nb.json +146 -0
  122. package/dist/cli/app/public/libs/exe_math/sre/mathmaps/nemeth.json +125 -0
  123. package/dist/cli/app/public/libs/exe_math/sre/mathmaps/nn.json +146 -0
  124. package/dist/cli/app/public/libs/exe_math/sre/mathmaps/sv.json +146 -0
  125. package/dist/cli/app/public/libs/exe_math/sre/require.d.mts +1 -0
  126. package/dist/cli/app/public/libs/exe_math/sre/require.mjs +2 -0
  127. package/dist/cli/app/public/libs/exe_math/sre/speech-worker.js +1 -0
  128. package/dist/cli/app/public/libs/exe_math/startup.js +1 -0
  129. package/dist/cli/app/public/libs/exe_math/tex-mml-svg.js +1 -0
  130. package/dist/cli/app/public/libs/exe_math/ui/lazy.js +1 -0
  131. package/dist/cli/app/public/libs/exe_math/ui/menu.js +1 -0
  132. package/dist/cli/app/public/libs/exe_math/ui/safe.js +1 -0
  133. package/dist/cli/cli/execonvert.js +807 -0
  134. package/dist/cli/cli/runtime.js +237 -0
  135. package/dist/cli/package.json +3 -0
  136. package/dist/cli/src/converter.js +5078 -0
  137. package/dist/cli/src/docx-import.js +1121 -0
  138. package/dist/cli/src/elpx-markdown.js +201 -0
  139. package/dist/cli/src/i18n.js +485 -0
  140. package/dist/cli/src/index.js +1 -0
  141. package/dist/cli/src/legacy-elp.js +846 -0
  142. package/dist/cli/src/markdown-import.js +26 -0
  143. package/package.json +68 -0
@@ -0,0 +1,723 @@
1
+ <!doctype html>
2
+ <html lang="es">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>eXeConvert</title>
7
+ <style>
8
+ :root {
9
+ --bg: #f3f7ef;
10
+ --panel: rgba(255, 255, 255, 0.92);
11
+ --line: #bfd0b7;
12
+ --ink: #243024;
13
+ --muted: #5b685a;
14
+ --brand: #5f9b3d;
15
+ --brand-dark: #2f5d2f;
16
+ --brand-soft: #e2eedb;
17
+ --arrow-in: #78b757;
18
+ --arrow-out: #2d6c4d;
19
+ --word: #185abd;
20
+ --word-dark: #0d3f90;
21
+ --pdf: #d93025;
22
+ --md: #111111;
23
+ }
24
+
25
+ * {
26
+ box-sizing: border-box;
27
+ }
28
+
29
+ body {
30
+ margin: 0;
31
+ min-height: 100vh;
32
+ font-family: Candara, "Trebuchet MS", "Gill Sans", sans-serif;
33
+ color: var(--ink);
34
+ background:
35
+ radial-gradient(circle at 82% 12%, rgba(95, 155, 61, 0.12), transparent 18rem),
36
+ radial-gradient(circle at 10% 88%, rgba(95, 155, 61, 0.08), transparent 16rem),
37
+ linear-gradient(180deg, #f8fbf6 0%, var(--bg) 100%);
38
+ }
39
+
40
+ .wrap {
41
+ width: min(1240px, calc(100% - 52px));
42
+ margin: 0 auto;
43
+ padding: 26px 0 34px;
44
+ }
45
+
46
+ .hero {
47
+ margin-bottom: 22px;
48
+ }
49
+
50
+ .logo-row-hero {
51
+ display: flex;
52
+ align-items: center;
53
+ gap: 18px;
54
+ margin-bottom: 6px;
55
+ }
56
+
57
+ .capture-trigger {
58
+ appearance: none;
59
+ border: 0;
60
+ padding: 0;
61
+ margin: 0;
62
+ background: transparent;
63
+ border-radius: 18px;
64
+ cursor: pointer;
65
+ display: inline-flex;
66
+ align-items: center;
67
+ justify-content: center;
68
+ transition:
69
+ transform 140ms ease,
70
+ box-shadow 140ms ease,
71
+ background-color 140ms ease;
72
+ }
73
+
74
+ .capture-trigger:hover,
75
+ .capture-trigger:focus-visible {
76
+ transform: translateY(-1px);
77
+ box-shadow: 0 10px 24px rgba(53, 77, 47, 0.14);
78
+ background: rgba(255, 255, 255, 0.58);
79
+ outline: none;
80
+ }
81
+
82
+ .capture-trigger:active {
83
+ transform: translateY(0);
84
+ }
85
+
86
+ .hero-icon {
87
+ width: clamp(3.2rem, 7vw, 5rem);
88
+ height: clamp(3.2rem, 7vw, 5rem);
89
+ flex-shrink: 0;
90
+ }
91
+
92
+ h1 {
93
+ margin: 0;
94
+ font-size: clamp(3.4rem, 7vw, 5.5rem);
95
+ line-height: 0.94;
96
+ letter-spacing: -0.05em;
97
+ color: var(--brand-dark);
98
+ }
99
+
100
+ .subtitle {
101
+ margin: 14px 0 0;
102
+ max-width: 54rem;
103
+ font-size: clamp(1.1rem, 2vw, 1.55rem);
104
+ line-height: 1.35;
105
+ color: var(--muted);
106
+ }
107
+
108
+ .layout {
109
+ display: grid;
110
+ grid-template-columns: 1fr 360px 1fr;
111
+ gap: 52px;
112
+ align-items: stretch;
113
+ }
114
+
115
+ .lane {
116
+ display: grid;
117
+ gap: 14px;
118
+ align-content: start;
119
+ }
120
+
121
+ .lane-title {
122
+ margin: 0 0 4px;
123
+ font-size: 1rem;
124
+ font-weight: 800;
125
+ letter-spacing: 0.16em;
126
+ text-transform: uppercase;
127
+ color: var(--brand-dark);
128
+ }
129
+
130
+ .card {
131
+ position: relative;
132
+ min-height: 154px;
133
+ padding: 24px 22px 24px 104px;
134
+ border: 2px solid var(--line);
135
+ border-radius: 26px;
136
+ background: var(--panel);
137
+ box-shadow: 0 14px 30px rgba(53, 77, 47, 0.07);
138
+ display: flex;
139
+ flex-direction: column;
140
+ justify-content: center;
141
+ }
142
+
143
+ .card h2 {
144
+ margin: 0 0 10px;
145
+ font-size: 1.46rem;
146
+ line-height: 1.05;
147
+ color: var(--brand-dark);
148
+ }
149
+
150
+ .card p {
151
+ margin: 0;
152
+ font-size: 0.98rem;
153
+ line-height: 1.32;
154
+ color: var(--muted);
155
+ }
156
+
157
+ .format-icon {
158
+ position: absolute;
159
+ left: 20px;
160
+ top: 20px;
161
+ width: 62px;
162
+ height: 62px;
163
+ display: grid;
164
+ place-items: center;
165
+ border-radius: 16px;
166
+ background: rgba(255, 255, 255, 0.72);
167
+ box-shadow: inset 0 0 0 1px rgba(47, 93, 47, 0.08);
168
+ }
169
+
170
+ .format-icon img {
171
+ display: block;
172
+ max-width: 100%;
173
+ max-height: 100%;
174
+ object-fit: contain;
175
+ }
176
+
177
+ .format-icon.md img {
178
+ max-width: 84%;
179
+ max-height: 84%;
180
+ }
181
+
182
+ .format-icon.pdf {
183
+ background: rgba(217, 48, 37, 0.08);
184
+ box-shadow: inset 0 0 0 1px rgba(217, 48, 37, 0.14);
185
+ }
186
+
187
+ .format-icon.pdf img {
188
+ max-width: 82%;
189
+ max-height: 82%;
190
+ }
191
+
192
+ .arrow-in,
193
+ .arrow-out {
194
+ position: absolute;
195
+ top: 50%;
196
+ width: 48px;
197
+ height: 20px;
198
+ transform: translateY(-50%);
199
+ overflow: visible;
200
+ }
201
+
202
+ .left .card .arrow-in {
203
+ right: -50px;
204
+ }
205
+
206
+ .right .card .arrow-out {
207
+ left: -50px;
208
+ }
209
+
210
+ .center {
211
+ align-self: center;
212
+ display: grid;
213
+ gap: 24px;
214
+ padding: 48px 32px;
215
+ border-radius: 38px;
216
+ background: linear-gradient(155deg, #6aa844 0%, #46792c 100%);
217
+ box-shadow: 0 25px 50px rgba(53, 77, 47, 0.22);
218
+ color: white;
219
+ }
220
+
221
+ .brand-row {
222
+ display: flex;
223
+ align-items: center;
224
+ justify-content: center;
225
+ gap: 12px;
226
+ min-width: 0;
227
+ }
228
+
229
+ .brand-icon {
230
+ width: 48px;
231
+ height: 48px;
232
+ flex: 0 0 48px;
233
+ display: block;
234
+ }
235
+
236
+ .center .brand {
237
+ margin: 0;
238
+ font-size: 3.1rem;
239
+ line-height: 0.95;
240
+ font-weight: 800;
241
+ letter-spacing: -0.05em;
242
+ text-align: center;
243
+ }
244
+
245
+ .center p {
246
+ margin: 0;
247
+ font-size: 1.05rem;
248
+ line-height: 1.4;
249
+ text-align: center;
250
+ color: rgba(255, 255, 255, 0.92);
251
+ }
252
+
253
+ .pill {
254
+ padding: 14px 22px;
255
+ border-radius: 24px;
256
+ border: 1px solid rgba(255, 255, 255, 0.25);
257
+ background: rgba(255, 255, 255, 0.12);
258
+ display: flex;
259
+ align-items: center;
260
+ justify-content: center;
261
+ gap: 16px;
262
+ margin-top: 10px;
263
+ }
264
+
265
+ .pill-icon {
266
+ width: 52px;
267
+ height: 52px;
268
+ background: white;
269
+ padding: 8px;
270
+ border-radius: 14px;
271
+ box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
272
+ flex-shrink: 0;
273
+ }
274
+
275
+ .pill-icon img {
276
+ display: block;
277
+ width: 100%;
278
+ height: 100%;
279
+ object-fit: contain;
280
+ }
281
+
282
+ .pill strong {
283
+ display: block;
284
+ font-size: 2.4rem;
285
+ line-height: 1;
286
+ font-family: "IBM Plex Mono", Consolas, monospace;
287
+ }
288
+
289
+ .pill strong code {
290
+ background: transparent;
291
+ padding: 0;
292
+ }
293
+
294
+ .footer-info {
295
+ margin-top: 40px;
296
+ margin-bottom: 20px;
297
+ text-align: center;
298
+ }
299
+
300
+ .disclaimer {
301
+ margin-bottom: 14px;
302
+ font-size: 0.9rem;
303
+ line-height: 1.4;
304
+ color: var(--muted);
305
+ max-width: 720px;
306
+ margin-left: auto;
307
+ margin-right: auto;
308
+ padding: 0 20px;
309
+ }
310
+
311
+ .url {
312
+ display: inline-block;
313
+ padding: 12px 24px;
314
+ border: 2px solid var(--line);
315
+ border-radius: 20px;
316
+ background: var(--brand-soft);
317
+ }
318
+
319
+ .url a {
320
+ color: var(--brand-dark);
321
+ text-decoration: none;
322
+ font-size: 1.15rem;
323
+ font-weight: 700;
324
+ }
325
+
326
+ .attribution {
327
+ margin-top: 22px;
328
+ font-size: 0.8rem;
329
+ line-height: 1.4;
330
+ color: var(--muted);
331
+ opacity: 0.8;
332
+ }
333
+
334
+ svg {
335
+ display: block;
336
+ }
337
+
338
+ @media (max-width: 1120px) {
339
+ .layout {
340
+ grid-template-columns: 1fr;
341
+ gap: 36px;
342
+ }
343
+
344
+ .arrow-in,
345
+ .arrow-out {
346
+ display: none;
347
+ }
348
+
349
+ .center {
350
+ order: -1;
351
+ width: 100%;
352
+ max-width: 440px;
353
+ margin: 0 auto;
354
+ }
355
+ }
356
+
357
+ @media (max-width: 640px) {
358
+ .wrap {
359
+ width: min(100% - 22px, 1320px);
360
+ padding-top: 22px;
361
+ }
362
+
363
+ .card {
364
+ min-height: 146px;
365
+ padding: 18px 18px 18px 96px;
366
+ border-radius: 24px;
367
+ }
368
+
369
+ .format-icon {
370
+ left: 18px;
371
+ top: 18px;
372
+ width: 56px;
373
+ height: 56px;
374
+ }
375
+
376
+ .brand-row {
377
+ gap: 8px;
378
+ }
379
+
380
+ .brand-icon {
381
+ width: 34px;
382
+ height: 34px;
383
+ flex-basis: 34px;
384
+ }
385
+ }
386
+ </style>
387
+ </head>
388
+ <body>
389
+ <main class="wrap" id="capture-root">
390
+ <header class="hero">
391
+ <div class="logo-row-hero">
392
+ <button
393
+ class="capture-trigger"
394
+ id="capture-button"
395
+ type="button"
396
+ aria-label="Descargar una captura PNG de esta página"
397
+ title="Descargar captura PNG"
398
+ >
399
+ <img class="hero-icon" src="./execonvert-icon.svg" alt="" />
400
+ </button>
401
+ <h1>eXeConvert</h1>
402
+ </div>
403
+ <p class="subtitle" id="info-subtitle">Convierte proyectos de eXeLearning en el navegador.</p>
404
+ </header>
405
+
406
+ <section class="layout" id="info-layout" aria-label="Qué hace eXeConvert">
407
+ <section class="lane left">
408
+ <h2 class="lane-title" id="info-input-title">Entrada</h2>
409
+
410
+ <article class="card">
411
+ <div class="format-icon" aria-hidden="true">
412
+ <img src="./exe-old.png" alt="" />
413
+ </div>
414
+ <h2><code>.elp</code></h2>
415
+ <p id="info-elp-input">Proyectos de la versión 2 que se migran al formato actual.</p>
416
+ <svg class="arrow-in" viewBox="0 0 50 20" aria-hidden="true">
417
+ <path d="M2 10H32" stroke="#78b757" stroke-width="3.5" stroke-linecap="round"/>
418
+ <path d="M30 2l16 8-16 8V2z" fill="#78b757"/>
419
+ </svg>
420
+ </article>
421
+
422
+ <article class="card">
423
+ <div class="format-icon" aria-hidden="true">
424
+ <img src="./docx.svg" alt="" />
425
+ </div>
426
+ <h2><code>.docx</code></h2>
427
+ <p id="info-docx-input">Documento Word que se importa como proyecto editable.</p>
428
+ <svg class="arrow-in" viewBox="0 0 50 20" aria-hidden="true">
429
+ <path d="M2 10H32" stroke="#78b757" stroke-width="3.5" stroke-linecap="round"/>
430
+ <path d="M30 2l16 8-16 8V2z" fill="#78b757"/>
431
+ </svg>
432
+ </article>
433
+
434
+ <article class="card">
435
+ <div class="format-icon md" aria-hidden="true">
436
+ <img src="./markdown.svg" alt="" />
437
+ </div>
438
+ <h2><code>.md</code></h2>
439
+ <p id="info-md-input">Markdown que se importa como proyecto <code>.elpx</code>.</p>
440
+ <svg class="arrow-in" viewBox="0 0 50 20" aria-hidden="true">
441
+ <path d="M2 10H32" stroke="#78b757" stroke-width="3.5" stroke-linecap="round"/>
442
+ <path d="M30 2l16 8-16 8V2z" fill="#78b757"/>
443
+ </svg>
444
+ </article>
445
+ </section>
446
+
447
+ <section class="center">
448
+ <div class="brand-row">
449
+ <img class="brand-icon" src="./execonvert-icon.svg" alt="" />
450
+ <h2 class="brand">eXeConvert</h2>
451
+ </div>
452
+ <p id="info-center-line-1">Todo en local, sin subir archivos.</p>
453
+ <p id="info-center-line-2">Convierte, guarda y sigue trabajando desde un único formato central.</p>
454
+ <div class="pill">
455
+ <div class="pill-icon" aria-hidden="true">
456
+ <img src="./elpx-icon.png" alt="" />
457
+ </div>
458
+ <strong><code>.elpx</code></strong>
459
+ </div>
460
+ </section>
461
+
462
+ <section class="lane right">
463
+ <h2 class="lane-title" id="info-output-title">Salida</h2>
464
+
465
+ <article class="card">
466
+ <div class="format-icon" aria-hidden="true">
467
+ <img src="./docx.svg" alt="" />
468
+ </div>
469
+ <h2><code>.docx</code></h2>
470
+ <p id="info-docx-output">Exportación desde <code>.elpx</code> a Word.</p>
471
+ <svg class="arrow-out" viewBox="0 0 50 20" aria-hidden="true">
472
+ <path d="M2 10H32" stroke="#2d6c4d" stroke-width="3.5" stroke-linecap="round"/>
473
+ <path d="M30 2l16 8-16 8V2z" fill="#2d6c4d"/>
474
+ </svg>
475
+ </article>
476
+
477
+ <article class="card">
478
+ <div class="format-icon md" aria-hidden="true">
479
+ <img src="./markdown.svg" alt="" />
480
+ </div>
481
+ <h2><code>.md</code></h2>
482
+ <p id="info-md-output">Exportación desde <code>.elpx</code> a Markdown.</p>
483
+ <svg class="arrow-out" viewBox="0 0 50 20" aria-hidden="true">
484
+ <path d="M2 10H32" stroke="#2d6c4d" stroke-width="3.5" stroke-linecap="round"/>
485
+ <path d="M30 2l16 8-16 8V2z" fill="#2d6c4d"/>
486
+ </svg>
487
+ </article>
488
+
489
+ <article class="card">
490
+ <div class="format-icon pdf" aria-hidden="true">
491
+ <img src="./pdf.svg" alt="" />
492
+ </div>
493
+ <h2><code>.pdf</code></h2>
494
+ <p id="info-pdf-output">Exportación desde <code>.elpx</code> a PDF.</p>
495
+ <svg class="arrow-out" viewBox="0 0 50 20" aria-hidden="true">
496
+ <path d="M2 10H32" stroke="#2d6c4d" stroke-width="3.5" stroke-linecap="round"/>
497
+ <path d="M30 2l16 8-16 8V2z" fill="#2d6c4d"/>
498
+ </svg>
499
+ </article>
500
+ </section>
501
+ </section>
502
+
503
+ <footer class="footer-info">
504
+ <p class="disclaimer" id="info-disclaimer">
505
+ La interactividad de iDevices no se puede exportar debido a las limitaciones técnicas de los formatos de destino (Word, PDF y Markdown).
506
+ </p>
507
+ <section class="url" id="info-url-label" aria-label="URL pública">
508
+ <a href="https://execonvert.github.io/">https://execonvert.github.io/</a>
509
+ </section>
510
+ <p class="attribution" id="info-attribution">
511
+ Proyecto independiente. eXeLearning y sus logotipos se usan aqui solo con fines identificativos. No existe afiliacion ni respaldo oficial por parte del proyecto eXeLearning.
512
+ </p>
513
+ </footer>
514
+ </main>
515
+ <script src="https://cdn.jsdelivr.net/npm/html-to-image@1.11.11/dist/html-to-image.js"></script>
516
+ <script>
517
+ const STORAGE_KEY = "execonvert.locale";
518
+ const SUPPORTED_LOCALES = ["es", "ca", "en"];
519
+ const infoTranslations = {
520
+ es: {
521
+ subtitle: "Convierte proyectos de eXeLearning en el navegador.",
522
+ layoutAria: "Que hace eXeConvert",
523
+ inputTitle: "Entrada",
524
+ outputTitle: "Salida",
525
+ elpInput: "Proyectos de la version 2 que se migran al formato actual.",
526
+ docxInput: "Documento Word que se importa como proyecto editable.",
527
+ mdInput: "Markdown que se importa como proyecto <code>.elpx</code>.",
528
+ centerLine1: "Todo en local, sin subir archivos.",
529
+ centerLine2: "Convierte, guarda y sigue trabajando desde un unico formato central.",
530
+ docxOutput: "Exportacion desde <code>.elpx</code> a Word.",
531
+ mdOutput: "Exportacion desde <code>.elpx</code> a Markdown.",
532
+ pdfOutput: "Exportacion desde <code>.elpx</code> a PDF.",
533
+ disclaimer:
534
+ "La interactividad de iDevices no se puede exportar debido a las limitaciones tecnicas de los formatos de destino (Word, PDF y Markdown).",
535
+ attribution:
536
+ "Proyecto independiente. eXeLearning y sus logotipos se usan aqui solo con fines identificativos. No existe afiliacion ni respaldo oficial por parte del proyecto eXeLearning.",
537
+ pageTitle: "eXeConvert",
538
+ captureTitle: "Descargar captura PNG",
539
+ captureAria: "Descargar una captura PNG de esta pagina",
540
+ captureBusy: "Generando captura...",
541
+ captureError: "No se pudo generar la captura PNG en este navegador.",
542
+ publicUrlAria: "URL publica"
543
+ },
544
+ ca: {
545
+ subtitle: "Converteix projectes d'eXeLearning al navegador.",
546
+ layoutAria: "Que fa eXeConvert",
547
+ inputTitle: "Entrada",
548
+ outputTitle: "Sortida",
549
+ elpInput: "Projectes de la versio 2 que es migren al format actual.",
550
+ docxInput: "Document Word que s'importa com a projecte editable.",
551
+ mdInput: "Markdown que s'importa com a projecte <code>.elpx</code>.",
552
+ centerLine1: "Tot en local, sense pujar fitxers.",
553
+ centerLine2: "Converteix, desa i continua treballant des d'un unic format central.",
554
+ docxOutput: "Exportacio des de <code>.elpx</code> a Word.",
555
+ mdOutput: "Exportacio des de <code>.elpx</code> a Markdown.",
556
+ pdfOutput: "Exportacio des de <code>.elpx</code> a PDF.",
557
+ disclaimer:
558
+ "La interactivitat dels iDevices no es pot exportar a causa de les limitacions tecniques dels formats de destinacio (Word, PDF i Markdown).",
559
+ attribution:
560
+ "Projecte independent. eXeLearning i els seus logotips s'utilitzen aqui nomes amb finalitats identificatives. No hi ha afiliacio ni suport oficial per part del projecte eXeLearning.",
561
+ pageTitle: "eXeConvert",
562
+ captureTitle: "Descarregar captura PNG",
563
+ captureAria: "Descarregar una captura PNG d'aquesta pagina",
564
+ captureBusy: "Generant captura...",
565
+ captureError: "No s'ha pogut generar la captura PNG en aquest navegador.",
566
+ publicUrlAria: "URL publica"
567
+ },
568
+ en: {
569
+ subtitle: "Convert eXeLearning projects in the browser.",
570
+ layoutAria: "What eXeConvert does",
571
+ inputTitle: "Input",
572
+ outputTitle: "Output",
573
+ elpInput: "Version 2 projects migrated to the current format.",
574
+ docxInput: "Word document imported as an editable project.",
575
+ mdInput: "Markdown imported as an <code>.elpx</code> project.",
576
+ centerLine1: "Everything stays local, with no uploads.",
577
+ centerLine2: "Convert, save, and keep working from a single central format.",
578
+ docxOutput: "Export from <code>.elpx</code> to Word.",
579
+ mdOutput: "Export from <code>.elpx</code> to Markdown.",
580
+ pdfOutput: "Export from <code>.elpx</code> to PDF.",
581
+ disclaimer:
582
+ "iDevice interactivity cannot be exported because of the technical limitations of the target formats (Word, PDF, and Markdown).",
583
+ attribution:
584
+ "Independent project. eXeLearning and its logos are used here for identification purposes only. No official affiliation with or endorsement by the eXeLearning project is implied.",
585
+ pageTitle: "eXeConvert",
586
+ captureTitle: "Download PNG capture",
587
+ captureAria: "Download a PNG capture of this page",
588
+ captureBusy: "Generating capture...",
589
+ captureError: "The PNG capture could not be generated in this browser.",
590
+ publicUrlAria: "Public URL"
591
+ }
592
+ };
593
+
594
+ const captureButton = document.getElementById("capture-button");
595
+ const captureRoot = document.getElementById("capture-root");
596
+
597
+ function resolveLocale() {
598
+ const params = new URLSearchParams(window.location.search);
599
+ const queryLocale = params.get("lang");
600
+ if (SUPPORTED_LOCALES.includes(queryLocale)) {
601
+ return queryLocale;
602
+ }
603
+
604
+ const stored = localStorage.getItem(STORAGE_KEY);
605
+ if (SUPPORTED_LOCALES.includes(stored)) {
606
+ return stored;
607
+ }
608
+
609
+ const nav = (navigator.language || "es").toLowerCase();
610
+ if (nav.startsWith("ca")) return "ca";
611
+ if (nav.startsWith("en")) return "en";
612
+ return "es";
613
+ }
614
+
615
+ function applyTranslations(locale) {
616
+ const copy = infoTranslations[locale] || infoTranslations.es;
617
+ document.documentElement.lang = locale;
618
+ document.title = copy.pageTitle;
619
+
620
+ document.getElementById("info-subtitle").textContent = copy.subtitle;
621
+ document.getElementById("info-layout").setAttribute("aria-label", copy.layoutAria);
622
+ document.getElementById("info-input-title").textContent = copy.inputTitle;
623
+ document.getElementById("info-output-title").textContent = copy.outputTitle;
624
+ document.getElementById("info-elp-input").textContent = copy.elpInput;
625
+ document.getElementById("info-docx-input").textContent = copy.docxInput;
626
+ document.getElementById("info-md-input").innerHTML = copy.mdInput;
627
+ document.getElementById("info-center-line-1").textContent = copy.centerLine1;
628
+ document.getElementById("info-center-line-2").textContent = copy.centerLine2;
629
+ document.getElementById("info-docx-output").innerHTML = copy.docxOutput;
630
+ document.getElementById("info-md-output").innerHTML = copy.mdOutput;
631
+ document.getElementById("info-pdf-output").innerHTML = copy.pdfOutput;
632
+ document.getElementById("info-disclaimer").textContent = copy.disclaimer;
633
+ document.getElementById("info-attribution").textContent = copy.attribution;
634
+ document.getElementById("info-url-label").setAttribute("aria-label", copy.publicUrlAria);
635
+ captureButton?.setAttribute("title", copy.captureTitle);
636
+ captureButton?.setAttribute("aria-label", copy.captureAria);
637
+
638
+ return copy;
639
+ }
640
+
641
+ const activeLocale = resolveLocale();
642
+ const activeCopy = applyTranslations(activeLocale);
643
+
644
+ async function downloadCapture() {
645
+ if (!captureRoot) {
646
+ return;
647
+ }
648
+
649
+ const previousLabel = captureButton?.title || activeCopy.captureTitle;
650
+ if (captureButton) {
651
+ captureButton.disabled = true;
652
+ captureButton.title = activeCopy.captureBusy;
653
+ }
654
+
655
+ try {
656
+ const exportNode = captureRoot.cloneNode(true);
657
+ exportNode.id = "capture-export-clone";
658
+ exportNode.style.width = "1240px";
659
+ exportNode.style.margin = "0";
660
+ exportNode.style.padding = "26px 60px 34px";
661
+ exportNode.style.overflow = "visible";
662
+ exportNode.style.background =
663
+ "radial-gradient(circle at 82% 12%, rgba(95, 155, 61, 0.12), transparent 18rem), radial-gradient(circle at 10% 88%, rgba(95, 155, 61, 0.08), transparent 16rem), linear-gradient(180deg, #f8fbf6 0%, #f3f7ef 100%)";
664
+
665
+ const exportLayout = exportNode.querySelector(".layout");
666
+ if (exportLayout) {
667
+ exportLayout.style.overflow = "visible";
668
+ }
669
+
670
+ const exportCards = exportNode.querySelectorAll(".card");
671
+ for (const card of exportCards) {
672
+ card.style.overflow = "visible";
673
+ }
674
+
675
+ const staging = document.createElement("div");
676
+ staging.style.position = "fixed";
677
+ staging.style.left = "-20000px";
678
+ staging.style.top = "0";
679
+ staging.style.zIndex = "-1";
680
+ staging.style.pointerEvents = "none";
681
+ staging.style.background = "#f3f7ef";
682
+ staging.appendChild(exportNode);
683
+ document.body.appendChild(staging);
684
+
685
+ const width = Math.ceil(exportNode.scrollWidth);
686
+ const height = Math.ceil(exportNode.scrollHeight);
687
+
688
+ const dataUrl = await window.htmlToImage.toPng(exportNode, {
689
+ cacheBust: true,
690
+ pixelRatio: 2,
691
+ backgroundColor: "#f3f7ef",
692
+ skipFonts: true,
693
+ width,
694
+ height,
695
+ canvasWidth: width * 2,
696
+ canvasHeight: height * 2,
697
+ style: {
698
+ width: width + "px",
699
+ height: height + "px"
700
+ }
701
+ });
702
+
703
+ staging.remove();
704
+
705
+ const link = document.createElement("a");
706
+ link.href = dataUrl;
707
+ link.download = "execonvert.png";
708
+ link.click();
709
+ } catch (error) {
710
+ console.error("No se pudo generar la captura PNG", error);
711
+ alert(activeCopy.captureError);
712
+ } finally {
713
+ if (captureButton) {
714
+ captureButton.disabled = false;
715
+ captureButton.title = previousLabel;
716
+ }
717
+ }
718
+ }
719
+
720
+ captureButton?.addEventListener("click", downloadCapture);
721
+ </script>
722
+ </body>
723
+ </html>