9 |
10 |
21 |
--------------------------------------------------------------------------------
/update-static.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | cat < /dev/null
4 |
44 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Rémi EMONET
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/vuejspython/fsapi.js:
--------------------------------------------------------------------------------
1 |
2 | export class FileSystemAPI {
3 | constructor(baseURL = "") {
4 | this.baseURL = baseURL;
5 | }
6 |
7 | async readFile(filename, prefix="", binary = false) {
8 | const response = await fetch(`${this.baseURL}/${prefix}${filename}`);
9 | if (!response.ok) {
10 | throw new Error(`Failed to read file: ${response.statusText}`);
11 | }
12 | if (binary) {
13 | return response.arrayBuffer();
14 | } else {
15 | return response.text();
16 | }
17 | }
18 |
19 | async writeFile(filename, data) {
20 | const response = await fetch(`${this.baseURL}/.file/${filename}`, {
21 | method: "POST",
22 | body: data,
23 | headers: {
24 | "Content-Type":
25 | typeof data === "string" ? "text/plain" : "application/octet-stream",
26 | },
27 | });
28 | if (!response.ok) {
29 | throw new Error(`Failed to write file: ${response.statusText}`);
30 | }
31 | return response.text();
32 | }
33 |
34 | async listFiles() {
35 | const response = await fetch(`${this.baseURL}/.files`);
36 | if (!response.ok) {
37 | throw new Error(`Failed to list files: ${response.statusText}`);
38 | }
39 | return response.json();
40 | }
41 |
42 | async deleteFile(filename) {
43 | const response = await fetch(`${this.baseURL}/.file/${filename}`, {
44 | method: "DELETE",
45 | });
46 | if (!response.ok) {
47 | throw new Error(`Failed to delete file: ${response.statusText}`);
48 | }
49 | return response.text();
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/vuejspython/builtin/rotate-files.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Rotate Files
4 |
5 |
42 | Fill the radius in the text field: .
43 | (or with
44 | A disk with radius {{ radius }} has an area of {{ area }}.
45 |
46 |
47 |
48 |
49 | ```
50 |
51 |
52 |
53 |
54 | ## Running, option 1: only with Python
55 |
56 | ~~~bash
57 | python3 example.py
58 |
59 | # or a tiny shell function helper
60 | pvue() { (sleep .5;firefox ${1%.*}.html)& python3 ${1%.*}.py;}
61 | pvue example.py
62 | ~~~
63 |
64 | This will give you an address to which you should append your HTML file name, here `example.html`.
65 | In this example, you will visit
66 | (or visit the given address `http://localhost:4260` and click your file).
67 |
68 | NB: you need to stop the command with `Ctrl+C` if you want to run another example.
69 |
70 |
71 | ## Running, option 2: with hot reload on file change
72 |
73 | Here we will start two processes, one for the HTML part (with live reload, and another only for the Python).
74 |
75 | Terminal 1, hosting the HTML files with hot reload:
76 |
77 | ~~~bash
78 | # one-time install
79 | pip install watchdog
80 | npm install -g simple-hot-reload-server
81 | # in terminal 1 (hot html reload, for all files)
82 | hrs .
83 | ~~~
84 | (this gives you the address to open, after appending your file name, e.g., )
85 |
86 | Terminal 2, running the python server
87 |
88 | ~~~bash
89 | # in terminal 2 (start or restart python)
90 | NOSERVE=1 python3 example.py
91 | # OR, for live restart
92 | NOSERVE=1 watchmedo auto-restart --patterns="*.py" python3 example.py
93 | ~~~
94 | NB: `NOSERVE=1` tells vuejspython to not serve the HTML files (it is handled by `hrs` above)
95 |
96 | NB: when changing the .py, a manual browser refresh is still needed, see below for a more complete solution
97 |
98 | ### Helper for complete live reload (live restart for python)
99 |
100 | ~~~bash
101 | pvue() { if test "$1" = open ; then shift ; (sleep 1 ; firefox "http://localhost:8082/${1%.*}.html") & fi; watchmedo auto-restart --patterns="*.py" --ignore-patterns="*/.#*.py" bash -- -c '(sleep .250 ; touch '"${1%.*}"'.html) & python3 '"${1%.*}"'.py' ; }
102 | # Then
103 | pvue example
104 | # OR to also open firefox
105 | pvue open example
106 | # OR some convenient variations
107 | NOSERVE=1 pvue open example
108 | pvue open example.
109 | pvue open example.py
110 | pvue open example.html
111 | # it always runs the file with the .py extension
112 | ~~~
113 |
114 |
115 | ## Other, different projects
116 |
117 | If you're interested only in using Python the language with Vue.js, you can try [brython](http://brython.info/) and the [brython vue demo](http://brython.info/gallery/test_vue.html)
118 |
119 | There are projects that try to help integrating Vue.js with different Python web frameworks. The goal is different: Vuejs-python makes python and vue tightly integrated, in a common, reactive model.
120 |
121 | ----
122 |
123 |
124 | ## Development (TO BE REVIEWED AND UPDATED)
125 |
126 | ### Requirements
127 |
128 | ~~~ bash
129 | pip install aiohttp
130 | pip install websockets
131 | ~~~
132 |
133 | You also need to get a few libraries:
134 |
135 | ~~~
136 | cd vuejspython
137 | ./update-static.sh # or manually download the files
138 | ~~~
139 |
140 | ### Notes
141 |
142 | Currently, the project uses requires some "observable collections", with some modifications.
143 | They are included in the package, in `vuejspython/observablecollections`.
144 | They have been obtained with:
145 |
146 | ~~~ bash
147 | git clone https://github.com/fousteris-dim/Python-observable-collections.git observablecollections
148 | patch -d observablecollections/ < 0001-Local-imports.patch
149 | ~~~
150 |
151 |
152 |
153 | ## Helpers
154 |
155 | ### Simply launch python and open a browser (firefox) at the right address.
156 |
157 | ~~~ bash
158 | # bash function
159 | pvue() { (sleep .5;firefox ${1%.*}.html)& python3 ${1%.*}.py;}
160 |
161 | # examples
162 | pvue example-1
163 | pvue example-1.
164 | pvue example-1.html
165 | pvue example-1.py
166 | ~~~
167 |
168 |
169 | ### OR, to develop with auto-reload.
170 |
171 | ~~~ bash
172 | # one-time install
173 | pip install watchdog
174 | npm install -g simple-hot-reload-server
175 |
176 |
177 | # in terminal 1 (hot html reload, for all files)
178 | hrs .
179 |
180 | # in terminal 2 (start and restart python
181 | pvue() { if test "$1" = open ; then shift ; (sleep 1 ; firefox "http://localhost:8082/${1%.*}.html") & fi; watchmedo auto-restart --patterns="*.py" --ignore-patterns="*/.#*.py" bash -- -c '(sleep .250 ; touch '"${1%.*}"'.html) & python3 '"${1%.*}"'.py' ; }
182 | pvue open example-1
183 | pvue example-1
184 | # the first opens firefox initially
185 | ~~~
186 |
187 |
188 | ## Pypi stuff
189 |
190 | ~~~
191 | python3 -m pip install --upgrade setuptools wheel
192 | python3 -m pip install --upgrade twine
193 |
194 | # update the version number in setup.py and then
195 | rm -rf dist/
196 | python3 setup.py sdist bdist_wheel
197 | python3 -m twine upload --repository-url https://test.pypi.org/legacy/ dist/*
198 | # OR: python3 -m twine upload dist/*
199 |
200 | python3 -m pip install --index-url https://test.pypi.org/simple/ --no-deps vuejspython
201 |
202 | pip uninstall vuejspython
203 |
204 | python3 -m pip install .. ; ll $VENV/lib/python3.6/site-packages/vuejspython
205 | ~~~
206 |
207 |
208 | ## TODO
209 |
210 | - see why example-8 is slow with the python-only server
211 | - test atomic in components
212 | - make it an all-components (no too-special ROOT', with also js that tells what class and package/file (import everything manually in a main.py if not easy) is the root -> this way we can run a single python and have multiple demos
213 | - have a clean solution for the observable collections (integrate and clean minimal code or find another lib)
214 |
--------------------------------------------------------------------------------
/vuejspython/builtin/toggle-exam.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Exam Toggle
4 |
5 |
6 |
40 |
41 |
110 |
329 |
--------------------------------------------------------------------------------
/vuejspython/builtin/diff.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 |
3 | diff v5.1.0
4 |
5 | Software License Agreement (BSD License)
6 |
7 | Copyright (c) 2009-2015, Kevin Decker
8 |
9 | All rights reserved.
10 |
11 | Redistribution and use of this software in source and binary forms, with or without modification,
12 | are permitted provided that the following conditions are met:
13 |
14 | * Redistributions of source code must retain the above
15 | copyright notice, this list of conditions and the
16 | following disclaimer.
17 |
18 | * Redistributions in binary form must reproduce the above
19 | copyright notice, this list of conditions and the
20 | following disclaimer in the documentation and/or other
21 | materials provided with the distribution.
22 |
23 | * Neither the name of Kevin Decker nor the names of its
24 | contributors may be used to endorse or promote products
25 | derived from this software without specific prior
26 | written permission.
27 |
28 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
29 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
30 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
31 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
34 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
35 | OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 | @license
37 | */
38 | !function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((e=e||self).Diff={})}(this,function(e){"use strict";function t(){}t.prototype={diff:function(u,a,e){var n=2=c&&h<=i+1)return d([{value:this.join(a),count:a.length}]);function o(){for(var e,n=-1*p;n<=p;n+=2){var t=void 0,r=v[n-1],i=v[n+1],o=(i?i.newPos:0)-n;r&&(v[n-1]=void 0);var l=r&&r.newPos+1=c&&h<=o+1)return d(function(e,n,t,r,i){for(var o=0,l=n.length,s=0,u=0;oe.length?t:e}),d.value=e.join(f)):d.value=e.join(t.slice(s,s+d.count)),s+=d.count,d.added||(u+=d.count))}var c=n[l-1];1e.length)&&(n=e.length);for(var t=0,r=new Array(n);t=c.length-2&&u.length<=d.context&&(i=/\n$/.test(a),o=/\n$/.test(f),l=0==u.length&&g.length>r.oldLines,!i&&l&&0e.length)return!1;for(var t=0;t"):i.removed&&t.push(""),t.push((n=i.value,n.replace(/&/g,"&").replace(//g,">").replace(/"/g,"""))),i.added?t.push(""):i.removed&&t.push("")}return t.join("")},e.createPatch=function(e,n,t,r,i,o){return y(e,e,n,t,r,i,o)},e.createTwoFilesPatch=y,e.diffArrays=function(e,n,t){return g.diff(e,n,t)},e.diffChars=function(e,n,t){return r.diff(e,n,t)},e.diffCss=function(e,n,t){return f.diff(e,n,t)},e.diffJson=function(e,n,t){return p.diff(e,n,t)},e.diffLines=L,e.diffSentences=function(e,n,t){return a.diff(e,n,t)},e.diffTrimmedLines=function(e,n,t){var r=i(t,{ignoreWhitespace:!0});return u.diff(e,n,r)},e.diffWords=function(e,n,t){return t=i(t,{ignoreWhitespace:!0}),s.diff(e,n,t)},e.diffWordsWithSpace=function(e,n,t){return s.diff(e,n,t)},e.merge=function(e,n,t){e=b(e,t),n=b(n,t);var r={};(e.index||n.index)&&(r.index=e.index||n.index),(e.newFileName||n.newFileName)&&(F(e)?F(n)?(r.oldFileName=N(r,e.oldFileName,n.oldFileName),r.newFileName=N(r,e.newFileName,n.newFileName),r.oldHeader=N(r,e.oldHeader,n.oldHeader),r.newHeader=N(r,e.newHeader,n.newHeader)):(r.oldFileName=e.oldFileName,r.newFileName=e.newFileName,r.oldHeader=e.oldHeader,r.newHeader=e.newHeader):(r.oldFileName=n.oldFileName||e.oldFileName,r.newFileName=n.newFileName||e.newFileName,r.oldHeader=n.oldHeader||e.oldHeader,r.newHeader=n.newHeader||e.newHeader)),r.hunks=[];for(var i=0,o=0,l=0,s=0;i