#StackBounty: #javascript #node.js #api #express #passport.js How to Authenticate & Authorize a Client-Side Web App using Remote No…

Bounty: 50

As shown in the illustration below, I have a standalone API Project running on a server with a port say 3001, and I have a Web App running on a server with port say 3002.

Flow of Web APP to API

API on port 3001, has all the API routes required for the Web App (& mobile apps) to fetch and put data, including Authentication API (Using passport-local and passport-jwt). In the API side of the project, I have also handled user role authorization, and every routes has list of roles who can access the APIs.

Example Route

todoRoutes.get('/', 
               requireAuth,
               AuthController.roleAuth(['user','editor','admin']),
               TodoController.getTodos);

Role Authorization API Method in port 3001

exports.roleAuth = function(roles){

    return function(req, res, next){

        var user = req.user;

        User.findById(user._id, function(err, foundUser){

            if(err){
                res.status(422).json({error: 'No user found.'});
                return next(err);
            }

            if(roles.indexOf(foundUser.role) > -1){
                return next();
            }

            res.status(401).json({error: 'You are not authorized to view this content'});
            return next('Unauthorized');

        });
    }
}

Response json after login successfully is like this

{
    "token": "JWT eyJhbGci...",
    "user": {
        "_id": "5986b81d940bab06ddc79b34",
        "email": "myemail@gmail.com",
        "role": "admin"
    }
}

Now in Web App, I want to use same role authorization and authentication (login), but you see, Web App is not connected to database, for me to make queries like check if the user in session is valid and has the role as in the response it got after login successfully.

Summary
Here are bullet points of what I was looking for in this question:

  1. Login on Client-Side Web Application, via Remote API on port 3001 (achieved)
  2. Get User Token and other information (response shown above) (achieved)
  3. Ensure user is authenticated on Client-Side Web App and also remember role of the user loggedin, to use these information for authorization of every routes on Client-side app. In client-side app I have few pages with forms to send data to Server-Side API on port 3002, these pages are used by two different user with roles editor and admin.

TIA


Get this bounty!!!

#StackBounty: #javascript #gulp #eslint #gulp-eslint How to switch output from task to task

Bounty: 50

Is it possible to switch Gulp’s output between tasks?

For example, I’d like to run my build task continuously and see its output by default, and I want to be able to replace build‘s output with eslint‘s output, but only if such occurs. So, I can see build‘s output again, if all offences are corrected.

Seemed pretty straightforward before I started to tinker. Am I missing something?


Get this bounty!!!

#StackBounty: #javascript #css #safari #hover #transform Hover effect issue on Safari 10.0

Bounty: 50

There is an issue with the hover effect that only appears on Safari 10.0.

The web is this:
Manu Caballero

What is happening is that the effect is working radomly, or not working at all:
Hover effect doesn't working
To see it working, you can use Chrome or Firefox.

The most strange thing is that, on Safari 10.0, if I try to use the inspector, the hover effect works…
enter image description here

On Safari 10.1 and other common browsers like Chrome, Firefox… is working perfectly.


Get this bounty!!!

#StackBounty: #javascript #client-side #bokeh Overlapping bars with BokehJS bar graph

Bounty: 50

I’d like to make a plot like the one shown below using BokehJS.

Specifically, I have two data series that share x-labels and I want to make a bar graph showing each in a different color (simple enough). But style-wise, I would like one bar to be narrower than the other, while they both share the same centers on the x-axis. For visibility’s sake, the wider bars should be shown “behind” the narrower bars.

Moreover, I’d like to make it using purely BokehJS, rather than using the Python interface. I can’t find any examples with this styling. Any help would be much appreciated!

Oh! One last thing: ideally, I’d like to be able to update this graph on the fly using javascript. So say at the beginning of the exercise, my data is in a javascript variable, but I have alternate data in another javascript variable (with the same structure). I’d like to be able to update the data and have the graph re-render on the client side. Worst case, I know how to write enough JS to totally tear-down the Bokeh plot and redraw it from scratch when I need to update. But I have to imagine there is a way to simply inject the new numerical data and tell the Bokeh plot to update itself. But perhaps I’m too optimistic?

Bar chart with overlapping bars


