Monday 31 May 2021

Session variable value is not updated when websocket connection happens - Python

I am creating an API to send message to echo server

For this, I am using echo chat server URL ws://echo.websocket.org/ from this site https://www.websocket.org/echo.html. This connection will echo our input.

First time when the user request the API, I need to establish connection with echo server and send the user message to echo server. When second time user request the same API, this time connection is already established. So, I just need to send user message to echo server.

For this, I am using python session to store the connection details. First time when the connection in made I am trying to save it in session. session['ConnetionMade'] = "True" by default it is false

So, second time when the user request the API, this time ConnetionMade is True. So, I don't to make connection again.

But here session variable is not updated when the connection is made. It is always false. But we set to True.

Below is the full working code. Kindly help me to update session variable.

Note : Session variable works when we skips socket connection code

from flask import Flask
from flask import request, session
from config import config
import websocket

try:
    import thread
except ImportError:
    import _thread as thread


SECRET_KEY = 'a secret key'

app = Flask(__name__)
app.config.from_object(__name__)

@app.route('/')
def root():
    return 'Hello NLP....!'

userMessage = ""
@app.route('/whatsapp', methods=['POST'])
def echo():
    global userMessage
    userMessage = request.json['message']

    # session.clear()

    print("\n\nuserMessage: ", userMessage, "\n\n")

    print("ConnetionMade--: ", session.get('ConnetionMade', "False"))

    if session.get('ConnetionMade', "False") == "False":
        session['ConnetionMade'] = "True"
        print('True set to ConnetionMade ', session.get('ConnetionMade', "False"))
        echoConnection()
    else:
        session['ConnetionMade'] = "False"
        print('False set to ConnetionMade ', session.get('ConnetionMade', "False"))


    return ""


def echoConnection():

    if __name__ == "__main__":
        websocket.enableTrace(True)
        ws = websocket.WebSocketApp("ws://echo.websocket.org/",
                                  on_open = on_open,
                                  on_message = on_message,
                                  on_error = on_error,
                                  on_close = on_close)

        ws.run_forever()

    return ""

def on_message(ws, message):
    print("\n\nMessage received from Echo Socket server:", message, '\n\n')
    return

def on_error(ws, error):
    print("on_error ", error)
    return

def on_close(ws):
    print("on_close")
    return

def on_open(ws):
    def run(*args):

        print("\n\nSocket connection made. Now sending this message ("+userMessage+") to Echo Socket server\n\n")
        ws.send(userMessage)
        print("\nsent...\n")
        print("thread terminating...")

    thread.start_new_thread(run, ())

    return

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=config['server']['port'])


from Session variable value is not updated when websocket connection happens - Python

How to automate parameters passed into pandas.read_sql?

I am trying to create a methodology for passing parameters automatically through something like locals(), similarly to how f-strings work.

How it currently works

import pandas as pd

def my_func(conn, string_id, date, integer_ids):
    sql = f"""    
    select * from RISK a
    where STRING_ID = '{string_id}'
    and DATE = {date}
    and INTEGER_ID in ({','.join(map(str, integer_ids))})"""
    df = pd.read_sql(sql, conn)
    return df

However, this approach means I cannot copy-paste the SQL into SQL developer or similar, and run it from there. So I would like an approach that makes use of parameters instead.

There seems to be two problems with that

  1. Parameters must be literals, so its not possible to pass along lists
  2. I need to create a dictionary manually, and cannot simply pass something like locals()

How I would like it to work would be something like the example below (which obviously doesn't work)

import pandas as pd

def my_func(conn, string_id, date, integer_ids):
    sql = """    
    select * from RISK
    where STRING_ID = :string_id
    and DATE = :date
    and INTEGER_ID in :integer_ids"""
    df = pd.read_sql(sql, conn, params=locals())
    return df

EDIT: After testing a bit, maybe I could use a regex to find all instances of :param and replace them with the parameter value, e.g.

import re
pattern = '[\n\r].*:\s*([^\n\r]*)'
matches = re.findall(pattern,sql)
for match in matches:
    sql = sql.replace(':'+match, eval(match))

It's just not very pretty, and it introduces issues related to object types. E.g. the string_id should be encapsulated by ', and the date needs to be converted to a string object as well



from How to automate parameters passed into pandas.read_sql?

django admin site nav sidebar messed up

I recently added a package to my project and did a pip freeze > requirements.txt afterwards. I then did pip install -r requirements.txt to my local and it added a sidebar.

enter image description here

I did a pip install -r requirements.txt to the server as well and it produced a different result. It's sidebar was messed up.

enter image description here

I tried removing the sidebar by doing this answer but it did not get removed.

.toggle-nav-sidebar {
    z-index: 20;
    left: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 23px;
    width: 23px;
    border: 0;
    border-right: 1px solid var(--hairline-color);
    background-color: var(--body-bg);
    cursor: pointer;
    font-size: 20px;
    color: var(--link-fg);
    padding: 0;
    display: none; /*added*/
}

#nav-sidebar {
    z-index: 15;
    flex: 0 0 275px;
    left: -276px;
    margin-left: -276px;
    border-top: 1px solid transparent;
    border-right: 1px solid var(--hairline-color);
    background-color: var(--body-bg);
    overflow: auto;
    display: none; /*added*/
}

What should I do to fix this?

If there are any other things I can add to help, do ask.

ADD requirements.txt:

asgiref==3.3.4
certifi==2020.12.5
chardet==4.0.0
defusedxml==0.7.1
diff-match-patch==20200713
Django==3.2.3
django-cors-headers==3.7.0
django-filter==2.4.0
django-import-export==2.5.0
django-property-filter==1.1.0
djangorestframework==3.12.4
et-xmlfile==1.0.1
idna==2.10
MarkupPy==1.14
odfpy==1.4.1
openpyxl==3.0.7
python-decouple==3.4
pytz==2019.2
PyYAML==5.4.1
requests==2.25.1
sqlparse==0.3.0
tablib==3.0.0
urllib3==1.26.4
xlrd==2.0.1
xlwt==1.3.0

ADD sample github repo:



from django admin site nav sidebar messed up

Refresh token using FastAPI and Swagger

I am trying to create an API for our organization using FastAPI. It has a KeyCloak server that is used for all authentication, and OpenID Connect and JWTs is the way that is considered best practise.

In the simplest case, someone else takes care of acquiring a valid JWT token so that FastAPI then can simply decode and read the user and permissions.

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

async def get_current_user(token: str = Depends(oauth2_scheme)):

    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )

    try:
        jwt_token = jwt.decode(token, key=env.keycloak_server_public_key, audience='myorg')
        return jwt_token['preferred_username']
    except jwt.exceptions.ExpiredSignatureError:
        raise credentials_exception

Life is simple!

I do, however, want to try to let users explore the API using the Swagger page. I have created this function that lets users login using the UI:

@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
    login_request = requests.post(
        "https://mygreatorg.com/auth/realms/master/protocol/openid-connect/token",
        data={
            "grant_type": "password",
            "username": form_data.username,
            "password": form_data.password,
            "client_id": "fastapi-application",
        },
    )
    raw_response = json.loads(login_request.content.decode('utf-8'))
    raw_response['acquire_time'] = time.time()

    TOKEN_CACHE[form_data.username] = raw_response

    return {"access_token": raw_response['access_token'], "token_type": "bearer"}

This works fine. The auth header in Swagger is now the token, and it validates, for about a minute. The expire time for the tokens are set to a very short time. One is then expected to refresh them using the refresh_token provided in the raw_response payload.

I can very easily make another request to get a new valid access token given the refresh_token. But I am unable to get Swagger to change the token of the request in the UI. The only way I find is to logout and login again, but users will be very annoyed if they are only allows a minute without being kicked out.

One workaround would be to simply cache the token and ignore the expire time and let the user be logged in for a while longer, but that defeats the purpose of the entire security setup and feels like a bad idea.

Any ideas on how to let the UI of FastAPI update the bearer token when its need a refresh, without letting the user login again?



from Refresh token using FastAPI and Swagger

phantomjs: document.querySelectorAll() not working for dynamic page

I am just trying to get deals items from this amazon URL :

when I open this link in browser and write the query in console, it works: document.querySelectorAll('div[class*="DealItem-module__dealItem_"]')

document.querySelectorAll() result

but when I try to fetch this through this phantomjs script, it seems to always returning nothing:

var page = require('webpage').create();

page.viewportSize = { height: 800, width: 1920 }; // BRODIE : CHROME

page.customHeaders = {
  accept:
    'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
  // 'accept-encoding': 'gzip, deflate, br',
  'accept-language': 'en-US,en;q=0.9',
  dnt: '1',
  'sec-ch-ua':
    '" Not A;Brand";v="99", "Chromium";v="90", "Microsoft Edge";v="90"',
  'sec-ch-ua-mobile': '?0',
  'sec-fetch-dest': 'document',
  'sec-fetch-mode': 'navigate',
  'sec-fetch-site': 'none',
  'sec-fetch-user': '?1',
  'upgrade-insecure-requests': '1',
  'user-agent':
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36 Edg/90.0.818.66',
};

page.settings.javascriptEnabled = true;
page.settings.loadImages = false;
//Script is much faster with this field set to false
phantom.cookiesEnabled = true;
phantom.javascriptEnabled = true;

page.onConsoleMessage = function (message) {
  console.log('console.log() -- ', message);
}; // BUBBLE UP LOGS FROM BROWSER CONSOLE TO PHANTOM CONSOLE

page.onLoadStarted = function () {
  loadInProgress = true;
  console.log('page loading started');
};
page.onLoadFinished = function () {
  loadInProgress = false;
  console.log('page loading finished');
};

page.onError = function (msg, trace) {
  console.log(msg);
  trace.forEach(function (item) {
    console.log('  ', item.file, ':', item.line);
  });
};

