Forum Archive

Edit

[deleted]

Here my EditView class project. A JavaScript based WYSIWYG editor hosted in a web view.

  • it can receive from a subclass (eg the supplied MyEditView example) a dict of existing images for the document
  • new images can be added to the document via the editor and these are persisted to the dict

Edit.py is designed to live in the site-packages folder.

It's necessary to install the CKEditor JavaScript package.... it's what replaces the little edit square with the full editor...

  • you want a 'Full' download ... http://ckeditor.com/download
  • unzipped into your scripts folder... to 'ckeditor' folder (all lower case)
  • If you want the editor buttons and image dialog configured as I have them I can post the config file

There is a tool posted below in the thread that will let you check the CKEditor installation and run many of the samples.


image (c) @tony .... (for more classes in this family see... Classes )


image (c) @tony

Edit.py

import ui, os, io, photos, console, SocketServer
from SimpleHTTPServer import SimpleHTTPRequestHandler
from PIL import Image as ImageP

class EditView (ui.View):
    def __init__(self):
        self.__make_self()
        self.__make_wv()
        self.did_load()
        self.layout()
        self.present('panel')
        self.__server.serve_forever()

    def did_load(self):
        pass

    def layout(self):
        self.__wv.frame = (0, 0, self.width, self.height)
        self.__wv.evaluate_javascript('CKEDITOR.instances.editor1.resize(%s, %s);' % (self.__wv.frame[2] - self.margin_w, self.__wv.frame[3] - self.margin_h))

    def set_data(self, data):
        self.__wv.evaluate_javascript("CKEDITOR.instances.editor1.setData('" + data + "')")

    def get_data(self): 
        return self.__wv.evaluate_javascript("CKEDITOR.instances.editor1.document.getBody().getHtml()")

    def keyboard_frame_will_change(self, frame):
        self.__wv.evaluate_javascript('CKEDITOR.instances.editor1.resize(%s, %s); setTimeout(function(){window.scrollTo(0,0)},1);' % (self.__wv.frame[2] - self.margin_w, self.__wv.frame[3] - (10 if frame[3] > 0 else self.margin_h) - frame[3]))

    def __make_self(self):
        self.EditView_version = '4.0'
        self.EditView_source = 'Original by @tony.'
        self.EditView_permissions = 'Permission to use/subclass/redistribute, but NOT to modify code.'
        self.name = 'Edit'
        os.chdir(os.path.expanduser('~/Documents'))
        self.__server = SocketServer.TCPServer(("", 0), EditRequestHandler)
        self.margin_w = 10
        self.margin_h = 10
        global _gdI
        _gdI = getattr(self, 'document_images', None)

    def __make_wv(self):
        self.__wv = ui.WebView()
        self.__wv.load_url('http://localhost:' + str(self.__server.server_address[1]) + '/dummy.html')
        self.__wv.scales_page_to_fit = False
        self.__wv.delegate = self.__wvDelegate()
        self.add_subview(self.__wv)

    class __wvDelegate (object):
        def webview_did_finish_load(self, webview):
            webview.superview.layout()

    def will_close(self):
        self.__server.shutdown()
        console.hide_output()

class EditRequestHandler(SimpleHTTPRequestHandler):
    def __init__(self, request, client_address, server):
        self.__make_self()
        SimpleHTTPRequestHandler.__init__(self, request, client_address, server)

    def __make_self(self):
        self.EditRequestHandler_version = '4.0'
        self.EditRequestHandler_source_code = 'Original by @tony.'
        self.EditRequestHandler_permissions = 'Permission to use/subclass/redistribute, but NOT to modify code.'

    def do_GET(self):
        if os.path.splitext(self.path)[1] == '.html':
            self.send_response(200)
            self.send_header("Content-type", 'text/html')
            self.send_header("Last-Modified", self.date_time_string())
            self.end_headers()
            self.wfile.write('<!DOCTYPE html><html><head><meta charset="utf-8"><script src="../ckeditor/ckeditor.js"></script></head><body><textarea cols="1" id="editor1" name="editor1" rows="1"></textarea><script>CKEDITOR.replace("editor1",{on: {}});</script></body></html>')
        elif os.path.splitext(self.path)[1] == '.jpg':
            try:
                bI = _gdI[self.path[1:]]
            except:
                with io.BytesIO() as bIO:
                    ip = photos.pick_image(show_albums = True)
                    ip.save(bIO, ip.format)
                    bI = bIO.getvalue()
                    _gdI[self.path[1:]] = bI
            self.send_response(200)
            self.send_header("Content-type", 'image/jpeg')
            self.send_header("Content-Length", str(len(bI)))
            self.send_header("Last-Modified", self.date_time_string())
            self.end_headers()
            self.wfile.write(bI)
        else:
            SimpleHTTPRequestHandler.do_GET(self)

    def log_message(self, format, *args):
        pass