Get this bounty!!!

#StackBounty: #open-source #javascript #data-visualization #responsive-design Responsive JavaScript table to load 20k records in 2 or 3…

Bounty: 50

I am looking for a responsive javascript table which loads and handles atleast 20k records within 2 or 3 seconds and have many options:

  • Csv
  • Copy to clipboard
  • Export excel, pdf, text, png, word, json
  • Visible columns

It must be open source.

Here is the ones I have found:

Angular uses ng:repeat which slows down the rendering

Swimlane – It’s not active as of now. No updates for a long time

Slick Grid – It’s not active as of now. No updates for a long time


Get this bounty!!!

#StackBounty: #javascript #angularjs #ionic-framework Ionic v1 close all opened modals

Bounty: 50

Here is my problem, I have a function inside $rootScope that is used inside many different ionic modals. That function switches states, and when it switches I want to close the currently opened modal automatically.

The thing is that I cannot write (for example) $scope.someModal.close(); for each of the modals, as they all have different names and are in different scopes.

Is there any kind of a function that I can do something like something.closeAllModals() or something.closeCurrentModal()?


Get this bounty!!!

#StackBounty: #javascript #nativescript #ntlm #des Using ntlm authentication in Nativescript ios platform

Bounty: 50

I am building an app with authenticates the user against a sharepoint site which uses NTLM authentication. I found the ntlm.js which has been patched for nativescript here https://github.com/hdeshev/nativescript-ntlm-demo.

I have managed to get it working for android platform, but it fails on ios showing an 401 error. As far as I can tell, the difference happens in this segment:

Ntlm.setCredentials = function(domain, username, password) {
    var magic = 'KGS!@#$%'; // Create LM password hash.
    var lmPassword = password.toUpperCase().substr(0, 14);
    while (lmPassword.length < 14) lmPassword += '';
    var key1 = Ntlm.createKey(lmPassword);
    var key2 = Ntlm.createKey(lmPassword.substr(7));
    var lmHashedPassword = des(key1, magic, 1, 0) + des(key2, magic, 1, 0);
    var ntPassword = ''; // Create NT password hash.
    for (var i = 0; i < password.length; i++)
        ntPassword += password.charAt(i) + '';
    var ntHashedPassword = str_md4(ntPassword);
    Ntlm.domain = domain;
    Ntlm.username = username;
    Ntlm.lmHashedPassword = lmHashedPassword;
    Ntlm.ntHashedPassword = ntHashedPassword;
};

When I log the result of ‘lmhashedPassword’ after going through the des() function, it simply returns ‘A’. Whereas on android, it returns a longer string. Something in the des function must be cutting it off, but I cannot see what.

Here is the des function:

function des (key, message, encrypt, mode, iv, padding) {
    //declaring this locally speeds things up a bit
    var spfunction1 = new Array (0x1010400,0,0x10000,0x1010404,0x1010004,0x10404,0x4,0x10000,0x400,0x1010400,0x1010404,0x400,0x1000404,0x1010004,0x1000000,0x4,0x404,0x1000400,0x1000400,0x10400,0x10400,0x1010000,0x1010000,0x1000404,0x10004,0x1000004,0x1000004,0x10004,0,0x404,0x10404,0x1000000,0x10000,0x1010404,0x4,0x1010000,0x1010400,0x1000000,0x1000000,0x400,0x1010004,0x10000,0x10400,0x1000004,0x400,0x4,0x1000404,0x10404,0x1010404,0x10004,0x1010000,0x1000404,0x1000004,0x404,0x10404,0x1010400,0x404,0x1000400,0x1000400,0,0x10004,0x10400,0,0x1010004);
    var spfunction2 = new Array (-0x7fef7fe0,-0x7fff8000,0x8000,0x108020,0x100000,0x20,-0x7fefffe0,-0x7fff7fe0,-0x7fffffe0,-0x7fef7fe0,-0x7fef8000,-0x80000000,-0x7fff8000,0x100000,0x20,-0x7fefffe0,0x108000,0x100020,-0x7fff7fe0,0,-0x80000000,0x8000,0x108020,-0x7ff00000,0x100020,-0x7fffffe0,0,0x108000,0x8020,-0x7fef8000,-0x7ff00000,0x8020,0,0x108020,-0x7fefffe0,0x100000,-0x7fff7fe0,-0x7ff00000,-0x7fef8000,0x8000,-0x7ff00000,-0x7fff8000,0x20,-0x7fef7fe0,0x108020,0x20,0x8000,-0x80000000,0x8020,-0x7fef8000,0x100000,-0x7fffffe0,0x100020,-0x7fff7fe0,-0x7fffffe0,0x100020,0x108000,0,-0x7fff8000,0x8020,-0x80000000,-0x7fefffe0,-0x7fef7fe0,0x108000);
    var spfunction3 = new Array (0x208,0x8020200,0,0x8020008,0x8000200,0,0x20208,0x8000200,0x20008,0x8000008,0x8000008,0x20000,0x8020208,0x20008,0x8020000,0x208,0x8000000,0x8,0x8020200,0x200,0x20200,0x8020000,0x8020008,0x20208,0x8000208,0x20200,0x20000,0x8000208,0x8,0x8020208,0x200,0x8000000,0x8020200,0x8000000,0x20008,0x208,0x20000,0x8020200,0x8000200,0,0x200,0x20008,0x8020208,0x8000200,0x8000008,0x200,0,0x8020008,0x8000208,0x20000,0x8000000,0x8020208,0x8,0x20208,0x20200,0x8000008,0x8020000,0x8000208,0x208,0x8020000,0x20208,0x8,0x8020008,0x20200);
    var spfunction4 = new Array (0x802001,0x2081,0x2081,0x80,0x802080,0x800081,0x800001,0x2001,0,0x802000,0x802000,0x802081,0x81,0,0x800080,0x800001,0x1,0x2000,0x800000,0x802001,0x80,0x800000,0x2001,0x2080,0x800081,0x1,0x2080,0x800080,0x2000,0x802080,0x802081,0x81,0x800080,0x800001,0x802000,0x802081,0x81,0,0,0x802000,0x2080,0x800080,0x800081,0x1,0x802001,0x2081,0x2081,0x80,0x802081,0x81,0x1,0x2000,0x800001,0x2001,0x802080,0x800081,0x2001,0x2080,0x800000,0x802001,0x80,0x800000,0x2000,0x802080);
    var spfunction5 = new Array (0x100,0x2080100,0x2080000,0x42000100,0x80000,0x100,0x40000000,0x2080000,0x40080100,0x80000,0x2000100,0x40080100,0x42000100,0x42080000,0x80100,0x40000000,0x2000000,0x40080000,0x40080000,0,0x40000100,0x42080100,0x42080100,0x2000100,0x42080000,0x40000100,0,0x42000000,0x2080100,0x2000000,0x42000000,0x80100,0x80000,0x42000100,0x100,0x2000000,0x40000000,0x2080000,0x42000100,0x40080100,0x2000100,0x40000000,0x42080000,0x2080100,0x40080100,0x100,0x2000000,0x42080000,0x42080100,0x80100,0x42000000,0x42080100,0x2080000,0,0x40080000,0x42000000,0x80100,0x2000100,0x40000100,0x80000,0,0x40080000,0x2080100,0x40000100);
    var spfunction6 = new Array (0x20000010,0x20400000,0x4000,0x20404010,0x20400000,0x10,0x20404010,0x400000,0x20004000,0x404010,0x400000,0x20000010,0x400010,0x20004000,0x20000000,0x4010,0,0x400010,0x20004010,0x4000,0x404000,0x20004010,0x10,0x20400010,0x20400010,0,0x404010,0x20404000,0x4010,0x404000,0x20404000,0x20000000,0x20004000,0x10,0x20400010,0x404000,0x20404010,0x400000,0x4010,0x20000010,0x400000,0x20004000,0x20000000,0x4010,0x20000010,0x20404010,0x404000,0x20400000,0x404010,0x20404000,0,0x20400010,0x10,0x4000,0x20400000,0x404010,0x4000,0x400010,0x20004010,0,0x20404000,0x20000000,0x400010,0x20004010);
    var spfunction7 = new Array (0x200000,0x4200002,0x4000802,0,0x800,0x4000802,0x200802,0x4200800,0x4200802,0x200000,0,0x4000002,0x2,0x4000000,0x4200002,0x802,0x4000800,0x200802,0x200002,0x4000800,0x4000002,0x4200000,0x4200800,0x200002,0x4200000,0x800,0x802,0x4200802,0x200800,0x2,0x4000000,0x200800,0x4000000,0x200800,0x200000,0x4000802,0x4000802,0x4200002,0x4200002,0x2,0x200002,0x4000000,0x4000800,0x200000,0x4200800,0x802,0x200802,0x4200800,0x802,0x4000002,0x4200802,0x4200000,0x200800,0,0x2,0x4200802,0,0x200802,0x4200000,0x800,0x4000002,0x4000800,0x800,0x200002);
    var spfunction8 = new Array (0x10001040,0x1000,0x40000,0x10041040,0x10000000,0x10001040,0x40,0x10000000,0x40040,0x10040000,0x10041040,0x41000,0x10041000,0x41040,0x1000,0x40,0x10040000,0x10000040,0x10001000,0x1040,0x41000,0x40040,0x10040040,0x10041000,0x1040,0,0,0x10040040,0x10000040,0x10001000,0x41040,0x40000,0x41040,0x40000,0x10041000,0x1000,0x40,0x10040040,0x1000,0x41040,0x10001000,0x40,0x10000040,0x10040000,0x10040040,0x10000000,0x40000,0x10001040,0,0x10041040,0x40040,0x10000040,0x10040000,0x10001000,0x10001040,0,0x10041040,0x41000,0x41000,0x1040,0x1040,0x40040,0x10000000,0x10041000);

    //create the 16 or 48 subkeys we will need
    var keys = des_createKeys (key);
    var m=0, i, j, temp, temp2, right1, right2, left, right, looping;
    var cbcleft, cbcleft2, cbcright, cbcright2
    var endloop, loopinc;
    var len = message.length;
    var chunk = 0;
    //set up the loops for single and triple des
    var iterations = keys.length == 32 ? 3 : 9; //single or triple des
    if (iterations == 3) {looping = encrypt ? new Array (0, 32, 2) : new Array (30, -2, -2);}
    else {looping = encrypt ? new Array (0, 32, 2, 62, 30, -2, 64, 96, 2) : new Array (94, 62, -2, 32, 64, 2, 30, -2, -2);}

    //pad the message depending on the padding parameter
    if (padding == 2) message += "        "; //pad the message with spaces
    else if (padding == 1) {temp = 8-(len%8); message += String.fromCharCode (temp,temp,temp,temp,temp,temp,temp,temp); if (temp==8) len+=8;} //PKCS7 padding
    else if (!padding) message += ""; //pad the message out with null bytes

    //store the result here
    result = "";
    tempresult = "";

    if (mode == 1) { //CBC mode
        cbcleft = (iv.charCodeAt(m++) << 24) | (iv.charCodeAt(m++) << 16) | (iv.charCodeAt(m++) << 8) | iv.charCodeAt(m++);
        cbcright = (iv.charCodeAt(m++) << 24) | (iv.charCodeAt(m++) << 16) | (iv.charCodeAt(m++) << 8) | iv.charCodeAt(m++);
        m=0;
    }

    //loop through each 64 bit chunk of the message
    while (m < len) {
        left = (message.charCodeAt(m++) << 24) | (message.charCodeAt(m++) << 16) | (message.charCodeAt(m++) << 8) | message.charCodeAt(m++);
        right = (message.charCodeAt(m++) << 24) | (message.charCodeAt(m++) << 16) | (message.charCodeAt(m++) << 8) | message.charCodeAt(m++);

        //for Cipher Block Chaining mode, xor the message with the previous result
        if (mode == 1) {if (encrypt) {left ^= cbcleft; right ^= cbcright;} else {cbcleft2 = cbcleft; cbcright2 = cbcright; cbcleft = left; cbcright = right;}}

        //first each 64 but chunk of the message must be permuted according to IP
        temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; right ^= temp; left ^= (temp << 4);
        temp = ((left >>> 16) ^ right) & 0x0000ffff; right ^= temp; left ^= (temp << 16);
        temp = ((right >>> 2) ^ left) & 0x33333333; left ^= temp; right ^= (temp << 2);
        temp = ((right >>> 8) ^ left) & 0x00ff00ff; left ^= temp; right ^= (temp << 8);
        temp = ((left >>> 1) ^ right) & 0x55555555; right ^= temp; left ^= (temp << 1);

        left = ((left << 1) | (left >>> 31));
        right = ((right << 1) | (right >>> 31));

        //do this either 1 or 3 times for each chunk of the message
        for (j=0; j<iterations; j+=3) {
            endloop = looping[j+1];
            loopinc = looping[j+2];
            //now go through and perform the encryption or decryption
            for (i=looping[j]; i!=endloop; i+=loopinc) { //for efficiency
                right1 = right ^ keys[i];
                right2 = ((right >>> 4) | (right << 28)) ^ keys[i+1];
                //the result is attained by passing these bytes through the S selection functions
                temp = left;
                left = right;
                right = temp ^ (spfunction2[(right1 >>> 24) & 0x3f] | spfunction4[(right1 >>> 16) & 0x3f]
                    | spfunction6[(right1 >>>  8) & 0x3f] | spfunction8[right1 & 0x3f]
                    | spfunction1[(right2 >>> 24) & 0x3f] | spfunction3[(right2 >>> 16) & 0x3f]
                    | spfunction5[(right2 >>>  8) & 0x3f] | spfunction7[right2 & 0x3f]);
            }
            temp = left; left = right; right = temp; //unreverse left and right
        } //for either 1 or 3 iterations

        //move then each one bit to the right
        left = ((left >>> 1) | (left << 31));
        right = ((right >>> 1) | (right << 31));

        //now perform IP-1, which is IP in the opposite direction
        temp = ((left >>> 1) ^ right) & 0x55555555; right ^= temp; left ^= (temp << 1);
        temp = ((right >>> 8) ^ left) & 0x00ff00ff; left ^= temp; right ^= (temp << 8);
        temp = ((right >>> 2) ^ left) & 0x33333333; left ^= temp; right ^= (temp << 2);
        temp = ((left >>> 16) ^ right) & 0x0000ffff; right ^= temp; left ^= (temp << 16);
        temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; right ^= temp; left ^= (temp << 4);

        //for Cipher Block Chaining mode, xor the message with the previous result
        if (mode == 1) {if (encrypt) {cbcleft = left; cbcright = right;} else {left ^= cbcleft2; right ^= cbcright2;}}
        tempresult += String.fromCharCode ((left>>>24), ((left>>>16) & 0xff), ((left>>>8) & 0xff), (left & 0xff), (right>>>24), ((right>>>16) & 0xff), ((right>>>8) & 0xff), (right & 0xff));

        chunk += 8;
        if (chunk == 512) {result += tempresult; tempresult = ""; chunk = 0;}
    } //for every 8 characters, or 64 bits in the message

    //return the result as an array
    return result + tempresult;
} //end of des