// OPEN PAGE
console.log('page.open()');
page.open(
  'https://www.amazon.com/gp/goldbox/ref=gbps_ftr_s-5_cd34_wht_26179410?gb_f_deals1=sortOrder:BY_SCORE,includedAccessTypes:GIVEAWAY_DEAL,enforcedCategories:2617941011&pf_rd_p=fd51d8cf-b5df-4144-8086-80096db8cd34&pf_rd_s=slot-5&pf_rd_t=701&pf_rd_i=gb_main&pf_rd_m=ATVPDKIKX0DER&pf_rd_r=A89BX6V6RQRQ94NFA0DP&ie=UTF8',
  function (status) {
    if (status !== 'success')
      console.log('U N A B L E   T O   O P E N   P A G E . . .');
    else console.log(' P A G E   O P E N E D . . .');

    var selector = 'div[class*="DealItem-module__dealItem_"]'

    var findAll = setInterval(function () {
      console.log('trying to fetch deals...');
      var deals = page.evaluate(function (sel) {
        return document.querySelectorAll(
          'div[class*="DealItem-module__dealItem_"]'
        );
      }, selector);

      if(deals.length) {
        console.log('deals.length', deals.length);
        clearInterval(findAll);
      }
    }, 1000);
  }
);

Also, when I try to take screenshot using page.render(), it shows page with unloaded/unfinished JS (which is different from when we type that URL in browser and search:):

Unfinished/Unloaded JS page

Also, I noticed that when I run this script in terminal, I get some JS errors of webpage:

phantom JS webpage errors

Any help will be greatly appriciated



from phantomjs: document.querySelectorAll() not working for dynamic page

GL version 2.1 with the gpu_shared4 extensions is not supported on Ubuntu 18.04.5 LTS as guest VM

I am trying to run a python (3.6.9) script with VTK 7.1.1 on Ubuntu 18.04.5 LTS as guest VM using virtual box. But I am receiving the following error:

In /build/vtk7‑w4DzBd/vtk7𔂱.1.1+dfsg1/Rendering/OpenGL2/vtkOpenGLRenderWindow.cxx, line 640
vtkXOpenGLRenderWindow (0x2a56080): GL version 2.1 with the gpu_shader4 extension is not supported 
by your graphics driver but is required for the new OpenGL rendering backend. Please update your 
OpenGL driver. If you are using Mesa please make sure you have version 10.6.5 or later and make sure 
your driver in Mesa supports OpenGL 3.2.

When I run the command

glxinfo | grep "OpenGL version"

it returns:

OpenGL version string: 2.1 Mesa 20.0.0-devel - padoka PPA

If I understand corretly the visualization on Ubuntu is done by Mesa 20.0.0-devel (required is 10.6.5 - this is OK) but the installed Mesa uses OpenGL 2.1 and not newer (required 3.2 - this is not OK). I have already installed the latest version of Mesa. Any suggestion how to solve this?



from GL version 2.1 with the gpu_shared4 extensions is not supported on Ubuntu 18.04.5 LTS as guest VM

Shoutcast broadcasting in android

I've checked the many blogs and forums and github but nothing found related/help for implementing shoutcast v1 or v2 in android, only ref which is helpful I've found in github is this:

https://github.com/fatihsokmen/android-icecast-broadcast

but above code only work with icecast server and also very limited use and files which is used for broadcasting is *.so files so we can not change or override the exiting methods.

is there any guide or helpful link or source code which I can use to build shoutcast broadcasting in android, please share with me.



from Shoutcast broadcasting in android

Create activities for an user with Stream-Framework

I'm trying to setup stream-framework the one here not the newer getstream. I've setup the Redis server and the environment properly, the issue I'm facing is in creating the activities for a user.

I've been trying to create activities, following the documentation to add an activity but it gives me an error message as follows:

...
  File "/Users/.../stream_framework/activity.py", line 110, in serialization_id
    if self.object_id >= 10 ** 10 or self.verb.id >= 10 ** 3:
AttributeError: 'int' object has no attribute 'id'

Here is the code

from stream_framework.activity import Activity
from stream_framework.feeds.redis import RedisFeed


class PinFeed(RedisFeed):
    key_format = 'feed:normal:%(user_id)s'

class UserPinFeed(PinFeed):
    key_format = 'feed:user:%(user_id)s'

feed = UserPinFeed(13)
print(feed)

activity = Activity(
    actor=13, # Thierry's user id
    verb=1, # The id associated with the Pin verb
    object=1, # The id of the newly created Pin object
)

feed.add(activity) # Error at this line

I think there is something missing in the documentation or maybe I'm doing something wrong. I'll be very grateful if anyone helps me get the stream framework working properly.



from Create activities for an user with Stream-Framework

Why is this MPEG-4 compression of GIF creating weird results?

I was wondering what would happen if MPEG-4 tried to compress an image with completely random pixels. So I made an image with random pixels using Pillow in Python.

The actual GIF:

GIF frame sample

This isn't animated as the animated one was too big. The colour of each pixel is completely random. As MPEG-4 should only blend in colours which are similar. So, there should be a few blended colours due to colours being similar by chance. That's not what happened.

One of the MP4 frames: MP4 Frame

There is a CLEAR pattern in the compressing. It appears like a matrix of sharp, uncompressed patches and compressed blended patches. What's going on? The effect is way more clear in the .mp4 file which, click here for that. And it's even more clear in the original file stored in my device. This is not something that should happen with pseudo random numbers that Python generates through the random module.

All of the pixels in all of the frames were created through this:

[random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)]


from Why is this MPEG-4 compression of GIF creating weird results?

Android 12 New Bluetooth Permissions

Bluetooth is the main dependency of our app. So, We already try to implement new Android 12 Bluetooth permissions. Our only resource is Android developers New Bluetooth permissions in Android 12. There is just saying add permissions

"android.permission.BLUETOOTH_CONNECT"

"android.permission.BLUETOOTH_SCAN"

I add and I got runtime permissions for both and of course location(usual as pre 12)).
There is no other change in my codebase. Should be? I don't know. So, the problem is my app can't find the BLE device. I couldn't find the reason.

Do you have any suggestions or resources?



from Android 12 New Bluetooth Permissions

RangeError ChildProcess: stderr maxBuffer length exceeded

I am attempting to execute a batch file using the .exec() method.

const { exec } = require("child_process");

exec('"./Something/Requests/run.bat"', { maxBuffer: 1024 * 500 }, function (error) {
                if (error) {
                    console.log(error);
                }
            })

Error Output:

RangeError [ERR_CHILD_PROCESS_STDIO_MAXBUFFER]: stderr maxBuffer length exceeded
    at Socket.onChildStderr (child_process.js:386:14)
    at Socket.emit (events.js:315:20)
    at addChunk (_stream_readable.js:295:12)
    at readableAddChunk (_stream_readable.js:267:11)
    at Socket.Readable.push (_stream_readable.js:212:10)
    at Pipe.onStreamRead (internal/stream_base_commons.js:186:23) {
  code: 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER',
  cmd: '"./Something/Requests/run.bat"'
}

Is there any other way to execute a batch file? I tried file types like .json and it opened the file with notepad just fine.



from RangeError ChildProcess: stderr maxBuffer length exceeded

Allure-Kotlin does not create allure-results in Espresso tests

I tried step by step the instructions from Allure-Kotlin for android tests. But after finishing my tests when I run(on Pixel_4_API_29):

adb pull /sdcard/allure-results This message is shown:

adb: error: failed to stat remote object '/sdcard/allure-results': No such file or directory

This is a sample repo I created to show what I did exactly.

More info: I run tests using ./gradlew app:connectedAndroidTest, tests are run with @RunWith(AllureAndroidJUnit4.class), I already added allure.prperties file to androidTest resources as well as listeners to META-INF.services. Also, I updated Kotlin version to 1.4.21 and Gradle to 6.7.1 to be matched with allure-kotlin 2.2.5. I also already made sure of required permission to access to /sdcard folder on emulator.

I really appreciate any helpful answer and comments.



from Allure-Kotlin does not create allure-results in Espresso tests

What should be the content type to set for a multipart email after parsing and making some changes to it?

I have a multipart email with all types of attachments ie. multiple email, plain text, pdf attachments, inline images and html too. After walking through the different parts of the multipart body and adding some text to the body of the main email, I wish to regenerate the whole email as an original. What should be the correct method to do that. Using python 3.6. Code snippet what I have tried is as follows:

mail_attached_bool = False
new_message1 = email.message.EmailMessage()
attached_bool = False

mhtml = 'Modified html variable'
mbody = 'Modified text variable'

