Svelte: Disable ESLint Rule - eslint

I'm working on a Svelt project that uses ESlint, and I'm trying to disable a rule within my svelte template but can't find any information on how to do so. My code is the following:
<script lang="ts">
const unsubscribe = promiseWritable.subscribe((value) => {
promise = value;
});
onDestroy(unsubscribe);
</script>
{#if !!promise} <---- ESLint error here!
{#await promise then promiseResult}
<Info {promiseResult} />
{/await}
{/if}
This results in {#if !!promise} having the ESLint error:
Expected non-Promise value in a boolean conditional.eslint#typescript-eslint/no-misused-promises)
Regardless of whether I should disable this rule, I'm wondering how I would disable it within the file since adding either:
// eslint-disable-next-line... or <!-- eslint-disable-next-line... -->
above the line won't disable the error.
For Reference I am using https://github.com/sveltejs/eslint-plugin-svelte3

Since this commit, you can now add a "magic comment" to your Svelte file to disable individual validations using the form <!-- svelte-ignore rule-name -->.
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
<div on:mouseover={mouseOver} on:mouseleave={mouseLeave} class="wrapper">
<slot name="content" />
</div>

The eslint-plugin-svelte plugin works fine with <!-- eslint-disable --> directives in svelte templates.
https://github.com/ota-meshi/eslint-plugin-svelte

I found a somewhat unsatisfying solution by adding /* eslint-disable */ to the bottom of the script tag giving us:
<script lang="ts">
const unsubscribe = promiseWritable.subscribe((value) => {
promise = value;
});
onDestroy(unsubscribe);
/* eslint-disable */
</script>
{#if !!promise} <---- No ESLint error anymore
{#await promise then promiseResult}
<Info {promiseResult} />
{/await}
{/if}
This will disable all linting in the HTML template.

You can set the settings.svelte3/named-blocks to true in your eslint config. Docs on svelte3/named-blocks. Then modify the targetted svelte files in overrides, and add template into ignorePatterns.
Such way requires no ...eslint-disable... in source files.
# .eslintrc.cjs
...
ignorePatterns: [
"**/*.svelte/*_template.ts",
],
overrides: [{ files: ["**/*.svelte/*.ts"], processor: "svelte3/svelte3" }],
settings: {
"svelte3/typescript": () => require("typescript"),
"svelte3/named-blocks": true,
},
...
Related GitHub issue

Related

Chrome Extension Manifest V3 permission for Javascript [duplicate]

This seems to be the easiest thing to do, but it's just not working. In a normal browser the .html and .js files works perfectly, but in the Chrome/Firefox extension the onClick function is not performing what it's supposed to do.
.js file:
function hellYeah(text) {
document.getElementById("text-holder").innerHTML = text;
}
.html file:
<!doctype html>
<html>
<head>
<title>
Getting Started Extension's Popup
</title>
<script src="popup.js"></script>
</head>
<body>
<div id="text-holder">
ha
</div>
<br />
<a onClick=hellYeah("xxx")>
hyhy
</a>
</body>
</html>
So basically once the user clicks "hyhy", "ha" should change into "xxx". And again - it works perfectly in the browser but does not work in the extension. Do you know why? Just in case I'm attaching the manifest.json below as well.
manifest.json:
{
"name": "My First Extension",
"version": "1.0",
"manifest_version": 2,
"description": "The first extension that I made.",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"permissions": [
"http://api.flickr.com/"
]
}
Chrome Extensions don't allow you to have inline JavaScript (documentation).
The same goes for Firefox WebExtensions (documentation).
You are going to have to do something similar to this:
Assign an ID to the link (<a onClick=hellYeah("xxx")> becomes <a id="link">), and use addEventListener to bind the event. Put the following in your popup.js file:
document.addEventListener('DOMContentLoaded', function() {
var link = document.getElementById('link');
// onClick's logic below:
link.addEventListener('click', function() {
hellYeah('xxx');
});
});
popup.js should be loaded as a separate script file:
<script src="popup.js"></script>
Reason
This does not work, because Chrome forbids any kind of inline code in extensions via Content Security Policy.
Inline JavaScript will not be executed. This restriction bans both inline <script> blocks and inline event handlers (e.g. <button onclick="...">).
How to detect
If this is indeed the problem, Chrome would produce the following error in the console:
Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' chrome-extension-resource:". Either the 'unsafe-inline' keyword, a hash ('sha256-...'), or a nonce ('nonce-...') is required to enable inline execution.
To access a popup's JavaScript console (which is useful for debug in general), right-click your extension's button and select "Inspect popup" from the context menu.
More information on debugging a popup is available here.
How to fix
One needs to remove all inline JavaScript. There is a guide in Chrome documentation.
Suppose the original looks like:
<a onclick="handler()">Click this</a> <!-- Bad -->
One needs to remove the onclick attribute and give the element a unique id:
<a id="click-this">Click this</a> <!-- Fixed -->
And then attach the listener from a script (which must be in a .js file, suppose popup.js):
// Pure JS:
document.addEventListener('DOMContentLoaded', function() {
document.getElementById("click-this").addEventListener("click", handler);
});
// The handler also must go in a .js file
function handler() {
/* ... */
}
Note the wrapping in a DOMContentLoaded event. This ensures that the element exists at the time of execution. Now add the script tag, for instance in the <head> of the document:
<script src="popup.js"></script>
Alternative if you're using jQuery:
// jQuery
$(document).ready(function() {
$("#click-this").click(handler);
});
Relaxing the policy
Q: The error mentions ways to allow inline code. I don't want to / can't change my code, how do I enable inline scripts?
A: Despite what the error says, you cannot enable inline script:
There is no mechanism for relaxing the restriction against executing inline JavaScript. In particular, setting a script policy that includes 'unsafe-inline' will have no effect.
Update: Since Chrome 46, it's possible to whitelist specific inline code blocks:
As of Chrome 46, inline scripts can be whitelisted by specifying the base64-encoded hash of the source code in the policy. This hash must be prefixed by the used hash algorithm (sha256, sha384 or sha512). See Hash usage for <script> elements for an example.
However, I do not readily see a reason to use this, and it will not enable inline attributes like onclick="code".
I had the same problem, and didnĀ“t want to rewrite the code, so I wrote a function to modify the code and create the inline declarated events:
function compile(qSel){
var matches = [];
var match = null;
var c = 0;
var html = $(qSel).html();
var pattern = /(<(.*?)on([a-zA-Z]+)\s*=\s*('|")(.*)('|")(.*?))(>)/mg;
while (match = pattern.exec(html)) {
var arr = [];
for (i in match) {
if (!isNaN(i)) {
arr.push(match[i]);
}
}
matches.push(arr);
}
var items_with_events = [];
var compiledHtml = html;
for ( var i in matches ){
var item_with_event = {
custom_id : "my_app_identifier_"+i,
code : matches[i][5],
on : matches[i][3],
};
items_with_events.push(item_with_event);
compiledHtml = compiledHtml.replace(/(<(.*?)on([a-zA-Z]+)\s*=\s*('|")(.*)('|")(.*?))(>)/m, "<$2 custom_id='"+item_with_event.custom_id+"' $7 $8");
}
$(qSel).html(compiledHtml);
for ( var i in items_with_events ){
$("[custom_id='"+items_with_events[i].custom_id+"']").bind(items_with_events[i].on, function(){
eval(items_with_events[i].code);
});
}
}
$(document).ready(function(){
compile('#content');
})
This should remove all inline events from the selected node, and recreate them with jquery instead.
I decide to publish my example that I used in my case. I tried to replace content in div using a script. My problem was that Chrome did not recognized / did not run that script.
In more detail What I wanted to do: To click on a link, and that link to "read" an external html file, that it will be loaded in a div section.
I found out that by placing the script before the DIV with ID that
was called, the script did not work.
If the script was in another DIV, also it does not work
The script must be coded using document.addEventListener('DOMContentLoaded', function() as it was told
<body>
<a id=id_page href ="#loving" onclick="load_services()"> loving </a>
<script>
// This script MUST BE under the "ID" that is calling
// Do not transfer it to a differ DIV than the caller "ID"
document.getElementById("id_page").addEventListener("click", function(){
document.getElementById("mainbody").innerHTML = '<object data="Services.html" class="loving_css_edit"; ></object>'; });
</script>
</body>
<div id="mainbody" class="main_body">
"here is loaded the external html file when the loving link will
be clicked. "
</div>
As already mentioned, Chrome Extensions don't allow to have inline JavaScript due to security reasons so you can try this workaround as well.
HTML file
<!doctype html>
<html>
<head>
<title>
Getting Started Extension's Popup
</title>
<script src="popup.js"></script>
</head>
<body>
<div id="text-holder">ha</div><br />
<a class="clickableBtn">
hyhy
</a>
</body>
</html>
<!doctype html>
popup.js
window.onclick = function(event) {
var target = event.target ;
if(target.matches('.clickableBtn')) {
var clickedEle = document.activeElement.id ;
var ele = document.getElementById(clickedEle);
alert(ele.text);
}
}
Or if you are having a Jquery file included then
window.onclick = function(event) {
var target = event.target ;
if(target.matches('.clickableBtn')) {
alert($(target).text());
}
}

Selectize disable sifter

I am trying to implement selectize javascript library. It works but my question is how do I disable the sifter option. The problem is by default sifter option is enabled and if I have words like Asset in the option, it will be filtered to become et.
I tried with below but doesn't work:
score: function () {
return function () {
return 1
}
}
Selectize is very dependent on sifter, I don't see a easy way to disable that, and I think if you do that, you get rid of most of (maybe the entire) selectize search feature.
sifter has an config option in its last version that can help you to achieve what you want, the config option is respect_word_boundaries:
If true, matches only at start of word boundaries (e.g. the beginning of words, instead of matching the middle of words)
The problem is selectize doesn't not use the latest version, so you have to use the not all-in-all bundled version of selectize called "default".
Make sure you're using sifter version 0.6.0.
I tried to do some tweaks using plugins on selectize to get this working. Check the result below:
Selectize.define('change_search', function(options) {
var self = this;
this.getSearchOptions = (function() {
var original = self.getSearchOptions();
return function() {
original['respect_word_boundaries'] = true;
return original;
};
})();
});
$(document).ready(function() {
$('#search').selectize({
plugins: ['change_search']
});
});
.search {
width: 300px;
margin: 10px;
display: block;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.12.6/css/selectize.default.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/microplugin/0.0.3/microplugin.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/sifter/0.6.0/sifter.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.12.6/js/selectize.min.js"></script>
<div class='search'>
<select placeholder="Choose one option..." id="search" multiple="multiple">
<option value="asset">Asset</option>
<option value="etc">Etcetera</option>
<option value="etymology">Etymology</option>
<option value="yet">Yet</option>
</select>
</div>

How to use jsx in preact via cdn?

got this code from preact's site, and try to make it work without babel building process, but failed, anybody knows if this is possible? Thanks,
http://jsfiddle.net/e281k4wz/117/
'use strict';
const { Component, h, render } = window.preact;
render((
<div id="foo">
<span>Hello, world!</span>
<button onClick={ e => alert("hi!") }>Click Me</button>
</div>
), document.body);
Yes. You have to include babel before your jsx code and use the script as type="text/babel" see the following example with react
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/#babel/standalone/babel.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
</head>
<body>
<div id="app"></div>
<script type="text/babel">
class App extends React.Component {
render() {
return (
<div className="app-content">
<h1>Hello from React</h1>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('app'));
</script>
</body>
</html>
You cannot directly use the JSX into the JavaScript as it's a invalid syntax.
For running the preact into the client you have to either transpile the jsx code into valid javascript or use the helper method (Component , h , render) provided by preact.
HTML
<h1>Render by Preact client library using h and render function</h1>
<div id="preact">
</div>
JavaScript
var Component = window.preact.Component,
h = window.preact.h,
render = window.preact.render;
var PreactApp = function (props){
return h('h1',
{className: ''},
'Hello from Preact world!');
}
render(PreactApp(),document.getElementById("preact"));
Here in JS if you see h ( converting jsx to vdom ) and render (converting vdom to html ) function actually do the magic. Read more about from the official documentation - https://preactjs.com/guide/api-reference
Working example - https://jsfiddle.net/97125m3z/2/
Technically it is possible by using the HTM package, as long as you're targeting recent browsers that understand template strings. See https://github.com/developit/htm for details.
However, this will render slower than simply creating the components using h() as it is a whole heap of string parsing. It also makes it difficult to use syntax highlighting in your IDE, which makes debugging frustrating.
I used HTM when I was first getting used to using Preact without a build step, but very quickly replaced it with manually creating the components and eliminated the JSX.
You get a better understanding of how everything fits together if you don't use the JSX abstraction. Babel compiles it down into createElement calls anyway.

A way to render multiple root elements on VueJS with v-for directive

Right now, I'm trying to make a website that shows recent news posts which is supplied my NodeJS API.
I've tried the following:
HTML
<div id="news" class="media" v-for="item in posts">
<div>
<h4 class="media-heading">{{item.title}}</h4>
<p>{{item.msg}}</p>
</div>
</div>
JavaScript
const news = new Vue({
el: '#news',
data: {
posts: [
{title: 'My First News post', msg: 'This is your fist news!'},
{title: 'Cakes are great food', msg: 'Yummy Yummy Yummy'},
{title: 'How to learnVueJS', msg: 'Start Learning!'},
]
}
})
Apparently, the above didn't work because Vue can't render multiple root elements.
I've looked up the VueJS's official manual and couldn't come up with a solution.
After googling a while, I've understood that it was impossible to render multiple root element, however, I yet to have been able to come up with a solution.
The simplest way I've found of adding multiple root elements is to add a single <div> wrapper element and make it disappear with some CSS magic for the purposes of rendering.
For this we can use the "display: contents" CSS property. The effect is that it makes the container disappear, making the child elements children of the element the next level up in the DOM.
Therefore, in your Vue component template you can have something like this:
<template>
<div style="display: contents"> <!-- my wrapper div is rendered invisible -->
<tr>...</tr>
<tr>...</tr>
<tr>...</tr>
</div>
</template>
I can now use my component without the browser messing up formatting because the wrapping <div> root element will be ignored by the browser for display purposes:
<table>
<my-component></my-component> <!-- the wrapping div will be ignored -->
</table>
Note however, that although this should work in most browsers, you may want to check here to make sure it can handle your target browser.
You can have multiple root elements (or components) using render functions
A simple example is having a component which renders multiple <li> elements:
<template>
<li>Item</li>
<li>Item2</li>
... etc
</template>
However the above will throw an error. To solve this error the above template can be converted to:
export default {
functional: true,
render(createElement) {
return [
createElement('li', 'Item'),
createElement('li', 'Item2'),
]
}
}
But again as you probably noticed this can get very tedious if for example you want to display 50 li items. So, eventually, to dynamically display elements you can do:
export default {
functional: true,
props: ['listItems'], //this is an array of `<li>` names (e.g. ['Item', 'Item2'])
render(createElement, { props }) {
return props.listItems.map(name => {
return createElement('li', name)
})
}
}
INFO in those examples i have used the property functional: true but it is not required of course to use "render functions". Please consider learning more about functional componentshere
Define a custom directive:
Vue.directive('fragments', {
inserted: function(el) {
const children = Array.from(el.children)
const parent = el.parentElement
children.forEach((item) => { parent.appendChild(item) })
parent.removeChild(el)
}
});
then you can use it in root element of a component
<div v-fragments>
<tr v-for="post in posts">...</tr>
</div>
The root element will not be rendered in DOM, which is especially effective when rendering table.
Vue requires that there be a single root node. However, try changing your html to this:
<div id="news" >
<div class="media" v-for="item in posts">
<h4 class="media-heading">{{item.title}}</h4>
<p>{{item.msg}}</p>
</div>
</div>
This change allows for a single root node id="news" and yet still allows for rendering the lists of recent posts.
In Vue 3, this is supported as you were trying:
In 3.x, components now can have multiple root nodes! However, this does require developers to explicitly define where attributes should be distributed.
<!-- Layout.vue -->
<template>
<header>...</header>
<main v-bind="$attrs">...</main>
<footer>...</footer>
</template>
Multiple root elements are not supported by Vue (which caused by your v-for directive, beacause it may render more than 1 elements). And is also very simple to solve, just wrap your HTML into another Element will do.
For example:
<div id="app">
<!-- your HTML code -->
</div>
and the js:
var app = new Vue({
el: '#app', // it must be a single root!
// ...
})

How to write a lodash template loader for requirejs

I'm using a requirejs plugin to define "tmpl!" loader (not a jquery template, but a lodash template. The problem is that the text! loader is adding a ";" at the end of the template. This is being rendered and is breaking everything.
(function(global){
"use strict";
define({
load : function(name, require, load, config) {
var deps = [];
deps.push('text!' + name);
deps.push('underscore');
require(deps, function(source, _) {
var template = _.template(source);
load(template);
});
}
});
})(this);
How can I stop text! from adding a semi-colon? Or: is there a better way to do this?
Taking the questions in reverse order:
is there a better way to do this?
It seems there is an existing implementation of this, and you might want to consider using it rather than writing your own. Although the simple case is a small amount of code, there are a bunch of r.js optimizer-related things you might eventually need.
But regarding your implementation logic, I noticed that this similar project for Handlebars does not use the text! plugin but instead does its own XHR in the load() method. This is not explained, but he gives some guidance for adapting it to other templating languages. Note: the link came from this question where there is some other good discussion of the approach.
How can I stop text! from adding a semi-colon?
I tried your plug-in and did not get any added semicolons. Perhaps you could post more of the sample project and templates? Below is mine, with everything in one flat folder for simplicity:
require.js: latest from RequireJS site
domReady.js: latest from RequireJS site
text.js: latest from RequireJS site
lodash.js: latest from lodash site
tmpl.js: your example loader from the question
index.html:
<!DOCTYPE html>
<html>
<head>
<script src='require.js'></script>
<script>
requirejs.config({
map: {
'*': { 'underscore': 'lodash' }
}
});
require( [ 'underscore', 'tmpl!friend-template.htm', 'domReady!' ]
, function( _, friendTemplate ){
var friendsData = [{ name: 'Bob', age: 35 }, { name: 'Fred', age: 38 }];
document.body.innerHTML = friendTemplate( {friends: friendsData});
});
</script>
</head>
<body>
<!-- To be populated dynamically. -->
</body>
</html>
friend-template.htm:
<ul>
<% _.forEach(friends, function(friend) { %>
<li>
<span><%- friend.name %></span>
<span>( Age: <span class="value"><%- friend.age %></span> )</span>
</li>
<% }); %>
</ul>
I've created a loader specifically for Lo-Dash which you can see here:
https://gist.github.com/tbranyen/6821045
Note: I have no unit tests or assurances this free of bugs, but from my initial testing it appears to work fantastic.
This is better in a number of ways than requirejs-tpl which bakes in it's own implementation which is not exposed. It also requires a file extension and hardcoded path. Both of these are configurable in my code.
Edit: I've since released a project called lodash-template-loader which has tests. https://github.com/tbranyen/lodash-template-loader

Resources