class Documents (object):
    def __init__(self):
        self.__make_self()

    def __make_self(self):
        self.Documents_version = '4.0 cut down and bundled with example'
        self.Documents_source_code = 'Original by @tony.'
        self.Documents = 'Permission to use/subclass/redistribute, but NOT to modify code.'
        self.document_images = dict()

    def document_read(self):
        sC = 'This<img src = "image1.jpg"> is the <b><i>document</i></b> with multiple images and added images persisted...<br><br><img src = "image2.jpg"> <br>End'
        with io.BytesIO() as bIO:
            ip = ImageP.open('Smiling_1')
            ip.save(bIO, ip.format)
            self.document_images['image1.jpg'] = bIO.getvalue()
        with io.BytesIO() as bIO:
            ip = ImageP.open('Test_Sailboat')
            ip.save(bIO, ip.format)
            self.document_images['image2.jpg'] = bIO.getvalue()
        return sC

class MyEditView (Documents, EditView):
    def __init__(self):
        Documents.__init__(self)
        EditView.__init__(self)

    def did_load(self):
        self.__make_self()

    def layout(self):
        self.margin_h = 40
        self.__bO.frame = (30, self.height - 30, 32, 32)
        super(MyEditView, self).layout()

    def __make_self(self):
        self.__make_bO()

    def __make_bO(self):
        self.__bO = ui.Button()
        self.__bO.image = ui.Image.named('ionicons-ios7-folder-outline-32')
        self.__bO.action = self.__bOA
        self.add_subview(self.__bO)

    def __bOA(self, sender):
        self.set_data(self.document_read())

if __name__ == "__main__":
    MyEditView()

Version 4.0: re Documents 4.0 and also added multiple inheritance example

Version 3.1: added dict of images

[deleted]

Created the base EditView class, and it's request handler, and uploaded code.

techteej

This is what I get when running.

alt text

[deleted]

@techteej I'm guessing you haven't installed the CKEditor JavaScript package.... It's what replaces the little edit square with the full editor [see above]

JonB

FYI, it actually is not necessary to run a web server instance in order to feed your webview instance.
It is not well documented, iirc, but you can use a file name in loadurl, as long as you specify a full path.

E.g. See line 43 here

w.load_url(os.path.abspath(srcname))

[deleted]

If you have (or put) my WebBrowser class in site-packages, you can use this tool to verify your CKEditor installation and run many of the extensive samples....

Samples.py

import SocketServer, os
from SimpleHTTPServer import SimpleHTTPRequestHandler
from WebBrowser import WebBrowser

class ViewHandler(SimpleHTTPRequestHandler):
    def log_message(self, format, *args):
        pass 

if __name__ == "__main__":
    os.chdir(os.path.expanduser('~/Documents/ckeditor/'))
    wb = WebBrowser()
    wb.server = SocketServer.TCPServer(("", 0), ViewHandler)
    wb.open('http://localhost:' + str(wb.server.server_address[1]) + '/samples/')
    wb.server.serve_forever()
[deleted]

@JonB Yes, I knew*, but...

  • unless I'm mistaken, that would make it into a multi-file project (all my classes are single file as a design goal)
  • the server has a vital role... in supplying existing and new images to the editor (images that are not in the file system and have no need to touch it... consider for example if you had a Word file containing images and wanted to use EditView to edit it... the images in memory and their names would be loaded into a dict and then supplied to the server via the class).

When I post the next version with a dict of images I'll try to include a simple subclass example to illustrate (but you can test it now by setting the optional attributes for a single image, or by picking a new image to insert via the editor.)

*the snippet that I have is from Kenbo01.

[deleted]

Updated the code with a MyEditView (single image, for now) example subclass.

[deleted]

Updated the code to v3.1 that:

  • adds support for multiple images in the document being edited
  • persists new images added to the document via the editor
TutorialDoctor

How do you install CK Editor?
I'm not a pro. The setup isn't simple enough.

wradcliffe

Can you post your config file for the layout you show in the original post?