# while parsing the multipart of the raw message: msg
if msg.is_multipart():
    for part in msg.walk():
        if part.get_content_type() == 'multipart/report':
            new_message.attach(mbody)
            if mhtml:            
                new_message.attach(mhtml)

            for rel1 in part.walk():
                if rel1.get_content_type() == 'message/delivery-status':
                    new_message.attach(rel1)
                if rel1.get_content_type() == 'text/rfc822-headers':
                    new_message.attach(rel1)

        if part.get_content_type() in ["multipart/related",
                                       "multipart/mixed"]:
            new_message1.set_type("multipart/related")
            if mhtml:
                new_message1.attach(mhtml)
                print(999999)
            elif mbody:
                if mbody == '':
                    mbody = MIMEText(warning_txt,'plain')
                new_message1.attach(mbody)

        for rel in part.walk():
            mail_attached_bool = False
            attached_bool = False
            print(rel.get_content_type(), '------------cccccccc')
            # other kinds of attachments
            cdispo = str(rel.get('Content-Disposition'))
            attach = re.compile('application/*')
            attachment = attach.search(rel.get_content_type())

            if rel.get_content_type() in ['message/rfc822',]:
                new_message1.set_type('multipart/related')
                print(rel.get_content_type(), '----------content type')
                mail_attached_bool = True
                attached_bool = True
                x += 1
            
            if rel.is_multipart() and rel.get_content_type() \
               not in \
               ["multipart/alternative",
                "message/rfc822"
               ]:
                new_message1.set_type(rel.get_content_type())

            # ignore the first html as its the mail body
            if rel.get_content_type() == "text/html" and cdispo=='None':
                i += 1
                if i == 1 and html_body:
                    continue
                print('i: ',i)
            # ignore the first plain text as its the mail body
            if rel.get_content_type() == "text/plain" and cdispo=='None':
                j += 1
                if j == 1 and text_body:
                    continue
                print('j: ',j)

            #--------------#                    
            if 1:#rel.get_content_type() != 'message/rfc822':#mail_attached_bool is False:
                # has mail content apart from body (ios)
                if rel.get_content_type() == "text/html":
                    new_message1.attach(rel)
                    print(rel.get_filename(),'-----   html  attached')

                if rel.get_content_type() == "text/plain" and \
                   rel.get('Content-Disposition') in [None, "inline"]:
                    new_message1.attach(rel)
                    print('---------------text attachment', 666666)

                if rel.get_content_type() in ['image/png',
                                              'image/jpeg',
                                              'image/jpg'] \
                                              or ('attachment' in cdispo) \
                                    or ('inline' in cdispo) or (attachment):

                    # inline images and text
                    if "inline" in cdispo and \
                       not rel.get_content_type() in [
                           "text/plain",
                       ] \
                           and not attached_bool:
                        attached_bool = True
                        new_message1.attach(rel)
                        
                    if attachment or "attachment" in cdispo and \
                       (not attached_bool) or cdispo == 'None':
                        new_message1.attach(rel)
                        attached_bool = True

                    elif cdispo == 'None' and (not attached_bool):
                        new_message1.attach(rel)
                        print('attaching here')

                if rel.get_content_type() in ['text/calendar']:
                    new_message1.attach(rel)

            if mail_attached_bool:
                new_message1.attach(rel)

        new_message.set_type('multipart/alternative')
        new_message.attach(new_message1)
        if new_message1:
            print('new_message1 exists')
            break

Then send the mail. When the mail is sent it is attaching the main mail body and its attachment 2 times in the new message object. Why does this happen? What is the correct content type to set for the new mail?



from What should be the content type to set for a multipart email after parsing and making some changes to it?

Line chart is not being displayed in Chart.js

The problem is quite forward, I can't see the line of the graph, and when I press any button. The time of the X axes should change accordignally to which button is pressed I have been looking through the documentation, for quite some time, but still can't figure it out.

ChartData

import React, { useRef, useEffect, useState } from "react";
import { historyOptions } from '../chartConfig/chartConfig';
import 'chartjs-adapter-moment';
import annotationPlugin from 'chartjs-plugin-annotation';
import { Chart, registerables } from 'chart.js';
Chart.register(...registerables);
Chart.register(annotationPlugin);



const determineTimeFormat = (
  timeFormat: string,
  day: any,
  week: any,
  year: any
) => {
  switch (timeFormat) {
    case "24h":
      return day;
    case "7d":
      return week;
    case "1y":
      return year;
    default:
      return day;
  }
};

interface Props {
  data: any
}

const ChartData: React.FC<Props> = ({ data }) => {
  const chartCanvasRef = useRef<HTMLCanvasElement | null>(null);
  const { day, week, year, detail } = data;
  const [timeFormat, setTimeFormat] = useState("24h");
  const [isRebuildingCanvas, setIsRebuildingCanvas] = useState(false);
  
 

  useEffect(() => {
    setIsRebuildingCanvas(true);
  }, [timeFormat]);

  useEffect(() => {
    if (isRebuildingCanvas) {
      setIsRebuildingCanvas(false);
    }
  }, [isRebuildingCanvas]);

  useEffect(() => {
      if (chartCanvasRef && chartCanvasRef.current && detail) {
    const chartCanvas = chartCanvasRef.current
    if (isRebuildingCanvas || !chartCanvas) {
      return;
    }
  
    const chartInstance = new Chart(chartCanvasRef.current, {
      type: "line",
      data: {
        datasets: [
          {
            label: `${detail.name} price`,
            data: determineTimeFormat(timeFormat, day, week, year),
            backgroundColor: "rgba(134,159,152, 1)",
            borderColor: "rgba(174, 305, 194, 0.4",

          },
        ],
      },

Options

  options: {     
        plugins: {
          annotation: {
            annotations: {
           
            }
          }
        },
      
        animations: {
          tension: {
            duration: 1000,
            easing: 'linear',
            from: 1,
            to: 0,
            loop: true
          }
        },
        maintainAspectRatio: false,
        responsive: true,
        scales: {
          x: 
            {         
              type: 'time',
            },  
        },
      }
    });
    return () => {
      chartInstance.destroy();
    }
  }}, [day, isRebuildingCanvas,timeFormat, week, year, detail]);

Rest of the Component code


return (
    <div className='chart__container'>
    {renderPrice()}
      {isRebuildingCanvas ? undefined : (
        <canvas ref={chartCanvasRef} id='myChart' width={250} height={250}></canvas>
      )}
      <button className='time__format' onClick={() => setTimeFormat("24h")}>24h</button>
      <button className='time__format' onClick={() => setTimeFormat("7d")}>7d</button>
      <button className='time__format'  onClick={() => setTimeFormat("1y")}>1y</button>
    </div>
  );
};

export default ChartData;


from Line chart is not being displayed in Chart.js

How to create icons for windows, MacOS and Linux application

I hope I am asking this in the correct section, otherwise, kindly move my post.

I am building an application which is available for Windows, Linux (as AppImage) and MacOS. I need shortcut icons for those. I have a logo, but I am struggling to bring it to the right format. It seems to me that all three platforms use different icon sizes and formats.

Is there any online/offline generator that allows me to create icons for all three platforms from a jpg file?



from How to create icons for windows, MacOS and Linux application

SSR with data fetch without state management library

I am trying to make a SSR react app, but not able to pass props from express to the component. What mistake am i doing?

server.js

import AppPage2 from './src/project02/LandingPage';
......
......
server.get('/project2',async (req,res)=>{
    const context = {data:'test'}
    const sheet = new ServerStyleSheet();
    const content = ReactDOMServer.renderToString(sheet.collectStyles(
        <StaticRouter location={req.url} context={context}>
            <AppPage2 state=/>
        </StaticRouter>)
    );
    const styles = sheet.getStyleTags();
    let html = appShell( 'Project 2', content,' project2.bundle.js',styles)
    res.status(200).send(html);
    res.end()
})

AppPage2(./src/project02/LandingPage)

import React from 'react';
import {Wrapper,Title}  from './styleComponent/testStylePage'
.......
.......
class AppPage extends React.Component {

    componentDidMount() {
       console.log("",this,this.props, this.props.staticContext)
    }

    render(){
        return(
            <Wrapper>
                <Title>This is project 01 </Title>
            </Wrapper>
        )
    }
}

export default AppPage;

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import AppPage from './project02/LandingPage'

ReactDOM.hydrate(
        <AppPage></AppPage>,
    document.querySelector('#root')
);

webpack.client.conf

const path = require('path');
const glob = require("glob");
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;


const entry = glob.sync("src/*.js")
    .reduce((x, y) => Object.assign(x, 
        {
            [y.replace('src/','').replace('.js','')]: `./${y}`,
        }
), {});


    
    module.exports = {
            target: 'node',
            mode: 'development',//development,production
            entry: entry,
            output: {
                filename:'[name].bundle.js',
                path: path.resolve(__dirname,'build/public/'),
                publicPath: '/build/'
            },
            module: {
                rules: [
                    {
                        test: /\.js$/,
                        exclude: /(node_modules)/,
                        use: {
                            loader: 'babel-loader'
                        },
                        
                    },
                ]
            },
            plugins: [
                // new BundleAnalyzerPlugin()
            ]
        }

I am not able to log console.log("",this,this.props, this.props.staticContext) from AppPage2(./src/project02/LandingPage) this page i am sending data from server.js(express)



from SSR with data fetch without state management library

web kit mask image trows a cors error angular

I see some answers on stackoverflow but it is difficult to understand and I have also tried to sanitize it but the issue is same. https://stackoverflow.com/a/61984516/4646531

Access to image at 'https://ift.tt/34n6j8l' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

<div [ngStyle]="{'-webkit-mask-image': 'url(https://mdn.mozillademos.org/files/12676/star.svg)'}">
  yo! This text is contained within a <code>P</code> tag.
</div>

Code on stackblitz



from web kit mask image trows a cors error angular

How to load an existing custom lib which is having non AMD and AMD library using requireJS

In my project there is custom third party library (a single build file) , which they have created using couple of non AMD and AMD files. And most of the properties are exposed directly to window object. In our project as per new requirement we have to load this third party library in asynchronous mode using requireJS. I tried with shim configuration but am getting error from third party library saying that globals/window, globals/documents are needed.

  1. How to resolve the above error in current project without editing third party library ? is it possible ?
  2. How to consume this third party libs properties in the project, since all properties are exposed directly to window Object.

This is the error we are encountering now

enter image description here

Could anyone please help me on this ?



from How to load an existing custom lib which is having non AMD and AMD library using requireJS

Django Custom Queryset managers: Implicit chained filter()?

In Django, when it comes to M2M relationships, we know that these two queries:

# 1
MyModel.objects.filter(othermodel__attr1="someval1", othermodel__attr2="someval2")
# 2
MyModel.objects.filter(othermodel__attr1="someval1").filter(othermodel__attr2="someval2")

Will not necessarily return the same results (docs).

I've recently started utilizing custom QuerySet managers and it suddenly dawned on me that I may get this undesired behavior (for me at least) if I'm doing something like this:

# defined as customobjects = MyModelQuerySet.as_manager() in `MyModel`

class MyModelQuerySet(models.QuerySet): 
      def method1(self):
          return self.filter(othermodel__attr1="someval1")
      
      def method2(self):
          return self.filter(othermodel__attr2="someval2")

and using MyModelQuerySet like this:

results = MyModel.customobjects.method1().method2()

