Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
june-paulajs
Advanced tools
JuNe PaulaJS (Portable Adaptable Utility for Lightweight Applications) JavaScript framework to build frontend, user interfaces, Single-page application or Progressive Web App
Dataclick JuNe PaulaJS Free open-source JavaScript framework to build frontend, user interfaces and single-page applications
● JuNe PaulaJS (Portable Adaptable Utility for Lightweight Applications) is a JavaScript framework similar to React, Vue or Angular, but with more and needed features, without dependencies an optimized in 1 file.
🏗 To build frontend, user interfaces, Single-page application (SPA) or Progressive Web App (PWA), also to create public pages with link compatibility for SEO. With a fully functionality and easy installation and use.
⌨ Developing without using any pseudo-language, just pure (Vanilla) JavaScript, without compiler/transpiler to edit your files directly (build optional for compact/uglify).
📳 Run on all devices (desktop, mobile, tablet).
🏎️ So, developments, deployments, executions and performance are faster.
🍃 And a lower impact on the carbon footprint, both in the server and in the client browser, by using files of a few 27 Kb, which represents less transfer and less execution times, in a difference between 400-800 times compared to other frameworks.
● Compatible and created with ECMAScript 2024 (ES15).
⏺ Includes the default features that any other framework has, such as reactive variables, for loops, or ifs.
⏺ But it also includes other features that in other frameworks you have to add a plugin, such as routing, language support, modal windows, toast notifications, captcha, or send requests to backend.
⏺ And also other important features such as a complete file upload system with custom preview, image rescaling, modules in background, automatic loader display, Open Graph, social share, or speech recognition/synthesis .
⏺ It includes everything you need to make your complete frontend, such as JuNe CSS, backend with JuNe BackServer, or a WebServer.
⏺ It´s easier and faster to directly develop, pure JavaScript, with no transpiler and including a single few Kbs file.
JuNe PaulaJS | React | Create-React | Vue | Angular | Next | |
---|---|---|---|---|---|---|
Files | 1 | 151 | 37.200 | 293 | 10.410 | 5.490 |
Folders | 0 | 23 | 4.909 | 56 | 943 | 497 |
Size | 27 Kb | 7.8 Mb | 225 Mb | 14 Mb | 36.7 Mb | 156 Mb |
✔ Pure vanilla JavaScript without dependencies, with native Web Components.
✔ Reactive variables with automatic visual changes.
✔ If-conditions to show/hide, and for-loops to content repeat.
✔ Routing system integrated, with window.history and compatibility with open in new tab/window.
✔ SEO compatibility (for public projects).
✔ Support for languages.
✔ Support for modal windows.
✔ Support for toast notifications.
✔ Send requests to backend (GET, POST, PUT, PATCH, DELETE), recommended: JuNe BackServer.
✔ Compatibility with JuNe BackServer Captcha.
✔ Upload multiple small or large files and entire folders with progress, from inputs, Drag & Drop or clipboard.
✔ Possibility of rescaling images for faster uploads and preview.
✔ Background modules and restore again to foreground with the same status.
✔ Meta tags or Open Graph protocol compatibility (for public projects).
✔ Social network share (for public projects).
✔ File type icons according file extension.
✔ Manage your frontend with your voice, transcribes from speech to text and human speech synthesis.
✔ Detect DOM new elements.
✔ Includes JuNe CSS (responsive).
✔ Optional Node.js HTTP server for development with automatic update (HMR).
✔ Develop using only JavaScript without other pseudo-languages (like React syntax).
✔ Simple structure: data, functions and html, without complications (useEffect, useState...).
✔ No compilation/transpiler needed, neither Babel/Webpack/Snowpack.
✔ Ease installation, just include (minified) JuNe PaulaJS JavaScript file on your HTML.
Eduardo Ruiz <eruiz@dataclick.es>
All you need is JuNe PaulaJS file and add it to your HTML page:
<script src="june-paula.js"></script>
or minified (better):
<script src="june-paula.min.js"></script>
And you can specify root path in path
parameter <script src="june-paula.min.js" path="/mypath/"></script>
(default /) slash ended.
So you can download one of these files.
You can install the complete package if you want to run a production server, a development environment, view examples, or use utilities to create template projects and uglify/build projects.
npm install june-paulajs
or better option globally with npm install -g june-paulajs
JuNe BackServer and JuNe WebServer are integrated, so it´s not necessary to install them directly.
Command | Definition | If globally |
---|---|---|
npm run start file | Start JuNe WebServer in development mode in current folder to run projects and reload on changes Default http://localhost:8080 Sample npm run start index.html | - |
npm run example file | Start JuNe WebServer in development mode in JuNe PaulaJS folder to run examples and reload on changes Default http://localhost:8080 Sample npm run example "05-If-sample.html" | - |
npm run backend | Start Backend with JuNe BackServer for some examples, or create your own for production or development Default http://localhost:8180 | - |
npm run create | Create a template project in current folder | paulajs create |
npm run build | Uglify/build a project to folder dist/ | paulajs build |
Not necessary, JuNe PaulaJS has no dependencies | - |
You may not need Nginx/Apache and launch your project directly with integrated JuNe WebServer:
webserver -url http://localhost:8180 -folder /var/www/myproject
Have a look to JuNe WebServer Readme for details.
If you want to create templates easily with JuNe CSS and Font Awesome, you must have JuNe PaulaJS installed globally, so create a project folder and type inside: paulajs create
Visual Studio Code Extension available.
The idea is to develop your entire project as an object with OOP (Object Oriented Programming) using this
where is integrated JuNe PaulaJS and your project functions.
Please remember that we are looking for a practical and lightweight functionality, so there are specific ways to do something, without creating many other variations and to achieve the usual functions in a frontend.
Global const created to access directly june_pau
General objects:
Object | Type | From | Definition | Sample |
---|---|---|---|---|
this.data | Array | Imported module | For reactive variables | this.data.myVariable = 1 |
this.funcs | Array | Imported module | Module own functions | this.funcs.myFunc() |
this.main | Array | main.js | Optional main global data/functions | this.main.funcs.myFunc() |
this.outlet | HTMLElement | HTML Tag jpau-content | HTML route content | <span>My Page</span> |
this.params | Array | Autogenerated | Params from URL | /users/:uid ➤ this.params.uid |
this.getparams | URLSearchParams | Autogenerated | Params from GET | /users/?var=1 ➤ this.getparams.var |
Or you could use globally june_pau.data
june_pau.funcs
june_pau.main.data
...
Global optional main file loaded at startup.
Export (all optional) constants for data variables and functions.
Save in root path main.js
and access with this.main.data
and this.main.funcs
If june_pau.main = -1
is previously defined then no attempt is made to load main.js
to avoid 404 and browser console error.
Value | Type | Definition |
---|---|---|
data | Array | Optional global data variables |
funcs | Array | Optional global functions |
Sample:
export const data = {
forceUpdate: false
};
export const funcs = {
onLoad: () => alert('First Load'),
onMount: () => alert('First Mount')
};
Object | Const | Type | Definition | Default |
---|---|---|---|---|
forceUpdate | data | Bool | Optional if true then force entire updated on every this.data change | false |
beforeunload | data | Bool | Optional Window before unload notice | nothing |
uploadSmallMax | data | Integer | Optional maximum file size in Kb for small uploads, recommended 5120 Kb (5 Mb) | - |
uploadLargeMax | data | Integer | Optional maximum file size in Kb for large uploads, recommended 51200 Kb (50 Mb) | - |
onLoad | funcs | Function | Optional function called on first load | - |
onMount | funcs | Function | Optional function called on first mount | - |
this.updElm(element)
or june_pau.updElm(element)
this.updHTML()
Create a file for each section of your page.
Export (all optional) constants for data variables, functions and HTML shown.
Save in file mySection.js
(you can use paths, starts with relative path always).
Object | Type | Definition |
---|---|---|
data | Array | Optional module data reactive variables |
funcs | Array | Optional module functions |
html | String | Optional module HTML content |
Sample:
export const data = {
title: 'My Module Document Title',
myVariable: 'My value',
myArray: [{name: 'John'}, {name: 'Peter'}]
};
export const funcs = {
onLoad: () => alert('Module loaded'),
onMount: () => alert('Module mounted'),
myFunc: (value) => `${value}`,
myFunctionClassic: function() {},
myFuncStyle: () => 'color: red'
};
export const html = `<div><input type="text"></div>`;
Object | Const | Type | Definition |
---|---|---|---|
title | data | String | Optional HTML document title For better performance: <title data-jpauattr="1" data-jpauihtml="{{ title }}">My APP title</title> |
onLoad | funcs | Function | Optional function called on module load |
onMount | funcs | Function | Optional function called on module mounted |
onVisible | funcs | Function | Optional function called when a background module is shown with first parameter true or false |
Prefix | Definition | Sample |
---|---|---|
: | Assign value using text and data variables | <img :title="Text and {{ variable }}"> <input readonly :value="{{ variable * 3 }}"> |
* | Assign value using return value from function, or to reassign data variables from inputs | <img *title="this.funcs.myTitle()"> <input *value="variable"> |
@ | For events | <input @click="this.funcs.myFunction()"> |
checked and selected (boolean) attributes using * may use object this.data.myvar[value]
or variable this.data.myvar == value
And with the other attributes may use object this.data.myvar[id | name]
or variable this.data.myvar
So you can directly program the variable assignment or use this method.
Tag | Definition | Sample |
---|---|---|
{{ variable }} | Replace variable by it´s value | <span>{{ username }}</span> |
{{ function() }} | Replace with function returned value | <span>{{ this.funcs.myFunction() }}</span> |
$this | Current object for events | <input @click="this.funcs.myFunction($this.tagName)"> |
{{ this.funcs.myFunc() }}
or {{ june_pau.funcs.myFunc() }}
or inside for-loops: {{ this.funcs.myFunc(x + this.data.myVar) }}
The process of repainting / generating HTML according to reactive variables is more efficient than other frameworks and is only performed when necessary (in a specific DOM node), and not several times.
Redux
JuNe PaulaJS reactive variables are only triggered at each variable or object change, so it is more efficient than standard Redux systems where you have to reassign the entire object with setState({...state, ...variables...})
however you can design your own Redux system by assigning the variables directly to their object without reassigning the entire object.
To show if true using data-jpau-if
<div data-jpau-if="this.data.mustShow && this.data.mustBeTwo === 2">
...
</div>
To repeat content from variables or arrays using data-jpau-for
<div data-jpau-for="for(let i = 0; i < 5; ++i)">
<span>Number {{ i }}</span>
</div>
<table>
<tbody>
<tr data-jpau-for="for(let user of this.data.users)">
<td>Name {{ user.name }}</td>
</tr>
</tbody>
</table>
HTML pre
tag is skipped for processing, so it can be used for sample code.
Always use a previous parent container:
<div> <!-- parent -->
<div data-jpau-for="...">...</div>
</div>
<select> <!-- parent -->
<option data-jpau-for="...">
</select>
<table> <!-- parent -->
<tr data-jpau-for="...">
...
</tr>
</table>
Tag | Definition | Sample |
---|---|---|
jpau-content | Block content and routes definition | <jpau-content><jpau-route path="/" module="index"></jpau-route></jpau-content> |
jpau-route | Route definition to load JS modules according path | <jpau-route path="/" module="index"></jpau-route> <jpau-route path="/users/:id" module="users"></jpau-route> <jpau-route path="(default)" module="page404"></jpau-route> |
jpau-link | Link to route using is with HTMLAnchorElement Use it as a normal a href tag | <a href="/" is="jpau-link">Home</a> <a href="/users" is="jpau-link">Users</a> |
jpau-route attributes:
path: URL route path with variables.
module: name of the module to load, must be unique name.
background: Optional true to set a background module.
<jpau-route path="/" module="index"></jpau-route>
<jpau-route path="/users/:uid" module="modules/users" background="true"></jpau-route>
(default) For jpau-route if no routes found and load a module for 404 notice.
Navigate to a route using this.link(URL)
user.user_name
, customer.customer_name
(not mandatory)<span>{{ myvar }}</span>
this.importMod() is the function that loads the modules and is called internally on each link request. But if you look at the examples that are downloaded in the repository, they are individual files, outside of a routing system. So, you can make an app that is all in one file, without loading importing modules. JuNe PaulaJS structure can be in a file or in an object (with data, funcs and html).
Call | Definition | Go |
---|---|---|
importMod(filename) | Load ´filename´ JavaScript module | this.link(filename) |
importMod(filename, true) | Load ´filename´ JavaScript as backgroud module | this.link(filename) |
importMod(object) | Load object JavaScript module as index | this.importMod(object) |
importMod(object, name) | Load object JavaScript module as name | this.importMod(object, name) |
Sample single page:
<jpau-content></jpau-content>
<script>
const page1 = {
data: {},
funcs: {},
html: 'Page1 <input type="button" @click="this.importMod(page2, 'page2')" value="Go to Page2">'
};
const page2 = {
data: {},
funcs: {},
html: 'Page2 <input type="button" @click="this.importMod(page1, 'page1')" value="Go to Page1">'
};
june_pau.main = -1;
june_pau.importMod(page1, 'background');
</script>
<meta property="og:image" content="{{ og:image }}">
export const data = {
title: 'My Module Document Title',
'og:image': 'https://mydomain.tld/myimage.jpg'
};
We can´t have control over whether a spider/crawler interprets JavaScript to change headers / DOM.
Add to main.js
(for globally use).
Object | Type | Definition |
---|---|---|
langs | Array | Languages available |
texts | Array | Texts in each language |
en-US
and default: 'en'
then is selected if language is en-AU
or en-*
(and don´t exist).First try window.navigator.language or first one of langs array.
Sample:
export const langs = [
{code: 'en-US', name: 'English', icon: '🇬🇧', default: 'en'},
{code: 'en-AU', name: 'English (Australia)', icon: '🇦🇺'},
{code: 'es-ES', name: 'Español', icon: '🇪🇸', default: 'es'}
];
export const texts = {
'en-US': { ok: 'Ok',
cancel: 'Cancel',
deleteAsk: 'Delete?',
uploadSmallMsg: 'Maximum file size is 5 Mb'
uploadLargeMsg: 'Maximum file size is 50 Mb'
},
'en-AU': { ok: 'Ok',
cancel: 'Cancel',
deleteAsk: 'Delete?',
uploadSmallMsg: 'Maximum file size is 5 Mb'
uploadLargeMsg: 'Maximum file size is 50 Mb'
},
'es-ES': { ok: 'Aceptar',
cancel: 'Cancelar',
deleteAsk: '¿Eliminar?',
uploadSmallMsg: 'El tamaño máximo es 5 Mb'
uploadLargeMsg: 'El tamaño máximo es 50 Mb'
}
};
this.setLang('code')
or june_pau.setLang('code')
sample this.setLang('en-US')
this.lng
(as en-US, es-ES...)this.text(code)
const mynumberstr = new Intl.NumberFormat(this.lng, {maximumFractionDigits: 2}).format(mynumber)
For dates (year, month and day positions): const mydatestr = new Intl.DateTimeFormat(this.lng).format(new Date())
Internal language codes used:
Code | Function | Default |
---|---|---|
ok | If you want Ok button for this.windowShow | Ok |
cancel | If you want Cancel button for this.windowShow | Cancel |
deleteAsk | Ask for delete for this.windowDel | Delete sure? |
uploadSmallMsg | Notice maximum size small files upload | Maximum file size |
uploadLargeMsg | Notice maximum size large files upload | Maximum file size |
A modal window disables the main window but is visible, users must interact before they can return to main window.
To show this.windowShow(text[, options])
or june_pau.windowShow(text[, options])
To hide last this.windowHide()
or june_pau.windowHide()
Responds to keyboard (Esc, Return, Space).
Object | Type | Definition |
---|---|---|
okAction | Function | Function for ok button |
okText | String | HTML text to show in ok button or default ok language text |
cancelAction | Function | Function for cancel button, set to 0 for just hide |
cancelText | String | HTML text to show in cancel button or default cancel language text |
input | String | Input default value (or empty string) to request an input value passed to okAction |
noHide | Bool | If true window not hidden on button click, windowHide implemented manually |
winCSSbg | String | CSS class name for background instead internal styles default: background: rgba(255,255,255,0.83); backdrop-filter: blur(2px); transition: .5s ease |
winCSSfg | String | CSS class name for window instead internal styles default: margin: auto; padding: 8px; text-align: center; border-radius: 6px; background: #FFF; box-shadow: 1px 1px 10px #444; transform: scale(1.4); transition: .3s ease |
ok
and cancel
exist in main.js
winCSSbg
and winCSSfg
in this.main.data
this.windowDel(function_for_delete, optional_text)
Is a non-modal, unobtrusive element that displays a short message when an event occurs, and dissapears in a time. Also called passive pop-up, snackbar, bubble or notification.
To show: this.toastShow(text[, options])
or june_pau.toastShow(text[, options])
To hide last: this.toastHide()
or june_pau.toastHide()
Object | Type | Definition | Default |
---|---|---|---|
toastPos | String | Position [top or bottom] | top |
toastPY | Integer | End animation Y position (for top or bottom) | 50px |
toastTime | Integer | Millisecons to hide when Page Visibility (0 for no hide) | 3500 |
toastCSS | String | CSS class name for toast instead internal styles default: width: 80%; left: 10%; right: 10%; padding: 7px 9px; text-align: center; border-radius: 6px; box-shadow: 1px 1px 10px #CCC; color: #FFF; background: rgba(0,0,0,0.83); backdrop-filter: blur(2px); transition: .3s ease' | - |
this.main.data
.wincssbg {
background: rgba(255, 255, 255, 0.83);
backdrop-filter: blur(2px);
transition: .5s ease;
}
.wincssfg {
margin: auto;
padding: 8px;
text-align: center;
border-radius: 6px;
background: var(--jcbg);
box-shadow: 1px 1px 10px #444;
transform: scale(1.4);
transition: .3s ease;
div {
color: var(--jcclr);
line-height: 1.7em;
}
}
.toastcss {
width: 80%;
left: 10%;
right: 10%;
padding: 7px 9px 20px;
text-align: center;
border-radius: 6px;
box-shadow: 1px 1px 10px #CCC;
color: #FFF;
background: rgba(0,0,0,0.83);
backdrop-filter: blur(2px);
transition: .3s ease;
}
this.sendRequest(url[, method[, data[, pget]]])
Param | Type | Definition |
---|---|---|
url | String | URL to send request |
method | String | Optional HTTP method: GET (default), POST, PUT, PATCH, DELETE |
data | FormData / Array | Optional for POST/PUT/PATCH: FormData from this.fdata or data array object {"myvar1": 1, "var2": 2} |
pget | Object | Optional GET parameters to add to the URL |
Common uses: GET for read, POST for create, PUT for update, PATCH for modify and DELETE for delete.
main.data.backend_url
Object | Type | Definition | OnOk | OnError |
---|---|---|---|---|
status | Integer | HTTP status | ✅ | ❌ |
headers | Array | HTTP headers | ✅ | ❌ |
response | JSON | HTTP response | ✅ | ❌ |
error | Exception | Error | ❌ | ✅ |
⏱ This function is asynchronous, but you may prefer to use a promise, in that case and if you want to use the token system as well, you can use the sendRequest breakdown with:
const f = this.sendReqIni(url, method, data, pget);
fetch(f.url, f.options).then(response => {
const headers = this.sendReqEnd(response);
if(response.ok)
return response.json();
else
this.toastShow(`Error: ${response.statusText}`);
}).then(json => {
// Process JSON here
}).catch(err => {
this.idle(false);
this.toastShow(`Error: ${err}`);
});
Loader in a HTMLElement with initial style.visibility: hidden
and store the id string in main.data.loader
Then it will be shown on request, and hidden when finished calling this.idle(bool)
style="opacity: 0; transition: all .5s"
to hide page while loading, and this function to main.js
export const funcs = {onMount: () => document.body.style.opacity = 1}
then page will be shown with a fade on mount.<title data-jpauattr="1" data-jpauihtml="{{ title }}">My App title</title>
auth: true
to data
in main.js
main.data._token
main.data._auth
To facilitate data submit converting form inputs into a FormData with this.fdata(formId, reportValidity)
let data = this->fdata('frm')
data.append(name, value)
Using JuNe BackServer Captcha to prevent form spamming by bots. It´s in invisible for users.
app.get('/captcha', (req, res) => {
req.content.k = app.captcha();
});
frm
form), add captcha key and send:async function sendForm(id) {
let fd = june_pau.fdata('frm');
if(fd === false) return;
fd = june_pau.captcha(fd, 'http://localhost:8080/captcha');
let res = await june_pau.sendRequest('http://localhost:8080/post', 'POST', fd);
}
app.post('/post', (req, res) => {
if(!req.body.captcha || !app.captcha(req.body.captcha))
return;
// Ok
});
The operation is the following, before sending the form by the frontend, it sends a request to the backend that returns a key that is registered in the backend for one minute, the frontend forwards it to the backend and it is verified that it exists. Since a FormData is used, the captcha key request is done first and then the form submit. Therefore, indicate a different and useless URL in the form action so that the bots waste time there.
Forget about the complication of a file upload system, which can be multiple and with large files. Just receive the file and nothing else.
webkitdirectory
(for directory upload) or multiple
(for more than 1 file).main.data.beforeunload
a notice window warning if unload and still files uploading.⚠️Be careful and do not allow uploads without check user login in frontend and backend.
For small files (< 12 Mb) you could use this.fdata , and the submit will be like a normal form. To enable this:
data-jpau-upload="small"
in file input <input type="file" name="myfile" data-jpau-upload="small">
this.main.data.uploadSmallMax
recomended 5120
5 Mb (default 0
for no limit).uploadSmallMsg
language code if different value to Maximum file size
myfile_WIDTH
and myfile_HEIGHT
JuNe BackServer combines these fields into the same object {name: FileName, type: Content-Type, size: FileSize, width: ImageWidth, height: ImageHeight}
Files are sent in 2 Mb-blocks with PUT method.
Each block is sent to URL data-jpau-action
or action
from input form.
Add dataset data-jpau-upload="large"
in file input <input type="file" name="myfile" data-jpau-upload="large">
Set maximum Kb size in this.main.data.uploadLargeMax
recommended 51200
50 Mb (default 0
for no limit).
Set uploadLargeMsg
language code if different value to Maximum file size
This input can´t be required.
You can add the dataset data-jpau-upload-id
or if not a random number will be generated with this.genId()
So the server can identify parts from the same request and section.
upload Id name is the name of the input field concatenated with number file, myvar
for first, myvar_1
for second, myvar_2
for third...
Variables sent to server using upload Id name and sufixed with _ID, _RND, _NAME, _TYPE, _SIZE, _WIDTH, _HEIGHT, _PATH, _PART, _PARTS:
myvar_ID: Id from data-jpau-upload-id
maybe random or a section code, to avoid different concatenations from several requests.
myvar_RND: Unique randon number.
myvar_NAME: file name.
myvar_TYPE: file content-type.
myvar_SIZE: file size.
myvar_WIDTH: image width (if file is image).
myvar_HEIGHT: image height (if file is image).
myvar_PATH: file path (webkitRelativePath: relative path to selected directory).
myvar_PART: file part (0, 1, 2, 3...).
myvar_PARTS: file total part (0, 1, 2, 3...).
myvar: file content part (raw).
Server must concatenate each file request, during the process must use _ID and _RND to avoid different sources.
Why 2 random codes? ID maybe used to identificate a section in your project (1 for user files, 2 for user images...), and RND is a unique Id to ensure differentiate the same file while uploading.
To allow adding files via Drag & Drop or clipboard, just add data-jpau-upload-target
with the id
of the file input target, then the element can accept Drag & Drop, paste image from clipboard, or paste files (only Chromium browsers).
If <input type="file" id="myfile" name="myfile" data-jpau-upload="large">
Then this div accepts drag and paste: <div data-jpau-upload-target="myfile">Drop / Paste here</div>
Change drag over default (#cfc) background color in data.main.dragColor
Drop and paste it´s for large files due these events contain the files and must be sent at the same time.
Files added or removed in object this.main.files
for a whole global/general control, with:
ID_RND_NAME
ID from myvar_ID, RND from myvar_RND and NAME from upload Id name{name: FileName, size: FileSize, upload: UploadedSize}
A key for totals is updated in each file operation {size: TotalSize, upload; TotalUploaded, percent: PercentUploaded}
this.main.files.total.size
total pending files size.
this.main.files.total.upload
total already uploaded.
this.main.files.total.percent
percent total already uploaded.
You can use this.sizeUnit(integer)
to show sizes in byte metric unit (Kb, Mb...).
Loader in a HTMLElement with initial style.visibility: hidden
and store the id string in main.data.loader
Then it will be shown on first large upload file, and hidden when finished all upload files calling this.idle(bool)
accept
attribute to limit file typeThis limitation will be use on files selection.
Only images:
<input type="file" name="myimage" accept="image/*" data-jpau-upload="large">
Only PDF:
<input type="file" name="mypdf" accept="application/pdf" data-jpau-upload="large">
Only Word:
<input type="file" name="mypdf" accept=".doc,.docx,application/msword" data-jpau-upload="large">
capture
attribute to read from device camera or microphoneuser: user facing or front facing camera and or microphone. environment: outer facing or back facing camera and or microphone.
Image:
<input type="file" id="myimage" name="myimage" capture="user" accept="image/*" data-jpau-upload="small">
Audio:
<input type="file" name="myaudio" name="myaudio" capture="user" accept="audio/*" data-jpau-upload="small">
Video:
<input type="file" id="myvideo" name="myvideo" capture="environment" accept="video/*" data-jpau-upload="large"
And use capture attribute to show a button to activate camera/microphone (add ´display: none´ to each input above):
<button *disabled="!this.e('myimage').capture" @click="this.e('myimage').click()">📷</button>
<button *disabled="!this.e('myaudio').capture" @click="this.e('myaudio').click()">🎤</button>
<button *disabled="!this.e('myvideo').capture" @click="this.e('myvideo').click()">📹</button>
export const funcs = {
onUpload: (e) => {
if(e.target) {
alert('Files: ' + e.target.files.length);
alert('File size: ' + e.target.files[0].size);
return true;
}
if(e.dataTransfer) {
alert('Drag & Drop, files: ' + e.dataTransfer.files.length);
return false;
}
}
};
export const funcs = {
onPreview: (container, idName) => {
// Preview container created: this.e(container);
}
};
export const funcs = {
onUploadEnd: (idName) => {
alert(`Finished ${idName}`);
}
};
export const funcs = {
onUploading: (cfile, iname, id, part, parts) => {
}
};
data-jpau-resize
in format (width)x(height), sample 1280x720
Also add data-jpau-upload
for small or large and accept
for images:<input type="file" name="myimage" data-jpau-upload="small" data-jpau-resize="1280x720" accept="image/*">
Create a template with an id
as explained below:
<template id="mytemplate"></template>
Create a <div>
with an id
at the place you want to show the preview / file information, use the dataset data-jpau-template
to specify the id of the template:
<div id="mypreview" data-jpau-template="mytemplate"></div>
Add to the file input or drop zone the dataset data-jpau-preview
with the id of the preview:
<input type="file" name="myfile" data-jpau-upload="small" data-jpau-preview="mypreview">
Create a <template>
with an id with the same name as div preview data-jpau-template
Add all optional HTMLElement with dataset data-jpau-element
with the element definition (and you can see the attribute changed):
progress* and time* only for large not for small.
this.sizeUnit
(innerText).fa-2xl
(className).And data-jpau-element-show
for show or hide until load complete:
<template id="mytemplate">
<img data-jpau-element="img"><br>
<i data-jpau-element="icon"></i>
Name: <span data-jpau-element="name"></span><br>
Size: <span data-jpau-element="size"></span><br>
<div data-jpau-element-show="loading">
<progress data-jpau-element="progress" max="100"></progress>
<span data-jpau-element="abort" class="cp">╳</span><br>
<span data-jpau-element="timeElapsed"></span> / <span data-jpau-element="timeEstimated"></span>
</div>
<div data-jpau-element-show="finish">Ok</div>
<div data-jpau-element-show="error" style="color: red"></div>
</template>
It´s an exclusive feature of JuNe PaulaJS that allows the current page (module) to be sent to the background, and to keep running when a new page (module) is loaded, and if it is reloaded again (for example selecting the link by the user), then the page (module) will be shown again in the foreground and without reloading the file again.
You can load another module (page) and the current one stays in background, then if the route shows it, it returns to foreground keeping all the status. By example in files upload modules/sections.
Module name is the file name, so don´t use same file names in different folders.
Do not abuse background modules to avoid browser memory problems.
⚠️ Important If you decide to create modules to send to background, you can´t repeat any Id in the whole project, be sure to use different names so as not to interfere with other modules.
To define a module for background, set background="true"
in route <jpau-route path="/sample" module="sample" background="true"></jpau-route>
You must use this.bgmod[module].data
to access data variables in background instead this.data, and this.bgmod[module].funcs.FUNCTION
to call module functions.
Optional function this.funcs.onVisible(status)
is called with the status boolean parameter to indicate visible (true) or sent to background (false).
To create share buttons getting links with this.socialShare([title[, url]])
document.title
window.location
Returns an object with icon object for Font Awesome class, and link for share link.let share = this->socialShare();
`<a href="${share.facebook.link}" target="_blank" title="Share with Facebook"><i class="${share.facebook.icon}"></i></a>`
If the browser supports speech recognition (only HTTPS), you can:
this.voiceLang()
initializes the language to be used, if no parameter is specified it will use the language set if languages have been declared in main file, or it will get the browser default language.
Forces a language with its code this.voiceLang('en-US')
You must create a button and either disable it or make it visible depending on whether the browser supports recognition using the this.voiceOpts()
function.
<button *disabled="!this.voiceOpts().speech" @click="this.funcs.speechRecog()">🎤 Speak here</button>
this.voiceOpts()
returns an object with 2 values:
Starts speech recognition with this.speech(callAlways, function, noProcess)
all parameters are optional:
To set voice commands, add data-jpau-speech
attribute with the text to be recognized:
<a href="/mypage" data-jpau-speech="My page" is="jpau-link">My page</a>
<input type="reset" value="Cancel" data-jpau-speech="Cancel">
So when you speak into the microphone, you can navigate to a page or perform a button action.
export const funcs = {
toText: function(v) { // Set voice value to a HTMLInputElement
this.e('txtSpeech').value = v;
},
speechRecog1: function() { // Initializes speech with voice commands else call toText
this.voiceLang();
this.speech(false, this.funcs.toText);
},
speechRecog2: function() { // Initializes speech with voice commands and call toText
this.voiceLang();
this.speech(true, this.funcs.toText);
},
speechRecog3: function() { // Initializes speech without voice commands and call toText
this.voiceLang();
this.speech(true, this.funcs.toText, true);
}
};
First, set the language with this.voiceLang()
(as explained in speech recognition).
Optionally you can set a voice, listing from this.voiceOpts().voices
that returns an array with name and lang, so you could make a HTML select.
Sample to show in browser console:
this.voiceOpts().voices.forEach(e => console.log(`Name: ${e.name} - Language: ${e.lang}`));
Set voice element object in this.voiceLang(false, voice)
second parameter, and language to false, to use set language or browser language.
Start a speech with speak(obj, text, speaker, play, pause)
export const funcs = {
speakText: function(obj, txt) {
this.voiceLang();
this.speak(this.e(obj), this.e(txt).value, '🔊', '▶️', '⏸️');
},
};
export const html = `
<textarea id="txtSpeak">This is a sample text</textarea>
<button id="bttSpeak" @click="this.funcs.speakText('bttSpeak', 'txtSpeak')">🔊</button>
`;
With FontAwesome
export const funcs = {
speakText: function(obj, txt) {
this.voiceLang();
this.speak(this.e(obj), this.e(txt).value, '<i class="fa-solid fa-volume-high fa-fw"></i>', '<i class="fa-solid fa-play fa-fw"></i>', '<i class="fa-solid fa-pause fa-fw"></i>');
},
};
export const html = `
<textarea id="txtSpeak">This is a sample text</textarea>
<button id="bttSpeak" @click="this.funcs.speakText('bttSpeak', 'txtSpeak')"><i class="fa-solid fa-volume-high fa-fw"></i></button>
`;
Name | Value | Definition |
---|---|---|
data-jpau-if | JavaScript Code | If command |
data-jpau-for | JavaScript Code | For command |
data-jpau-speech | Text | For commands speech recognition |
data-jpau-upload | small/large | File input upload type |
data-jpau-action | URL | Action URL for upload large files with PUT (or form action) |
data-jpau-upload-id | Id code | Unique Id for upload same file |
data-jpau-upload-target | Id HTMLElement | Target HTMLElement from a Drag & Drop / clipboard paste HTMLElement |
data-jpau-resize | widthxheight | Resize input images |
data-jpau-template | Id HTMLElement | Template HTMLElement for uploads |
data-jpau-preview | Id HTMLElement | Preview HTMLElement for uploads |
data-jpau-element | Code | Preview template element (img, cancel, name, size, icon...) |
data-jpau-show | Code | Preview template allow show (loading, finish ,error) |
this or june_pau according scope. Have a look to functions to help you to develop your project as prepHTML, html2text, htmlEntities, sizeUnit, fileIcon, socialShare...
Function | Param | Definition |
---|---|---|
this.prepHTML(element) | parentNode | Prepare HTML if new added to DOM (document for all) |
this.load(object) | main | To configure the object directly instead of importing module |
this.importMod(string ∣ object[, bg]) | filename ∣ module, bg | Import module with filename or using object directly, and background module |
this.link(string) | URL | Navigate to route (sample /users/23 ) and assign params/getparams |
this.setLang(string) | lang | Set language (as window.navigator.language) |
this.genId() | - | Generate an unique Id |
this.e(string) | id | Return document.getElementById (HTMLElement) |
this.updElm(element) | HTMLElement | Update element |
this.updHTML() | - | Update all |
this.text(string) | key | Return text code in current language |
this.html2text(string) | html | Remove HTML tags and returns only text |
this.htmlEntities(string) | html | Convert applicable characters to HTML entities (& < > ") |
this.sizeUnit(integer) | bytes | Returns string with format in byte metric unit 1.95 Kb for 2000 |
this.idle(bool) | show | Show or hide this.main.data.loader if exists |
this.shake(element) | HTMLElement | Shake effect to element (5 ms) |
this.stopp() | - | Event prevent default and stop propagation |
this.windowShow(string[, array]) | html, options | Show modal window |
this.windowHide() | - | Hide last modal window |
this.windowDel(function[, text]) | function if confirm, optional text | Predefined delete ask window |
this.toastShow(string[, array]) | html, options | Show toast notification |
this.toastHide() | - | Hide last toast notification |
this.sendRequest(string[, string, array, object]) | URL, method, data, getparams | Async send requests (CRUD operations) |
this.fdata(string[, bool]) | id, check | Create FormData from form inputs, check validation |
this.captcha(formdata, string) | formdata, URL | Add captcha to formdata from URL endpoint |
this.fileIcon(string) | filename | Returns file type Font Awesome icon |
this.socialShare([string[, string]]) | title, URL | Returns array for Social Network share buttons |
this.voiceLang([string[, voice]]) | lang, voice | Set optional language for speech/synthesis, and voice |
this.voiceOpts() | - | Returns array if browser supports speech recognition (speech), and voices for synthesis |
this.speech([bool, function, bool]) | callAlways, function, noProcess | Starts speech recognition |
this.speak(element, string, string, string, string) | HTMLElement, text, speaker, play, pause | Speak speech |
st=>start: Start
op1=>operation: main.funcs.onLoad
op2=>operation: module.funcs.onLoad
op3=>start: Performed HTML
op4=>operation: module.funcs.onVisible(true)
op5=>operation: main.funcs.onMount [once]
op6=>operation: module.funcs.onMount
st->op1->op2->op3->op4->op5->op6
You can run your project without a HTTP server (development), but to run a PaulaJS project you can use this HTTP server: JuNe WebServer that is integrated and reloads page on new changes, so you can launch it opening a terminal in your project folder and type npm run webserver
and it will open your default browser, if you want a specific file use index parameter npm run webserver -index myfile.html
If you see examples that send requests to a backend as upload files, open another terminal and run npm run backend
to see the information for each request.
Build project it´s not neccesary because you can copy your files and PaulaJS file for distribution.
If you want to offuscate your code or facilitate the installation copying all in dist/ folder.
First install Uglify-JS globally to reduce files size and make it difficult to view your source code.
npm install -g uglify-js
So if you have installed JuNe PaulaJS globally run paulajs build
Or if it´s local npm run build
/myparam1/myparam2/myparam3
/index.html
as main file:server {
...
location / {
try_files $uri $uri/ /index.html?$args;
}
...
}
.htaccess
# BEGIN JuNe PaulaJS
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
# END JuNe PaulaJS
https://github.com/EduardoRuizM/junedns-frontend
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
File | Description |
---|---|
dev/ | Development or production programs |
∟ backend.js | Backend for JuNe PaulaJS test purposes examples |
∟ webserver.js | JuNe WebServer for run in development or production mode |
∟ paulajs.js | Utility for create template or build project |
∟ backserver.js | JuNe BackServer |
∟⎽⎽⎽⎽ template/ | Files to create a PaulaJS project |
examples/ | JuNe PaulaJS examples and files (also used for project templates creation) |
june-paula.js | JuNe PaulaJS file |
june-paula.min.js | JuNe PaulaJS minified file |
logo.png | JuNe PaulaJS logo |
package.json | JuNe PaulaJS package.json |
README.md | Full and detailed JuNe PaulaJS documentation |
Everything you need to develop your project:
FAQs
JuNe PaulaJS (Portable Adaptable Utility for Lightweight Applications) JavaScript framework to build frontend, user interfaces, Single-page application or Progressive Web App
We found that june-paulajs demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.