In case it may be relevant, I have changed the way the request is made too. When the user clicks login, the following promise is called:

Ntlm.login('url')
            .then(() => {
                console.log('Success');
                appSettings.setString('token', 'abc123');
                this.router.navigate(['/ilt']);
            })
            .catch(error => {
                console.log('Failed');
                appSettings.remove('token');
                alert('Failed! ' + error );
            })

I created a new login function in the ntlm.js file:

Ntlm.login = function(url) {

    return new Promise((resolve, reject) => {
        if (!Ntlm.domain || !Ntlm.username || !Ntlm.lmHashedPassword || !Ntlm.ntHashedPassword) {

            Ntlm.error('No NTLM credentials specified. Use Ntlm.setCredentials(...) before making calls.');
        }
        var hostname = Ntlm.getLocation(url).hostname;
        var msg1 = Ntlm.createMessage1(hostname);
        var request = new XMLHttpRequest();

        request.onload = function() {
            var response = request.getResponseHeader('WWW-Authenticate');
            var challenge = Ntlm.getChallenge(response);

            var msg3 = Ntlm.createMessage3(challenge, hostname);
            request.open('GET', url, false);
            var authorization = 'NTLM ' + msg3.toBase64();
            request.setRequestHeader('Authorization', authorization);

            request.onload = function() {
                if (request.readyState == 4 && request.status == 200) {
                    resolve(request.status);
                }
                else if (request.readyState == 4 && request.status != 200) {
                    reject(request.status);
                }
            };
            request.send(null);
        };
        request.open('GET', url, false);
        request.setRequestHeader('Authorization', 'NTLM ' + msg1.toBase64());
        request.send(null);   
    })

};