Then I may be getting the behavior of chained filters. For me this makes using a custom QuerySet manager completely useless as I need an AND behavior most of the time. But I'm not sure this is indeed the behaviour. If it is, are there are any workarounds while using managers? (I want the ability to flexibly use different filters and mix and match them with managers, but I don't want the chained filters behavior)



from Django Custom Queryset managers: Implicit chained filter()?

Sunday 30 May 2021

Javascript Confirm not working in Godaddy

From here, https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_confirm

<!DOCTYPE html>
<html>
<body>

<p>Click the button to display a confirm box.</p>

<button onclick="myFunction()">Try it</button>

<script>
function myFunction() {
  confirm("Press a button!");
}
</script>

</body>
</html>

Everything works well. But when I try it in Godaddy HTML block. It does not work.In Godaddy, Button is seen but when I click button nothing happens so it does not work although design is not problematic.

How can I make it work? Is it possible to run confirm method in Godaddy HTML Block? In fact I can run different Javascript features / code like local storage or document.execCommand("copy"); without any problem in Godaddy. But Javascript confirm method does not working in Godaddy. How can we solve it?

Edit: You can provide alternative solution to ask user "yes" - "no" question in Godaddy by using Javascript - HTML. My aim is to ask user "Are you sure to do this?" I mean you can provide a solution rather than confirm.



from Javascript Confirm not working in Godaddy

PYSPARK_PYTHON setup in jupyter notebooks is ignored

I've been trying to setup PYSPARK_PYTHON from a juputer notebook(using jupyter lab) to use a specific conda env but i cannot find a way to make it work, I have found some examples using:

import os

os.environ['PYSPARK_PYTHON'] = "<the path>"

But it did not work so I also tried:

spark = pyspark.sql.SparkSession.builder \
       .master("yarn-client") \
       .appName(session_name) \
       .config("spark.yarn.appMasterEnv.PYSPARK_PYTHON","<the path>") \
       .enableHiveSupport() \
       .getOrCreate(cluster=cluster)

sc = spark.sparkContext
sqlContext = SQLContext(sc)

But it never uses the specified python version in the specified path , question is, is it possible the config is being ignored? do something else needs to be done in notebook?

I'm using yarn-client mode



from PYSPARK_PYTHON setup in jupyter notebooks is ignored

Converting TableLayout to RecyclerView

I'm trying to convert my TableLayout to a RecyclerView. The TableLayout is fine so far as it goes, but some of the tables have lots of rows, and are really slow to inflate, and I think that a RecyclerView would be the more efficient model to use (and would allow easy access to searching/filtering functionality).

The issue I'm having is that my TableLayout is defined as a set of custom views or compound controls, with a few standard views thrown in, like so:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res-auto"
    style="@style/MySection"
    android:id="@+id/section_cape" >

    <TableLayout style="@style/MyTable"
        android:id="@+id/table_cape" >

        <com.example.myapp.CompoundSwitch
            android:id="@+id/cape"
            custom:switch_label_tag="label_show"
            custom:switch_label_text="@string/label_show"
            custom:switch_indented="false"
            android:visibility="visible" />

        <TextView
            style="@style/MyTextView"
            android:id="@+id/info_capeNotAvailable"
            android:text="@string/info_notAvailable" />

        <com.example.myapp.CompoundSpinner
            android:id="@+id/capeProvider"
            custom:spinner_label_tag="label_variableProvider"
            custom:spinner_label_text="@string/label_provider"
            custom:spinner_indented="false"
            android:visibility="visible" />

        <com.example.myapp.CompoundSlider
            android:id="@+id/capeTransition"
            custom:slider_label_tag="label_providerTransition"
            custom:slider_label_text="@string/label_transition"
            custom:slider_indented="true"
            custom:slider_range="false"
            android:visibility="gone" />

        ... etc ...

Each of the custom views is defined as a TableRow.

I'm struggling to understand what to inflate in the onCreateViewHolder() method of my Adapter. Of course, each custom view does have a layout, but for some of these custom views, there are several layouts and a different layout is used depending on what custom attributes are defined in the xml.

So how do I map my rows of custom views (each with its own set of attributes) into the RecyclerView structure?

My current thinking is that I would have to move each row (custom view) statement into its own separate layout xml file, and then inflate the appropriate one of these in the onCreateViewHolder() method (based on viewType) but I'm not sure that this is the correct approach... and there would be a lot of very small layout files... seems unnecessarily unwieldy.



from Converting TableLayout to RecyclerView

Formatting numbers in compose TextField

I am trying to create a reusable NumberField component:

@Composable
fun NumberField(
  value: Number?,
  onNumberChange: (Number) -> Unit,
) {
  TextField(
    value = value?.toString() ?: "",
    onValueChange = {
      it.toDoubleOrNull()?.let { value ->
        if (value % 1.0 == 0.0) {
          onNumberChange(value.toInt())
        } else {
          onNumberChange(value)
        }
      }
    },
    singleLine = true,
    keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number)
  )
}

To be used as:

@Composable
fun NumberContent() {
  val number = remember { mutableStateOf<Number?>(null) }

  NumberField(value = number.value) {
    number.value = it
  }
}

I would like the number to be an Int or Double depending on what the user is typing. What I have above works until you try to enter a decimal number, as it seems "5.", does not parse as double. I want to allow the user to type 5. and then fill in rest. As such I don't want to add a zero after decimal automatically because that might not be the next number they want to enter. Is this the best way to go about it? I know that I can just accept any text and then try to format the text they entered later as an int or double and make them fix it then, just thought it would be nice to bundle it all in the composable.



from Formatting numbers in compose TextField

Android + ESP32 send data over bluetooth (BLE)

I'm trying to send data from my android app to an esp32 over bluetooth (BLE) but i can't find the proper way to do it. All i can do for now is scan and find ble devices. My arduino code is working as i want (it receives the data properly) because i used another app which let me send data to ble devices so i know the arduino code is fine.

I've been searching for days here and google how to achieve it but i still stucked in it. This is my code for now:

Scanner:

class BluetoothFragment : Fragment() {
    private lateinit var binding: FragmentBluetoothBinding
    private var list : MutableList<BluetoothDevice> = ArrayList()
    private lateinit var  bluetoothAdapter : BluetoothAdapter

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        Log.d("DeviceListActivity", "onCreate()")
        return inflater.inflate(R.layout.fragment_bluetooth, container, false)
    }

    // TODO: 19/05/2021 implementar listener en el recycler view para crear la conexión con el ble

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding = FragmentBluetoothBinding.bind(view)
        if (ContextCompat.checkSelfPermission(
                requireContext(),
                Manifest.permission.ACCESS_COARSE_LOCATION
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            val permissions = arrayOf(
                android.Manifest.permission.ACCESS_COARSE_LOCATION,
            )
            ActivityCompat.requestPermissions(requireActivity(), permissions, 0)
        }

        setRecyclerView(list)
    }

    private val bleScanner = object :ScanCallback() {
        override fun onScanResult(callbackType: Int, result: ScanResult?) {
            super.onScanResult(callbackType, result)
            Log.d("pepe","onScanResult: ${result?.device?.address} - ${result?.device?.name}")
            if(result?.device?.name?.isNotEmpty() == true){
                var bluetoothDevice = result?.device?.name?.let { BluetoothDevice(it) }
                if (bluetoothDevice != null) {
                    list.add(bluetoothDevice)
                    bluetoothAdapter.notifyDataSetChanged()
                }
            }
        }

        override fun onBatchScanResults(results: MutableList<ScanResult>?) {
            super.onBatchScanResults(results)
            Log.d("DeviceListActivity","onBatchScanResults:${results.toString()}")
        }

        override fun onScanFailed(errorCode: Int) {
            super.onScanFailed(errorCode)
            Log.d("DeviceListActivity", "onScanFailed: $errorCode")
        }

    }

    private val bluetoothLeScanner: BluetoothLeScanner
        get() {
            val bluetoothManager = requireActivity().getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
            val bluetoothAdapter = bluetoothManager.adapter
            return bluetoothAdapter.bluetoothLeScanner
        }

    class ListDevicesAdapter(context: Context?, resource: Int) : ArrayAdapter<String>(context!!, resource)


    override fun onStart() {
        Log.d("DeviceListActivity","onStart()")
        super.onStart()
        bluetoothLeScanner.startScan(bleScanner)
    }

    override fun onStop() {
        bluetoothLeScanner.stopScan(bleScanner)
        super.onStop()
    }

    private fun setRecyclerView(allCategories: List<BluetoothDevice>) {
        val layoutManager: RecyclerView.LayoutManager = LinearLayoutManager(context)
        binding.rvBluetooth.layoutManager = layoutManager
        bluetoothAdapter = BluetoothAdapter(allCategories)
        binding.rvBluetooth.adapter = bluetoothAdapter
    }
}

Arduino code (I'm controlling a little car with it so thats why i have 5 different values):

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>

#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

// Motor 1
int motor1Pin1 = 23;
int motor1Pin2 = 22;
int enable1Pin = 21;

// Motor 2
int motor2Pin1 = 18;
int motor2Pin2 = 19;
int enable2Pin = 5;

const int freq = 30000;
const int pwmChannel = 0;
const int resolution = 8;
int dutyCycle = 200;

class MyCallbacks: public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic *pCharacteristic) {
      std::string value = pCharacteristic->getValue();

