Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to drag and drop with vue-draggable/sortable.js #311

Closed
ghost opened this issue Feb 9, 2019 · 16 comments
Closed

Unable to drag and drop with vue-draggable/sortable.js #311

ghost opened this issue Feb 9, 2019 · 16 comments

Comments

@ghost
Copy link

ghost commented Feb 9, 2019

Specification

  • Platform: Windows 10
  • Versions:
    • pywebview 2.2.1
    • python 2.6.8

Description

I'm building a standalone application in a bit of a complicated way as it will be migrated eventually. It is working for the most part but I can't get draggable functionality to work in a pywebview window.

I'm using Flask with Vue.js, pywebview, then packaging with pyinstaller.
I'm building the vue.js frontend into static files and using pywebview to display the static content served by flask. It is then being put into a single executable with pyinstaller.

All of the functionality works except I am using vue-draggable that uses sortable.js and that functionality seems to be failing only in the pywebview window.

When I launch the executable, I can access the webserver that is run via local browsers and also from the pywebview window. Chrome 72, Edge 16 and IE 11 all work and allow draggable elements between lists, but the pywebview window does not allow it even though it is telling me it is running using IE 11.

web-client check script
navigator.sayswho= (function(){
    var ua= navigator.userAgent, tem,
    M= ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
    if(/trident/i.test(M[1])){
        tem=  /\brv[ :]+(\d+)/g.exec(ua) || [];
        return 'IE '+(tem[1] || '');
    }
    if(M[1]=== 'Chrome'){
        tem= ua.match(/\b(OPR|Edge)\/(\d+)/);
        if(tem!= null) return tem.slice(1).join(' ').replace('OPR', 'Opera');
    }
    M= M[2]? [M[1], M[2]]: [navigator.appName, navigator.appVersion, '-?'];
    if((tem= ua.match(/version\/(\d+)/i))!= null) M.splice(1, 1, tem[1]);
    return M.join(' ');
})();

console.log(navigator.sayswho);

Asks

Honestly I am unsure where to even begin looking to understand why the dragging isn't working. I have tried turning on text-select=True and debug=True, but neither seems to have helped with the dragging problem.

Is this a known issue or is there a quick fix? I saw the PR with CEF and thought that might be a possible option/fix if that comes out within the next few days, but if there is an immediate alternative, I would be grateful.

My current build command for pyinstaller is

pyinstaller --name="flasktest" --add-data="frontbuild\*;frontbuild" --add-data "C:\Users\<user>\AppData\Local\Programs\Python\Python36\Lib\site-packages\webview\lib\WebBrowserInterop.x64.dll;./" --onefile -y ./backend/srv.py

My current create.window command for pyinstaller is

webview.create_window(
                webview_name,
                "http://127.0.0.1:23948",
                width=width,
                height=height,
                text_select=True,
                debug=True
            )
@r0x0r
Copy link
Owner

r0x0r commented Feb 10, 2019

I made a possible fix to the drag-drop branch. Would you give it a try and see if it solves your problem?

@ghost
Copy link
Author

ghost commented Feb 11, 2019

installed with

pip install --upgrade git+https://github.com/r0x0r/pywebview.git@drag-drop

After a clean build, it didn't seem to fix the problem. Everything still works in IE11, Edge, and Chrome.

@r0x0r
Copy link
Owner

r0x0r commented Feb 11, 2019

I tested master against https://www.dropzonejs.com and drag & drop works just fine. The problem seems to be in your code.

@ghost
Copy link
Author

ghost commented Feb 11, 2019

Lets see if I can give you some better context on how I'm using drag and drop functionality:
I'm using vue.js with vue-draggable

import draggable from 'vuedraggable'

and displaying lists of items as:

<draggable style="min-height:100%" class="list-group dragArea" element="ul" v-model="currentFile.headers" :options="{group:{ name:'map'}}">
  <li class="list-group-item" v-for="(header, index) in currentFile.headers" :key="index">
    {{ header }}
  </li>