This is all working fine on the Android version, just cant understand why it isnt on ios. Very frustrating! If anyone can make sense of this, I would be eternally grateful. I realise it is a lot of code and quite niche area!

Many thanks,


Get this bounty!!!

#StackBounty: #javascript #reactjs #redux Rewriting Crime Map – React Component with Redux

Bounty: 50

I’ve been working on a crime map demo – and I am keen to learn more about how to rewrite this application to use redux. What is the best approach, why – what is wrong with the way its currently written – too reliant on jQuery?

What would be the advantage of using redux – to keep component data available for other sister components – master parent components?

//index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';

var $ = require("jquery");
import MapChart from './modules/mapChart/MapChart';

var CrimeMap = React.createClass({

    getInitialState: function() {
      return {
        result: ''
      };
    },

    componentDidMount: function () {
        this.serverRequest = $.get(this.props.source, function (result) {          
          this.setState({
            result: result
          });
        }.bind(this));
    },

    componentWillUnmount: function() {
      this.serverRequest.abort();
    },

    getLayers: function(data){
      var items = [];

      items.push(  <MapChart
                      key="1"  
                      data= {data} /> );

      return items;      
    },

    render: function () {
       var result = this.state.result;
       return (
            
{this.getLayers(result)}
); } }); //https://data.police.uk/docs/method/crime-street/ ReactDOM.render( <CrimeMap source="https://data.police.uk/api/crimes-street/all-crime?poly=52.268,0.543:52.794,0.238:52.130,0.478&date=2013-01" />, document.getElementById('root') );

//MapChart.js

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
var $ = require("jquery");
import './MapChart.css';

import {Map, InfoWindow, Marker, GoogleApiWrapper} from 'google-maps-react';

export class MapContainer extends Component {

    render() {
        function getIcon(category){
            //anti-social-behaviour
            //burglary
            //criminal-damage-arson
            //drugs
            //other-theft
            //shoplifting
            //vehicle-crime
            //other-crime

            switch(category) {
                case "anti-social-behaviour":
                    return 'http://maps.google.com/mapfiles/ms/icons/green-dot.png'
                    break;
                case "burglary":
                    return 'http://maps.google.com/mapfiles/ms/icons/red-dot.png'
                    break;
                case "criminal-damage-arson":
                    return 'http://maps.google.com/mapfiles/ms/icons/yellow-dot.png'
                    break;
                case "drugs":
                    return 'http://maps.google.com/mapfiles/ms/icons/purple-dot.png'
                    break;
                case "other-theft":
                    return 'http://maps.google.com/mapfiles/ms/icons/pink-dot.png'
                    break;
                case "shoplifting":
                    return 'http://maps.google.com/mapfiles/ms/icons/blue-dot.png'
                    break;
                case "other-crime":
                    return 'http://maps.google.com/mapfiles/ms/icons/orange-dot.png'
                    break;
                default:
                    return 'http://maps.google.com/mapfiles/ms/icons/ltblue-dot.png'
            }
        }

        const data = [];

        $.each(this.props.data, function( index, value ) {
            var obj = {
                "label": value.category,
                "lat": value.location.latitude,
                "lng": value.location.longitude,
                "icon": getIcon(value.category)
            }
            data.push(obj);
        });

        return (
          <Map 
            google={this.props.google} 
            initialCenter={{
              lat: 52.225827,
              lng: 0.484861
            }}
            zoom={11}
          >

            {
              data.map(function (item, index) {
                return (
                  <Marker
                    key={index}
                    icon={item.icon}
                    title={item.label}
                    name={item.label}
                    position={{lat: item.lat, lng: item.lng}} />
                )
              })
            }

          </Map>
        );
    }
}

export default GoogleApiWrapper({
  apiKey: 'xx'
})(MapContainer)