      if (value.length() > 0) {
        if (value[0] == '1') {
          dutyCycle = 200;
          Serial.println("Moving Forward");
          digitalWrite(motor1Pin1, LOW);
          digitalWrite(motor1Pin2, HIGH);
          digitalWrite(motor2Pin1, LOW);
          digitalWrite(motor2Pin2, HIGH);
          while (dutyCycle <= 255) {
            ledcWrite(pwmChannel, dutyCycle);
            dutyCycle = dutyCycle + 5;
            delay(500);
          }

        }
        if (value[0] == '4') {
          dutyCycle = 200;
          Serial.println("Moving Backwards");
          digitalWrite(motor1Pin1, HIGH);
          digitalWrite(motor1Pin2, LOW);
          digitalWrite(motor2Pin1, HIGH);
          digitalWrite(motor2Pin2, LOW);
          while (dutyCycle <= 255) {
            ledcWrite(pwmChannel, dutyCycle);
            dutyCycle = dutyCycle + 5;
            delay(500);
          }
        }
        if (value[0] == '2') {
          dutyCycle = 100;
          Serial.println("Motor right");
          digitalWrite(motor1Pin1, LOW);
          digitalWrite(motor1Pin2, HIGH);
          digitalWrite(motor2Pin1, HIGH);
          digitalWrite(motor2Pin2, LOW);
        }
        if (value[0] == '3') {
          dutyCycle = 100;
          Serial.println("Motor left");
          digitalWrite(motor1Pin1, HIGH);
          digitalWrite(motor1Pin2, LOW);
          digitalWrite(motor2Pin1, LOW);
          digitalWrite(motor2Pin2, HIGH);
        }
        if (value[0] == '0') {
          Serial.println("Motor stopped");
          digitalWrite(motor1Pin1, LOW);
          digitalWrite(motor1Pin2, LOW);
          digitalWrite(motor2Pin1, LOW);
          digitalWrite(motor2Pin2, LOW);
        }
      }
    }
};


void setup() {
  Serial.begin(115200);
  BLEDevice::init("Andruino");
  BLEServer *pServer = BLEDevice::createServer();

  BLEService *pService = pServer->createService(SERVICE_UUID);

  BLECharacteristic *pCharacteristic = pService->createCharacteristic(
                                         CHARACTERISTIC_UUID,
                                         BLECharacteristic::PROPERTY_WRITE
                                       );

  pCharacteristic->setCallbacks(new MyCallbacks());
  pService->start();

  BLEAdvertising *pAdvertising = pServer->getAdvertising();
  pAdvertising->start();

  pinMode(motor1Pin1, OUTPUT);
  pinMode(motor1Pin2, OUTPUT);
  pinMode(enable1Pin, OUTPUT);

  pinMode(motor2Pin1, OUTPUT);
  pinMode(motor2Pin2, OUTPUT);
  pinMode(enable2Pin, OUTPUT);

  ledcSetup(pwmChannel, freq, resolution);

  ledcAttachPin(enable1Pin, pwmChannel);
  ledcAttachPin(enable2Pin, pwmChannel);
 
  ledcWrite(pwmChannel, dutyCycle);
}

void loop() {

}

How could i send data from my android app to esp32 over bluetooth?



from Android + ESP32 send data over bluetooth (BLE)

jQuery does not calculate Value Added Tax on Form

I have added this field to my form in order to calculate value added tax (vat):

<div class="col-md-4">
    <div class="form-check">
        <input type="radio" id="vat_on" name="vat" value="on" checked>
        <label class="form-check-label">
        Calculate value added tax  
        </label>
    </div>
    <div class="form-check">
        <input type="radio" id="vat_off" name="vat" value="off">
        <label class="form-check-label">
            Do not calculate value added tax
        </label>
    </div>
</div>

And I tried adding this as jQuery:

if($('[name=vat]:checked').val() === 'on'){
   var value_added_tax = ((price_final*cnt) - ((price_final*cnt)*0.9)).toLocaleString();
}else{
   var value_added_tax = (0).toLocaleString();
}

But when I test this and checked the Calculate value added tax radio button, it returns: Nan !

However it should be returning a value instead of Nan.

I have also tried removing toLocaleString() from both conditions, but didn't solve the problem.

So what is going wrong here ? How can I fix this issue ?

I would really appreciate any idea or suggestion from you guys...

Thanks in advance.



from jQuery does not calculate Value Added Tax on Form

adb: failed to open app.apk: Operation not permitted

I am unable to run the app on a physical device (Xiaomi) after upgrading the flutter SDK to the latest version. It is working fine on downgrading the flutter and few packages.

OS: Ubuntu 18.04.5 LTS

The error details are in the below image. I have also tried to install the apk via the command line which is also not working

$ adb install app.apk
adb: failed to open app.apk: Operation not permitted

Tried adb kill-server, gave full permission to the folder, etc. Nothing worked.

Please help.

The error details are in the below image



from adb: failed to open app.apk: Operation not permitted

How can I have Python TTK use the Windows OS default progress bar theme?

How in TTK can I use the OS default loader theme instead of the tkinter one?

Loading - Known

Loading - Unknown

This is an example of a normal progress bar.

from tkinter import *
from tkinter.ttk import *

root = Tk()
root.geometry('400x250+1000+300')

progress_bar = Progressbar(root, orient=HORIZONTAL, length=100, mode='indeterminate')
progress_bar.pack(expand=True)
progress_bar.start()

root.mainloop()

I get a progress bar, but it isn't themed like the OS default progress bar is.

TTK-themed progress bar

I thought that perhaps a style could make it look like that, so I listed the styles:

Style().theme_names() # ('winnative', 'clam', 'alt', 'default', 'classic', 'vista', 'xpnative')

I tried each one like so:

from tkinter import *
from tkinter.ttk import *

root = Tk()
root.geometry('400x250+1000+300')

os_default_style = Style()
os_default_style.theme_use('THEME')
os_default_style.configure('osdefault.Horizontal.TProgressbar')
progress_bar = Progressbar(root, orient=HORIZONTAL, length=100, mode='indeterminate', style='osdefault.Horizontal.TProgressbar')
progress_bar.pack(expand=True)
progress_bar.start()

root.mainloop()

They produce ones that are similar, but none are the system. How do I make it look exactly like one used by the system?



from How can I have Python TTK use the Windows OS default progress bar theme?

Instantiate ES6 class

I am trying to implement the following tags with my design.

I am using the class Tags to simply create tags within my input field, however when I initialize the library I get an error.

const ACTIVE_CLASS = "bg-light";
const VALUE_ATTRIBUTE = "data-value";

class Tags {
  /**
   * @param {HTMLSelectElement} selectElement
   */
  constructor(selectElement) {
    this.selectElement = selectElement;
    this.selectElement.style.display = "none";
    this.placeholder = this.getPlaceholder();
    this.allowNew = selectElement.dataset.allowNew ? true : false;

    // Create elements
    this.holderElement = document.createElement("div");
    this.containerElement = document.createElement("div");
    this.dropElement = document.createElement("ul");
    this.searchInput = document.createElement("input");

    this.holderElement.appendChild(this.containerElement);
    this.containerElement.appendChild(this.searchInput);
    this.holderElement.appendChild(this.dropElement);
    // insert after
    this.selectElement.parentNode.insertBefore(this.holderElement, this.selectElement.nextSibling);

    // Configure them
    this.configureSearchInput();
    this.configureHolderElement();
    this.configureDropElement();
    this.configureContainerElement();
    this.buildSuggestions();
  }

  /**
   * Attach to all elements matched by the selector
   * @param {string} selector
   */
  static init(selector = "select[multiple]") {
    let list = document.querySelectorAll(selector);
    for (let i = 0; i < list.length; i++) {
      let el = list[i];
      let inst = new Tags(el);
    }
  }

  /**
   * @returns {string}
   */
  getPlaceholder() {
    let firstOption = this.selectElement.querySelector("option");
    if (!firstOption) {
      return;
    }
    if (!firstOption.value) {
      let placeholder = firstOption.innerText;
      firstOption.remove();
      return placeholder;
    }
    if (this.selectElement.getAttribute("placeholder")) {
      return this.selectElement.getAttribute("placeholder");
    }
    if (this.selectElement.getAttribute("data-placeholder")) {
      return this.selectElement.getAttribute("data-placeholder");
    }
    return "";
  }

  configureDropElement() {
    this.dropElement.classList.add("dropdown-menu");
  }

  configureHolderElement() {
    this.holderElement.classList.add("form-control");
    this.holderElement.classList.add("dropdown");
  }

  configureContainerElement() {
    this.containerElement.addEventListener("click", (event) => {
      this.searchInput.focus();
    });

    // add initial values
    let initialValues = this.selectElement.querySelectorAll("option[selected]");
    for (let j = 0; j < initialValues.length; j++) {
      let initialValue = initialValues[j];
      if (!initialValue.value) {
        continue;
      }
      this.addItem(initialValue.innerText, initialValue.value);
    }
  }

  configureSearchInput() {
    this.searchInput.type = "text";
    this.searchInput.autocomplete = false;
    this.searchInput.style.border = 0;
    this.searchInput.style.outline = 0;
    this.searchInput.style.maxWidth = "100%";

    this.adjustWidth();

    this.searchInput.addEventListener("input", (event) => {
      this.adjustWidth();
      if (this.searchInput.value.length >= 1) {
        this.showSuggestions();
      } else {
        this.hideSuggestions();
      }
    });
    // keypress doesn't send arrow keys
    this.searchInput.addEventListener("keydown", (event) => {
      if (event.code == "Enter") {
        let selection = this.getActiveSelection();
        if (selection) {
          this.addItem(selection.innerText, selection.getAttribute(VALUE_ATTRIBUTE));
          this.resetSearchInput();
          this.hideSuggestions();
        } else {
          // We use what is typed
          if (this.allowNew) {
            this.addItem(this.searchInput.value);
            this.resetSearchInput();
            this.hideSuggestions();
          }
        }
        event.preventDefault();
        return;
      }
      if (event.code == "ArrowUp") {
        this.moveSelectionUp();
      }
      if (event.code == "ArrowDown") {
        this.moveSelectionDown();
      }
      if (event.code == "Backspace") {
        if (this.searchInput.value.length == 0) {
          this.removeLastItem();
          this.adjustWidth();
        }
      }
    });
  }

  moveSelectionUp() {
    let active = this.getActiveSelection();
    if (active) {
      let prev = active.parentNode;
      do {
        prev = prev.previousSibling;
      } while (prev && prev.style.display == "none");
      if (!prev) {
        return;
      }
      active.classList.remove(ACTIVE_CLASS);
      prev.querySelector("a").classList.add(ACTIVE_CLASS);
    }
  }

  moveSelectionDown() {
    let active = this.getActiveSelection();
    if (active) {
      let next = active.parentNode;
      do {
        next = next.nextSibling;
      } while (next && next.style.display == "none");
      if (!next) {
        return;
      }
      active.classList.remove(ACTIVE_CLASS);
      next.querySelector("a").classList.add(ACTIVE_CLASS);
    }
  }

  /**
   * Adjust the field to fit its content
   */
  adjustWidth() {
    if (this.searchInput.value) {
      this.searchInput.size = this.searchInput.value.length + 1;
    } else {
      // Show the placeholder only if empty
      if (this.getSelectedValues().length) {
        this.searchInput.placeholder = "";
        this.searchInput.size = 1;
      } else {
        this.searchInput.size = this.placeholder.length;
        this.searchInput.placeholder = this.placeholder;
      }
    }
  }

  /**
   * Add suggestions from element
   */
  buildSuggestions() {
    let options = this.selectElement.querySelectorAll("option");
    for (let i = 0; i < options.length; i++) {
      let opt = options[i];
      if (!opt.getAttribute("value")) {
        continue;
      }
      let newChild = document.createElement("li");
      let newChildLink = document.createElement("a");
      newChild.append(newChildLink);
      newChildLink.classList.add("dropdown-item");
      newChildLink.setAttribute(VALUE_ATTRIBUTE, opt.getAttribute("value"));
      newChildLink.setAttribute("href", "#");
      newChildLink.innerText = opt.innerText;
      this.dropElement.appendChild(newChild);

      // Hover sets active item
      newChildLink.addEventListener("mouseenter", (event) => {
        this.removeActiveSelection();
        newChild.querySelector("a").classList.add(ACTIVE_CLASS);
      });

      newChildLink.addEventListener("click", (event) => {
        event.preventDefault();
        this.addItem(newChildLink.innerText, newChildLink.getAttribute(VALUE_ATTRIBUTE));
        this.resetSearchInput();
        this.hideSuggestions();
      });
    }
  }

  resetSearchInput() {
    this.searchInput.value = "";
    this.adjustWidth();
  }

  /**
   * @returns {array}
   */
  getSelectedValues() {
    let selected = this.selectElement.querySelectorAll("option:checked");
    return Array.from(selected).map((el) => el.value);
  }

  /**
   * The element create with buildSuggestions
   */
  showSuggestions() {
    if (!this.dropElement.classList.contains("show")) {
      this.dropElement.classList.add("show");
    }

    // Position next to search input
    this.dropElement.style.left = this.searchInput.offsetLeft + "px";

    // Get search value
    let search = this.searchInput.value.toLocaleLowerCase();

    // Get current values
    let values = this.getSelectedValues();

    // Filter the list according to search string
    let list = this.dropElement.querySelectorAll("li");
    let found = false;
    let firstItem = null;
    for (let i = 0; i < list.length; i++) {
      let item = list[i];
      let text = item.innerText.toLocaleLowerCase();
      let link = item.querySelector("a");

      // Remove previous selection
      link.classList.remove(ACTIVE_CLASS);

      // Hide selected values
      if (values.indexOf(link.getAttribute(VALUE_ATTRIBUTE)) != -1) {
        item.style.display = "none";
        continue;
      }

      if (text.indexOf(search) !== -1) {
        item.style.display = "list-item";
        found = true;
        if (!firstItem) {
          firstItem = item;
        }
      } else {
        item.style.display = "none";
      }
    }

    // Special case if nothing matches
    if (!found) {
      this.dropElement.classList.remove("show");
    }

    // Always select first item
    if (firstItem) {
      if (this.holderElement.classList.contains("is-invalid")) {
        this.holderElement.classList.remove("is-invalid");
      }
      firstItem.querySelector("a").classList.add(ACTIVE_CLASS);
    } else {
      // No item and we don't allow new items => error
      if (!this.allowNew) {
        this.holderElement.classList.add("is-invalid");
      }
    }
  }

  /**
   * The element create with buildSuggestions
   */
  hideSuggestions(dropEl) {
    if (this.dropElement.classList.contains("show")) {
      this.dropElement.classList.remove("show");
    }
    if (this.holderElement.classList.contains("is-invalid")) {
      this.holderElement.classList.remove("is-invalid");
    }
  }

  /**
   * @returns {HTMLElement}
   */
  getActiveSelection() {
    return this.dropElement.querySelector("a." + ACTIVE_CLASS);
  }

  removeActiveSelection() {
    let selection = this.getActiveSelection();
    if (selection) {
      selection.classList.remove(ACTIVE_CLASS);
    }
  }

  removeLastItem() {
    let items = this.containerElement.querySelectorAll("span");
    if (!items.length) {
      return;
    }
    let lastItem = items[items.length - 1];
    this.removeItem(lastItem.getAttribute(VALUE_ATTRIBUTE));
  }

  /**
   * @param {string} text
   * @param {string} value
   */
  addItem(text, value) {
    if (!value) {
      value = text;
    }
    let span = document.createElement("span");
    span.classList.add("badge");
    span.classList.add("bg-primary");
    span.classList.add("me-2");
    span.setAttribute(VALUE_ATTRIBUTE, value);
    span.innerText = text;
    this.containerElement.insertBefore(span, this.searchInput);

    // update select
    let opt = this.selectElement.querySelector('option[value="' + value + '"]');
    if (opt) {
      opt.setAttribute("selected", "selected");
    } else {
      // we need to create a new option
      opt = document.createElement("option");
      opt.value = value;
      opt.innerText = text;
      opt.setAttribute("selected", "selected");
      this.selectElement.appendChild(opt);
    }
  }

  /**
   * @param {string} value
   */
  removeItem(value) {
    let item = this.containerElement.querySelector("span[" + VALUE_ATTRIBUTE + '="' + value + '"]');
    if (!item) {
      return;
    }
    item.remove();

    // update select
    let opt = this.selectElement.querySelector('option[value="' + value + '"]');
    if (opt) {
      opt.removeAttribute("selected");
    }
  }
}

export default Tags;

import Tags
Tags.init();
<!DOCTYPE html>
<html lang="en">

<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="description" content="">
  <meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors">
  <meta name="generator" content="Hugo 0.80.0">
  <title>Insider</title>

  <link rel="canonical" href="">

  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BmbxuPwQa2lc/FVzBcNJ7UAyJxM6wuqIj61tLrc4wSX0szH/Ev+nYRRuWlolflfl" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.4.0/font/bootstrap-icons.css">

  <!-- Favicons -->
  <link rel="apple-touch-icon" href="https://getbootstrap.com/docs/5.0/assets/img/favicons/apple-touch-icon.png" sizes="180x180">
  <link rel="icon" href="https://getbootstrap.com/docs/5.0/assets/img/favicons/favicon-32x32.png" sizes="32x32" type="image/png">
  <link rel="icon" href="https://getbootstrap.com/docs/5.0/assets/img/favicons/favicon-16x16.png" sizes="16x16" type="image/png">
  <link rel="manifest" href="https://getbootstrap.com/docs/5.0/assets/img/favicons/manifest.json">
  <link rel="mask-icon" href="https://getbootstrap.com/docs/5.0/assets/img/favicons/safari-pinned-tab.svg" color="#7952b3">
  <link rel="icon" href="https://getbootstrap.com/docs/5.0/assets/img/favicons/favicon.ico">
  <meta name="theme-color" content="#7952b3">

  <!-- Custom styles for this template -->
  <link href="https://unpkg.com/bootstrap-table@1.18.3/dist/bootstrap-table.min.css" rel="stylesheet">
</head>

<body>
  <header class="p-3 bg-dark text-white">
    <div class="container">
      <div class="d-flex flex-wrap align-items-center justify-content-center justify-content-lg-start">
        <ul class="nav col-12 col-lg-auto me-lg-auto mb-2 justify-content-center mb-md-0">
          <li>
            <button class="btn btn-outline-light" type="button" data-bs-toggle="modal" data-bs-target="#exampleModal">Check
                    </button>
          </li>
        </ul>
      </div>
    </div>
  </header>

  <main class="container pt-3">
    <div class="row mt-3">
      <h2>Content</h2>
    </div>
  </main>

  <!-- Modal -->
  <div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
    <div class="modal-dialog modal-lg">
      <div class="modal-content">
        <div class="modal-header">
          <h5 class="modal-title" id="exampleModalLabel">Your Check</h5>
          <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
        </div>
        <div class="modal-body">
          <br>
          <p class="h2">Check</p>
          <p>Input your symbols and we will send you all relevant information.</p>
          <br>
          <form>
            <div class="col">
              <select class="form-select" id="validationTags" multiple="" data-allow-new="true" style="display: none;">
                <option value="1" selected="selected">JavaScript</option>
                <option value="2">HTML5</option>
                <option value="3">CSS3</option>
                <option value="4">jQuery</option>
                <option value="5">React</option>
                <option value="6">Angular</option>
                <option value="7">Vue</option>
                <option value="8">Python</option>
              </select>
              <div class="form-control dropdown">
                <div><span class="badge bg-primary me-2" data-value="1">JavaScript</span><input type="text" autocomplete="false" placeholder="" size="1" style="border: 0px; outline: 0px; max-width: 100%;">
                </div>
                <ul class="dropdown-menu">
                  <li><a class="dropdown-item" data-value="1" href="#">JavaScript</a></li>
                  <li><a class="dropdown-item" data-value="2" href="#">HTML5</a></li>
                  <li><a class="dropdown-item" data-value="3" href="#">CSS3</a></li>
                  <li><a class="dropdown-item" data-value="4" href="#">jQuery</a></li>
                  <li><a class="dropdown-item" data-value="5" href="#">React</a></li>
                  <li><a class="dropdown-item" data-value="6" href="#">Angular</a></li>
                  <li><a class="dropdown-item" data-value="7" href="#">Vue</a></li>
                  <li><a class="dropdown-item" data-value="8" href="#">Python</a></li>
                </ul>
              </div>
              <div class="invalid-feedback">Please select a valid tag.</div>
            </div>
            <button type="submit" class="btn btn-primary">Submit</button>
          </form>
        </div>
      </div>
    </div>
  </div>
  <!-- Modal END -->

  <footer class="text-muted py-5">
    <div class="container">
      <p class="mb-1">Footer</p>
    </div>
  </footer>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/js/bootstrap.bundle.min.js" integrity="sha384-b5kHyXgcpbZJO/tY9Ul7kGkf1S0CWuKcCD38l8YkeH8z8QjE0GmW1gYU5S9FOnJ0" crossorigin="anonymous"></script>

</body>

</html>

As you can see the script does not work.

To be honest I am not quite sure why. I am guessing there is a problem when initializing the Tags-class. I currently do it the following:

    import Tags
    Tags.init();

Any suggestions what is wrong or how to correctly call the init()-function from the Tags-class?

I appreciate your replies!



from Instantiate ES6 class

How to prevent resize and maximize of javascript window

How to prevent resizeand maximize of javascript window.

I am trying to stop my resizing and maximising the window.

i am using following code

var win = window.open(myURL, "_blank", "toolbar=no,menubar=no,scrollbars=yes,dialog=yes,resizable=no,top=100,left=250,width=800,height=530");
        

have tried multiple solution from stackoverflow but not get any luck.Can anybody help me,



from How to prevent resize and maximize of javascript window

React-spring Parallax

I'm trying to implement some parallax animation using react-spring, but I'm not able to find a way to space the animated containers equally.

Here I made a snippet which contains a basic parallax effect animating some divs on scroll:

<Parallax pages={5}>
  <ParallaxLayer offset={0} speed={0.4} style=>
    <div className="box" />
  </ParallaxLayer>

  <ParallaxLayer offset={0.9} speed={0.6} style=>
    <div className="box" />
  </ParallaxLayer>

  <ParallaxLayer offset={1.1} speed={0.8} style=>
    <div className="box" />
  </ParallaxLayer>

  <ParallaxLayer offset={1.9} speed={1} style=>
    <div className="box" />
  </ParallaxLayer>

  <ParallaxLayer offset={2} speed={1.2} style=>
    <div className="box" />
  </ParallaxLayer>
</Parallax>

I set them with an incremental speed to give that parallax effect, plus I tried increasing / decreasing the offsets to have them distanciated equally, but that didn't work much as they get placed too close or too far away between each other.

Is there a way to overcome this?



from React-spring Parallax

Android Q, programmatically connect to different WiFi AP for internet

As in Android Q, several WiFi APIs are restricted. I am trying to use alternate APIs to connect to different Wifi AP for internet.

Below is my code :

    WifiNetworkSpecifier.Builder builder = new WifiNetworkSpecifier.Builder();
    builder.setSsid("wifi-ap-ssid");
    builder.setWpa2Passphrase("wifi-ap-password");

    WifiNetworkSpecifier wifiNetworkSpecifier = builder.build();

    NetworkRequest.Builder networkRequestBuilder1 = new NetworkRequest.Builder();
    networkRequestBuilder1.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
    networkRequestBuilder1.setNetworkSpecifier(wifiNetworkSpecifier);

    NetworkRequest nr = networkRequestBuilder1.build();
    ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    cm.requestNetwork(nr, callback);

This allows me to connect but Internet is disabled. This is working as defined in Android docs.

Alternate way i tried is below :

    WifiNetworkSuggestion.Builder wifiNetworkSuggestionBuilder1 = new WifiNetworkSuggestion.Builder();
    wifiNetworkSuggestionBuilder1.setSsid("wifi-ap-ssid");
    wifiNetworkSuggestionBuilder1.setWpa2Passphrase("wifi-ap-password");
    WifiNetworkSuggestion wifiNetworkSuggestion = wifiNetworkSuggestionBuilder1.build();
    List<WifiNetworkSuggestion> list = new ArrayList<>();
    list.add(wifiNetworkSuggestion);
    wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
    wifiManager.removeNetworkSuggestions(new ArrayList<WifiNetworkSuggestion>());
    wifiManager.addNetworkSuggestions(list);

declared permission in Manifest :

<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>

Using this didn't change anything in behavior.

Please let know sequence of APIs to connect successfully to different Wifi AP with internet capability.



from Android Q, programmatically connect to different WiFi AP for internet

document.getElementById().onclick not working inside Google Tag Manager

I am using a cookie consent management service, calling it via Google Tag Manager (custom HTML tag). Their script has function CookieControl.open(); which opens a sidebar to allow users to change their preferences.

<script src="https://cc.cdn.civiccomputing.com/9/cookieControl-9.x.min.js"></script>
<script>
var config = {
...
...
...
};

CookieControl.load(config);

window.onload = function () {
    var cookiesExist = document.querySelector('#cookies');
    if (cookiesExist) {
        document.getElementById("cookies").onclick =
            function () {
                CookieControl.open();
            };
    }
};
</script>

In my footer, I have added a link <a id="cookies">Cookies</a> which the function in GTM is supposed to target. Unfortunately this is not working and the sidebar does not open when I click on the "Cookies" link. It does sometimes work, randomly, on Safari on the iPad. But it's not consistent. Any ideas why most of the time this doesn't work (but other times it does)?



from document.getElementById().onclick not working inside Google Tag Manager

How to run an application in codesandbox with different subfolder for backend and frontend

I want to get a codesandbox for an app I am working on... The project now has two different subfolders named backend and frontend... How can that be done? I am sending for you my packages.json file content:

{
  "name": "projeto_aplicado",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "dependencies": {
    "concurrently": "^6.2.0"
  },
  "devDependencies": {},
  "scripts": {
    "server": "npm run server --prefix backend",
    "start": "concurrently \"npm run server\" \"npm run client\" ",
    "client": "npm start --prefix frontend"
  },
  "author": "",
  "license": "ISC"
}

I am also sending the link for my web app: https://codesandbox.io/s/blissful-fire-jjnl5?file=/package.json:0-393



from How to run an application in codesandbox with different subfolder for backend and frontend

Saturday 29 May 2021

Max jsx props per line within a function parameter

I am using prettier-eslint and trying to add a new eslint rule that limits the number of jsx props per line:

eslintrc:

...
rules: {
  'react/jsx-max-props-per-line': [2, { maximum: 1 }],
  'react/jsx-indent-props': [2, 2],
  'react/jsx-first-prop-new-line': [2, 'multiline'],
}
...

However, when I have code like the following, it gets corrected as detailed below. I would prefer it to be corrected instead to the following. jsx-wrap-multiline seems to go after the solution I am looking for, but it doesn't deal with function parameters. How would I be able to get the desired linting linsted below? Thanks!

// Original Code
const foo = () => showModal(<SampleComponent title="hello world" id={123} />);

// Fixed Code
const foo = () =>
  showModal(<SampleComponent
    title="hello world"
    id={123}
  />);

// Desired Fix
const foo = () => showModal(
  <SampleComponent
    title="hello world"
    id={123}
  />
);

full .estlintrc.js:

module.exports = {
  parser: '@typescript-eslint/parser',
  parserOptions: {
    project: './tsconfig.json',
  },
  env: {
    browser: true,
  },
  overrides: [
    {
      files: ['*.test.*'],
      env: {
        jest: true,
      },
    },
  ],
  plugins: ['@typescript-eslint', 'jsx-max-len', '@babel'],
  extends: [
    'airbnb-typescript',
    'plugin:@typescript-eslint/recommended',
    'plugin:react/recommended',
    'prettier',
    'prettier/react',
    'prettier/@typescript-eslint',
  ],
  globals: {
    // tests
    page: true,
    browser: true,
    describe: true,
    beforeAll: true,
    beforeEach: true,
    afterAll: true,
    afterEach: true,
    it: true,
    test: true,
    expect: true,
    global: true,
  },
  rules: {
    // ----- REACT ----- //
    'react/destructuring-assignment': 0,
    'react/display-name': 0,
    'react/jsx-closing-bracket-location': 1,
    'react/jsx-curly-newline': 0, // handled by prettier
    'react/jsx-indent': 'off',
    'react/jsx-one-expression-per-line': 0, // unnecessary rule
    'react/jsx-props-no-spreading': 0, // Allow prop spreading
    'react/jsx-wrap-multilines': ['error', { arrow: true, return: true, declaration: true }],
    'react/no-array-index-key': 0, // index keys are fine when used correctly
    'react/no-unused-prop-types': 0, // Fails on SFC which GoogleMapReact is, etc.
    'react/prop-types': 0, // Don't use prop types, use Typescript
    'react/require-default-props': 0,
    'react/jsx-max-props-per-line': [2, { maximum: 1 }],
    'react/jsx-indent-props': [2, 2],
    'react/jsx-first-prop-new-line': [2, 'multiline'],

    // ----- JSX ----- //
    'jsx-a11y/click-events-have-key-events': 0,
    'jsx-a11y/label-has-associated-control': 0,
    'jsx-a11y/label-has-for': 0, // good eventually, but not now
    'jsx-a11y/no-noninteractive-element-interactions': 0,
    'jsx-a11y/no-static-element-interactions': 0,
    'jsx-max-len/jsx-max-len': [2, { lineMaxLength: 100, tabWidth: 2, maxAttributesPerLine: 1 }],

    // ----- TYPESCRIPT ----- //
    '@typescript-eslint/ban-types': 0,
    '@typescript-eslint/explicit-module-boundary-types': 0, // Eventually turn these back on
    '@typescript-eslint/indent': 'off',
    '@typescript-eslint/no-empty-interface': 0,
    '@typescript-eslint/no-explicit-any': 0, // For now allow 'any'
    '@typescript-eslint/no-inferrable-types': 0,
    '@typescript-eslint/no-redeclare': 0,
    '@typescript-eslint/no-var-requires': 0,
    '@typescript-eslint/prefer-as-const': 0,
    '@typescript-eslint/prefer-optional-chain': 'error',

    // ----- OTHER ----- //
    'array-bracket-spacing': 0, // ['error', 'always'],
    'arrow-parens': ['error', 'always'],
    'comma-dangle': ['error', 'always-multiline'],
    // Always enforce curly braces around if/else blocks; https://eslint.org/docs/rules/curly
    curly: 'error',
    'import/named': 0, // doesn't play well with Typescript
    'implicit-arrow-linebreak': 0, // this conflicts with lines that are too long
    'import/prefer-default-export': 0,
    // This doesn't work with the aliases we've set up, plus I believe Typescript catches this
    // anyways
    'import/no-unresolved': 0,
    indent: 'off',
    'no-alert': 0,
    'no-case-declarations': 0,
    'no-console': ['error', { allow: ['warn', 'error'] }], // allow warnings and error logs
    'no-plusplus': ['error', { allowForLoopAfterthoughts: true }],
    // GraphQL relies on an internal variable, __typename, with a dangling underscore.
    'no-underscore-dangle': ['error', { allow: ['__typename'] }],
    // Use the babel/eslint plugin to handle optional changing something like a?.foo() would
    // raise a linting error before
    'no-unused-expressions': 0,
    // I *think* that the typescript compiler catches unused variables, plus this complaints about
    // imported types
    'no-unused-vars': 0,
    'object-curly-spacing': ['error', 'always'],
    'prefer-destructuring': 0,
    quotes: 'off',
    semi: ['error', 'always'],
  },
};

full .prettierrc:

{
  "arrowParens": "always",
  "printWidth": 100,
  "trailingComma": "all",
  "tabWidth": 2,
  "singleQuote": true
}


from Max jsx props per line within a function parameter

React Transition CSS animation flickering

I need help in preventing my HTML from flickering. I have a component for fade-in-out animation which uses React Transition. Sometimes I see a flickering effect on Chrome. In Safari everything works well. I tried to add -webkit-backface-visibility: hidden; and some more solutions found in Google but everything led me to failure. Do you have any ideas?

Codepen

Video with the flickering effect.



from React Transition CSS animation flickering

Fitbit - timer - how to show current time on application

I'm trying to use my fitbit to help know how far into my gym I am more easily. Making this more simple so the solution is easier for people to help with.

I'm using a fitbit and some basic JS.

Using the clock API I can create a timer, but not trigger one with a button.

i.e., this does the job.

import clock from "clock";
import document from "document";
import { preferences } from "user-settings";
import * as util from "../common/utils";

import { display } from "display";

// Update the clock every minute
clock.granularity = "seconds";

// Get a handle on the <text> element
const ClockLabel = document.getElementById("timeLabel");
const Timer= document.getElementById("timerLabel");
const myButton = document.getElementById("button-1");
myButton.text = "button";

// Update the <text> element every tick with the current time
clock.ontick = (evt) => {
  var Timing = 4*60*60
   let today = evt.date;
  var diff = Timing - ((today - start)/1000 |0);
  let hours  = (diff / 3600) | 0;
  let minutes = ((diff - (hours*3600)) / 60) | 0;
  let seconds = diff - (hours * 3600) - (minutes * 60)| 0;

  console.log("hours:"+hours+", minutes:"+minutes+", seconds:"+seconds);


  let hours = today.getHours();
  let minutes = today.getMinutes();
  let seconds = today.getSeconds();
  if (preferences.clockDisplay === "12h") {
    // 12h format
    hours = hours % 12 || 12;
  } else {
    // 24h format
    hours = util.zeroPad(hours);
  }
  ClockLabel.text = `${hours}:${minutes}:${seconds}`;
}

However when firing from a button, it doesn't work whatsoever.

myButton.addEventListener("click", (evt) => {
  var start = Date.now()
//also this doesn't work let today = evt.date;

  myButton.text = "Started";
  
  
  var Timing = 4*60*60;
  var diff = Timing - ((Date.now() - start)/1000 |0);
  let hours  = (diff / 3600) | 0;
  let minutes = ((diff - (hours*3600)) / 60) | 0;
  let seconds = diff - (hours * 3600) - (minutes * 60)| 0;

  console.log("hours:"+hours+", minutes:"+minutes+", seconds:"+seconds);
    ClockLabel.text = `${hours}:${minutes}:${seconds}`;

});

This draws me to the conclusion that using this function is probably a better way forward.

function CountDownTimer(duration, granularity) {
  this.duration = duration;
  this.granularity = granularity || 1000;
  this.tickFtns = [];
  this.running = false;
}

CountDownTimer.prototype.start = function() {
  if (this.running) {
    return;
  }
  this.running = true;
  var start = Date.now(),
      that = this,
      diff, obj;

  (function timer() {
    diff = that.duration - (((Date.now() - start) / 1000) | 0);

    if (diff > 0) {
      setTimeout(timer, that.granularity);
    } else {
      diff = 0;
      that.running = false;
    }

    obj = CountDownTimer.parse(diff);
    that.tickFtns.forEach(function(ftn) {
      ftn.call(this, obj.minutes, obj.seconds);
    }, that);
  }());
};

CountDownTimer.prototype.onTick = function(ftn) {
  if (typeof ftn === 'function') {
    this.tickFtns.push(ftn);
  }
  return this;
};

CountDownTimer.prototype.expired = function() {
  return !this.running;
};

CountDownTimer.parse = function(seconds) {
  return {
      'hours': (seconds / 3600)|0,
    'minutes': (seconds / 60) | 0,
    'seconds': (seconds % 60) | 0
  };
};



export default CountDownTimer;


from Fitbit - timer - how to show current time on application

Django : bulk upload with confirmation

Yet another question about the style and the good practices. The code, that I will show, works and do the functionality. But I'd like to know is it ok as solution or may be it's just too ugly?

As the question is a little bit obscure, I will give some points at the end.

So, the use case.

I have a site with the items. There is a functionality to add the item by user. Now I'd like a functionality to add several items via a csv-file.

How should it works?

  1. User go to special upload page.
  2. User choose a csv-file, click upload.
  3. Then he is redirected to the page that show the content of csv-file (as a table).
  4. If it's ok for user, he clicks "yes" (button with "confirm_items_upload" value) and the items from file are added to database (if they are ok).

I saw already examples for bulk upload for django, and they seem pretty clear. But I don't find an example with an intermediary "verify-confirm" page. So how I did it :

  1. in views.py : view for upload csv-file page
def upload_item_csv_file(request):
    if request.method == 'POST':
        form = UploadItemCsvFileForm(request.POST, request.FILES)
        if form.is_valid():
            uploaded_file_name = handle_uploaded_item_csv_file(request.FILES['item_csv_file'])
            request.session['uploaded_file'] = uploaded_file_name
            return redirect('show_upload_csv_item')
    else:
        form = UploadItemCsvFileForm()
    return render(request, 'myapp/item_csv_upload.html', {'form': form})
  1. in utils.py : handle_uploaded_item_csv_file - just save the file and return a file-name
def handle_uploaded_item_csv_file(f):
    now = datetime.now()
    # YY_mm_dd_HH_MM
    dt_string = now.strftime("%Y_%m_%d_%H_%M")
    file_name = os.path.join(settings.MEDIA_ROOT, f"tmp_csv/item_csv_{dt_string}.csv")
    with open(file_name, 'wb+') as destination:
        for chunk in f.chunks():
            destination.write(chunk)

    return f"tmp_csv/item_csv_{dt_string}.csv"
  1. in views.py : view for show_upload_csv_item
@transaction.atomic
def show_uploaded_file(request):
    if 'uploaded_file' in request.session :
        file_name = request.session['uploaded_file']
    else :
        print("Something wrong : raise 404")
        raise Http404
    if not os.path.isfile(os.path.join(settings.MEDIA_ROOT, file_name)):
        print("Something wrong, file does not exist : raise 404")
        raise Http404

    with open(os.path.join(settings.MEDIA_ROOT, file_name)) as csvfile :
        fieldnames = ['serial_number', 'type', 'shipping_date', 'comments']
        csv_reader = csv.DictReader(csvfile, delimiter=';', fieldnames=fieldnames)
        list_items = list(csv_reader)

    if request.POST and ("confirm_items_upload" in request.POST) :
        if request.POST["confirm_items_upload"] == "yes" :
            for cur_item in list_items :
                if not cur_item['shipping_date'] :
                    cur_item.pop('shipping_date', None)

                try :
                    Item.objects.create(**cur_item)
                except IntegrityError :
                    messages.warning(request, f"This Item : {cur_item} - already exists. No items were added." )
            os.remove(os.path.join(settings.MEDIA_ROOT, file_name))
            return redirect('items')
    else :
        return render(request, 'myapp/item_csv_uploaded.html', {'items': list_items})
  1. In forms.py : the form is very obvious, but just to be clear
class UploadItemCsvFileForm(forms.Form):
    item_csv_file = forms.FileField()

Here are the questions/points.

a) Even if obviously it could be better, is this solution is acceptable or not at all ?

b) I pass 'uploaded_file' from one view to another using "request.session" is it a good practice? Is there another way to do it without using GET variables?

c) At first my wish was to avoid to save the csv-file. But I could not figure out how to do it? Reading all the file to request.session seems not a good idea for me. Is there some possibility to upload the file into memory in Django?

d) If I have to use the tmp-file. How should I handle the situation if user abandon upload at the middle (for example, he sees the confirmation page, but does not click "yes" and decide to re-write his file). How to remove the tmp-file?

e) Small additional question : what kind of checks there are in Django about uploaded file? For example, how could I check that the file is at least a text-file? Should I do it?

All others remarks are welcome as well.



from Django : bulk upload with confirmation