</draggable>

and dragging from there into:

<draggable style="min-height:40px;" class="list-group dragArea" element="ul" v- 
  model="label.association"
  :options="{group:{ name:'map', put: (to) => {
    return to.el.children.length < 1
  }}}">
  <li class="list-group-item" v-for="(association, index) in label.association" :key="index">
    {{ association }}
  </li>
</draggable>

I'm building it into static content with ``npm run build```

The code for the pywebview window is:

def run_server(self, webview_name="Tools", width=1024, height=720):

        app = self.build_app()
        def start_server():
            app.run(host='127.0.0.1', port=23948)

        if self.env == "dev":
            start_server()
        else: # run as daemon
            t = threading.Thread(target=start_server)
            t.daemon = True
            print("%% DAEMON START %%")
            t.start()

            webview.create_window(webview_name, "http://127.0.0.1:23948", width=width, height=height)

        sys.exit()

Then the pyinstaller command is:

pyinstaller --name="tools" --add-data="frontbuild\*;frontbuild" --add-data "buildfiles\WebBrowserInterop.x64.dll;./" --onefile --clean -y ./backend/srv.py

Is there anything else I should show you that might be specific to the build process and with pywebview? Should I be exposing some JS element with js_api?

@r0x0r
Copy link
Owner

r0x0r commented Feb 11, 2019

I could not reproduce the problem with https://david-desmaisons.github.io/draggable-example/ either.

@ghost
Copy link
Author

ghost commented Feb 11, 2019

Would it be possible for you to provide the code you used with vue-draggable that worked so I can compare and see what exactly might be causing my problem?

@r0x0r
Copy link
Owner

r0x0r commented Feb 11, 2019 via email

@ghost
Copy link
Author

ghost commented Feb 11, 2019

I pulled down the draggable-example code, built it and packaged it with the same commands I was using and it worked successfully. I will determine what I was doing wrong in my codebase and let you know what was causing the breakage.

@ghost
Copy link
Author

ghost commented Feb 13, 2019

@r0x0r All of the following was over many hours and lots of testing to narrow down exactly what was breaking.


I created a fresh vue-cli 3 project using vue create <project_name> and vue 3.4.0

I did a manual install and enabled Typescript, Router, and CSS Pre-Processors. I then selected ESLint + Airbnb config, lint on save, and in package.json, etc.... After these steps, the draggable code did not work.

I then proceeded to remove each of the manual package additions incrementally until it worked. After removing each manual thing and then finally resorting to a default package install, I was still not successful in getting the draggable function to work.

All these iterations worked within a browser at the same time as the executable was open (so the server was serving the same static files to both pywebview and ie/edge/chrome at the same time). This leads me to believe it is a problem with pywebview instead of posting in vue-draggable about the issue. Even when running pywebview in CLI without packaging, the draggable option still does not work.

I am working to determine what the vue-draggable team did differently in their example compared to a fresh installation of vue-cli that causes their version to build and work correctly.

As of right now I found out that if I do a fresh vue-cli, the example vue-draggable code AND THEN take their package-lock.json, it works with pywebview. This was really strange and I was dreading continuing seeing as I know how immense a package-lock file is....

I eventually have narrowed it down to a specific difference in packages in the package-lock.json (NOT the package.json)

"sortablejs": {
      "version": "1.8.1",
      "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.8.1.tgz",
      "integrity": "..."
    },

broke the functionality, but

"sortablejs": {
      "version": "1.7.0",
      "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.7.0.tgz",
      "integrity": "..."
    },

made it work.

Something in the change from 1.7 to 1.8.1 breaks pywebview in some way. Making this change in package-lock.json fixes everything!

Please let me know if I can help in any way to identify what changes caused pywebview from preventing the dragging and dropping functionality to stop between Sortable.js v1.7.0 to v1.8.1!

@r0x0r
Copy link
Owner

r0x0r commented Feb 14, 2019

This is quite a heroic effort at debugging this problem.