//MapChart.css

 /* Always set the map height explicitly to define the size of the div
   * element that contains the map. */
  #map {
    height: 100%;
  }
  /* Optional: Makes the sample page fill the window. */
  html, body {
    height: 100%;
    margin: 0;
    padding: 0;
  }


Get this bounty!!!

#StackBounty: #javascript #java #javafx #javafx-2 #javafx-webengine How to create a JavaFX WebBrowser javascript listener without a Mem…

Bounty: 50

I have been using this snippet for creating js listener in my javafx browser:

       engine.getLoadWorker().stateProperty().addListener(
                (observable, oldValue, newValue) -> {
                    if (newValue == Worker.State.SUCCEEDED) {
                        System.out.println("changed event detected");
                        JSObject win = (JSObject) engine.executeScript("window");
                        win.setMember("java", new JavascriptListener());
                    }
                }
        );

But I would like to be able to call my functions without prefixing them with “java”.

Is that possible?


Get this bounty!!!

#StackBounty: #javascript #vue.js #uikit #vuejs2 #vue-component Vue – any way to reuse SLOT?

Bounty: 50

Im working on responsive Vue.js app with Uikit. I must create 2 menus – one for desktop version, one for mobile. So I must define same menu items 2 times, first for desktop links slot, second time for mobile. I dont want define it 2x. How can I deal with this problem elegantly? Any ideas?

<template id="app">
  <app-layout>

    <template slot="navlinks-desktop">
      <router-link to="/link1" tag="li" exact><a>Link 1</a></router-link>
      <router-link to="/link2" tag="li" exact><a>Link 2</a></router-link>
    </template>

    <template slot="navlinks-mobile">
      <router-link to="/link1" tag="li" exact><a>Link 1</a></router-link>
      <router-link to="/link2" tag="li" exact><a>Link 2</a></router-link>
    </template>

    <transition name="fade" slot="content">
      <router-view></router-view>
    </transition>

    <p slot="footer">Footer text</p>

  </app-layout>
</template>

<template id="app-layout">
  

EDIT: So… After some research and closer look to documentation, I must say, that this specific problem DOES NOT HAVE SOLUTION… Although it is possible to reuse slots, just render it programatically, IT IS NOT POSSIBLE TO REUSE SLOT WITH ROUTER LINK.

Example – no hacks – true “Vue way” to reuse slots:

<template id="app">
  <app-layout>

    <template slot="myslot">
      <li>THIS WORKS</li>
      <li>WILL</li>
      <li>WORK</li>
    </template>

  </app-layout>
</template>


  Vue.component('app-layout', {
    render: function (createElement) {
      var myslot = this.$slots.myslot

      return createElement('div', [
        createElement('ul', myslot),
        createElement('ul', myslot)
      ])
    }
  })

Its simple, elegant and readable. But, unfortunately, if you render component programatically, you cant use templates. So something like this…

<template id="app-layout">
  

…you can throw away and you must create whole structure, one by one programatically with createElement function, which is really painfull and error prone. Yes, you can use JSX, but then you must transpile it with Babel. And this is not what I want… Non working example:

<template id="app">
  <app-layout>

    <template slot="navlinks">
      <router-link to: "/">Home</router-link>
      <router-link to: "/products">Products</router-link>
      <router-link to: "/about">About</router-link>
    </template>

  </app-layout>
</template>


  Vue.component('app-layout', {
    render: function (createElement) {
      var navlinks = this.$slots.navlinks

      return createElement('div', [
        createElement('ul', navlinks),
        createElement('ul', navlinks)
      ])
    }
  })

In this example, second UL will be empty. And unfortunately, from the fact perspective that in Vue all vNodes must be unique, it is perfectly normal, that it will remain empty…

So the result is that I can not use structure as above. I cant have template app-layout for which I have template with wrapping elements. Finally, I rewrote it this way:

<template id="app">
  

No two separate templates, no slots. But no programmatical template rendering also. So I kept my example application clean and easy to understand. And that was the point…

PS: STILL, I WILL BE VERY HAPPY, IF I AM WRONG AND SOMEONE SHOW ME HOW TO REUSE SLOT WITH ROUTER LINK.


Get this bounty!!!