There was a problem with escaping strings when loading Javascript via evaluate_js, but since you are using a web server it should not matter here.

Have you got a chance to test it on a different platform (Mac or Linux)?
Also I just released a version 2.3 that supports CEF on Windows. If executable size is not an issue, you may give it a try.

@ghost
Copy link
Author

ghost commented Feb 14, 2019

Thanks! It was a problem that I seriously had to fix haha.

I have tested it on Linux (Ubuntu 16.04) and pywebview works. It seems it was something specific with ie11/trident on windows. I will try a rebuild with CEF on windows and see if the problem persists and let you know if it does or not. Honestly, my expectation is that CEF will fix the problems (and no I don't really care too much about the executable size considering my linux package ended up being approx 260mb lol).

So yeah, I'll test CEF with draggable on windows and let you know 👍 !

@ghost
Copy link
Author

ghost commented Feb 20, 2019

@r0x0r finally got to working with CEF on windows.

Seems that running it actively works, but once I package it with pyinstaller I get:

[0220/105055.933:ERROR:icu_util.cc(133)] Invalid file descriptor to ICU data received.

Do you know if there is anything else that I'm required to include in the build?


I also noticed that webview.gui = 'cef' doesn't work and I'm required to use the environment variable! Edit: worked with webview.config.gui = 'cef'

@ghost
Copy link
Author

ghost commented Feb 20, 2019

@r0x0r I have gotten a bit further.

It all seems to work using this file from cefpython3's repo: https://github.com/cztomczak/cefpython/blob/f94eaa6220fbd49ce9af1fa69d4984f8aa18bcef/examples/pyinstaller/hook-cefpython3.py

However, trying to package it into a single file executable seems to be a limitation of pywebview.

The building process is successful but I'm getting the following now:

[0220/123854.475:ERROR:main_delegate.cc(710)] Could not load locale pak for en-US
[0220/123854.475:ERROR:main_delegate.cc(717)] Could not load cef.pak
[0220/123854.475:ERROR:main_delegate.cc(734)] Could not load cef_100_percent.pak
[0220/123854.475:ERROR:main_delegate.cc(743)] Could not load cef_200_percent.pak
[0220/123854.475:ERROR:main_delegate.cc(753)] Could not load cef_extensions.pak
[0220/123854.488:ERROR:content_client.cc(272)] No data resource available for id 101
Segmentation fault

Which from my understanding has to do with providing the locales and other pak files properly in the path. Because it is being packaged, the only way we can go about this is with MEIPASS.

In webview/cef.py line 163 there is the cef initialization and I believe something as the following may need to be possibly specified on creation in order for it to package properly:

'resources_dir_path': sys._MEIPASS, 
'locales_dir_path': sys._MEIPASS + os.sep + 'locales',
'browser_subprocess_path': sys._MEIPASS + os.sep + 'subprocess.exe',

as per: https://groups.google.com/forum/#!topic/cefpython/4R22vCWIjk8

Would it be possible to provide an option to append to settings on line 157 from webview/cef.py during the webview.create_window process or before then as a config?

@r0x0r
Copy link
Owner

r0x0r commented Feb 21, 2019

@jakobroberts-kpmg I have not attempted to freeze a CEF app, so you know probably know more about this matter at this point

I would not like to introduce new options just for CEF, but rather write logic that would handle this edge case automatically. For example support for PyInstaller is baked in ´base_uri´ of util.py (line 24). Something like this could be done for CEF as well. Ie the code would look for sys._MEIPASS and if found would apply these settings.

@ghost
Copy link
Author

ghost commented Feb 25, 2019

@r0x0r After many hours of attempting the switch to CEF with pywebview I've given up and I'm sticking to ie11 and trident for the time being.... There are just too many factors from what I can see trying to make it into a single executable and I need it working for the interim.

I would be up for working together with you to bake in the logic though.

@r0x0r
Copy link
Owner

r0x0r commented Mar 11, 2019

I have added support for pyinstalle's one file mode to CEF. Changes are in master.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants