Added the HTML5 to JavaScript converter.

Wed, 31 Dec 2014 20:38:35 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Wed, 31 Dec 2014 20:38:35 +0100
changeset 3
e478a359e1fb
parent 2
917f93fc61dd
child 4
6438afaad632

Added the HTML5 to JavaScript converter.

PluginProjectWeb.py file | annotate | diff | comparison | revisions
PluginWeb.e4p file | annotate | diff | comparison | revisions
ProjectWeb/Html5ToCss3Converter.py file | annotate | diff | comparison | revisions
ProjectWeb/Html5ToJsConverter.py file | annotate | diff | comparison | revisions
ProjectWeb/Html5ToJsConverterParameterDialog.py file | annotate | diff | comparison | revisions
ProjectWeb/Html5ToJsConverterParameterDialog.ui file | annotate | diff | comparison | revisions
--- a/PluginProjectWeb.py	Wed Dec 31 19:16:39 2014 +0100
+++ b/PluginProjectWeb.py	Wed Dec 31 20:38:35 2014 +0100
@@ -178,6 +178,8 @@
         # TODO: add our actions here
         self.__html5ToCss3Act = self.__menu.addAction(self.tr(
             "HTML5 to CSS3"), self.__htm5ToCss3)
+        self.__html5ToJsAct = self.__menu.addAction(self.tr(
+            "HTML5 to JavaScript"), self.__htm5ToJs)
         
         self.__menu.aboutToShow.connect(self.__menuAboutToShow)
     
@@ -190,6 +192,8 @@
         
         self.__html5ToCss3Act.setEnabled(
             selectionAvailable and BeautifulSoupAvailable)
+        self.__html5ToJsAct.setEnabled(
+            selectionAvailable and BeautifulSoupAvailable)
     
     def __populateMenu(self, name, menu):
         """
@@ -254,7 +258,6 @@
         """
         Private slot handling the HTML5 to CSS3 conversion.
         """
-        # TODO: implement this
         from ProjectWeb.Html5ToCss3Converter import Html5ToCss3Converter
         vm = e5App().getObject("ViewManager")
         editor = vm.activeWindow()
@@ -269,3 +272,22 @@
             newEditor = vm.activeWindow()
             newEditor.setText(css3)
             newEditor.setLanguage("dummy.css")
+    
+    def __htm5ToJs(self):
+        """
+        Private slot handling the HTML5 to JavaScript conversion.
+        """
+        from ProjectWeb.Html5ToJsConverter import Html5ToJsConverter
+        vm = e5App().getObject("ViewManager")
+        editor = vm.activeWindow()
+        html = editor.selectedText()
+        
+        converter = Html5ToJsConverter(html)
+        
+        js = converter.getJavaScript()
+        
+        if js:
+            vm.newEditor()
+            newEditor = vm.activeWindow()
+            newEditor.setText(js)
+            newEditor.setLanguage("dummy.js")
--- a/PluginWeb.e4p	Wed Dec 31 19:16:39 2014 +0100
+++ b/PluginWeb.e4p	Wed Dec 31 20:38:35 2014 +0100
@@ -19,14 +19,18 @@
     <Source>PluginProjectWeb.py</Source>
     <Source>ProjectWeb/Html5ToCss3Converter.py</Source>
     <Source>ProjectWeb/Html5ToCss3ConverterParameterDialog.py</Source>
+    <Source>ProjectWeb/Html5ToJsConverter.py</Source>
+    <Source>ProjectWeb/Html5ToJsConverterParameterDialog.py</Source>
   </Sources>
   <Forms>
     <Form>ProjectWeb/Html5ToCss3ConverterParameterDialog.ui</Form>
+    <Form>ProjectWeb/Html5ToJsConverterParameterDialog.ui</Form>
   </Forms>
   <Translations/>
   <Resources/>
   <Interfaces>
     <Interface>ProjectWeb/Ui_Html5ToCss3ConverterParameterDialog.py</Interface>
+    <Interface>ProjectWeb/Ui_Html5ToJsConverterParameterDialog.py</Interface>
   </Interfaces>
   <Others>
     <Other>.hgignore</Other>
--- a/ProjectWeb/Html5ToCss3Converter.py	Wed Dec 31 19:16:39 2014 +0100
+++ b/ProjectWeb/Html5ToCss3Converter.py	Wed Dec 31 20:38:35 2014 +0100
@@ -31,10 +31,10 @@
                     'font:inherit', 'vertical-align:baseline', 'line-height:1',
                     'outline:0', 'font-weight:inherit', 'font-style:inherit',
                     'font-family:inherit', 'vertical-align:baseline')
-    CssToIgnore = ('head', 'meta', 'noscript', 'script', 'style', 'link',
-                   'no-js', 'title', 'object', 'col', 'colgroup', 'option',
-                   'param', 'audio', 'basefont', 'isindex', 'svg', 'area',
-                   'embed', 'br')
+    TagsToIgnore = ('head', 'meta', 'noscript', 'script', 'style', 'link',
+                    'no-js', 'title', 'object', 'col', 'colgroup', 'option',
+                    'param', 'audio', 'basefont', 'isindex', 'svg', 'area',
+                    'embed', 'br')
     
     def __init__(self, html, parent=None):
         """
@@ -60,7 +60,7 @@
             # TODO: implement this
             self.__createSoup()
             
-            alreadyDone = list(self.CssToIgnore)
+            alreadyDone = list(self.TagsToIgnore)
             
             css = '@charset "utf-8";{0}'.format(os.linesep)
             css += "/* {0} by {1}*/{2}".format(
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ProjectWeb/Html5ToJsConverter.py	Wed Dec 31 20:38:35 2014 +0100
@@ -0,0 +1,152 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2014 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the HTML5 to JavaScript converter.
+"""
+
+from __future__ import unicode_literals
+
+import os
+import re
+import datetime
+import getpass
+
+from PyQt5.QtCore import QObject
+from PyQt5.QtWidgets import QDialog
+
+from .Html5ToJsConverterParameterDialog import \
+    Html5ToJsConverterParameterDialog
+
+
+class Html5ToJsConverter(QObject):
+    """
+    Class implementing the HTML5 to JavaScript converter.
+    """
+    JsTemplate8 = "{0}{1}{2}{3}{4}{5}{6}{7}"
+    TagsToIgnore = ('head', 'meta', 'noscript', 'script', 'style', 'link',
+                    'no-js', 'title', 'object', 'col', 'colgroup', 'option',
+                    'param', 'audio', 'basefont', 'isindex', 'svg', 'area',
+                    'embed', 'br')
+    
+    def __init__(self, html, parent=None):
+        """
+        Constructor
+        
+        @param html HTML text to be converted (string)
+        @param parent reference to the parent object (QObject)
+        """
+        super(Html5ToJsConverter, self).__init__(parent)
+        
+        self.__html = html
+    
+    def getJavaScript(self):
+        """
+        Public method to get the converted JavaScript text.
+        
+        @return JavaScript text (string)
+        """
+        dlg = Html5ToJsConverterParameterDialog()
+        if dlg.exec_() == QDialog.Accepted:
+            indentation, scriptTags = dlg.getData()
+            
+            self.__createSoup()
+            
+            alreadyDone = list(self.TagsToIgnore)
+            
+            js = "<script>{0}".format(os.linesep) if scriptTags else ""
+            js += "// {0} by {1}{2}".format(
+                datetime.datetime.now().isoformat().split(".")[0],
+                getpass.getuser(),
+                os.linesep
+            )
+            js += "$(document).ready(function(){" + os.linesep
+            
+            # step 1: IDs
+            js += "/*{0}*/{1}".format(
+                "-" * 75,
+                os.linesep
+            )
+            for id_ in self.__getIds():
+                if id_ not in alreadyDone:
+                    js += "{0}// {1}{2}".format(
+                        indentation,
+                        "#".join(id_).lower(),
+                        os.linesep
+                    )
+                    js += self.JsTemplate8.format(
+                        indentation,
+                        "var ",
+                        re.sub("[^a-z0-9]", "",
+                               id_[1].lower() if len(id_[1]) < 11 else
+                               re.sub("[aeiou]", "", id_[1].lower())),
+                        " = ",
+                        '$("#{0}").length'.format(id_[1]),
+                        ";",
+                        os.linesep,
+                        os.linesep
+                    )
+                    alreadyDone.append(id_)
+            
+            # step 2: classes
+            js += "/*{0}*/{1}".format(
+                "-" * 75,
+                os.linesep
+            )
+            for class_ in self.__getClasses():
+                if class_ not in alreadyDone:
+                    js += "{0}// {1}{2}".format(
+                        indentation,
+                        ".".join(class_).lower(),
+                        os.linesep
+                    )
+                    js += self.JsTemplate8.format(
+                        indentation,
+                        "var ",
+                        re.sub("[^a-z0-9]", "",
+                               class_[1].lower() if len(class_[1]) < 11 else
+                               re.sub("[aeiou]", "", class_[1].lower())),
+                        " = ",
+                        '$(".{0}").length'.format(class_[1]),
+                        ";",
+                        os.linesep,
+                        os.linesep
+                    )
+                    alreadyDone.append(class_)
+            
+            js += "})"
+            js += "{0}</script>".format(os.linesep) if scriptTags else ""
+        else:
+            js = ""
+        return js.strip()
+    
+    def __createSoup(self):
+        """
+        Private method to get a BeaitifulSoup object with our HTML text.
+        """
+        from bs4 import BeautifulSoup
+        self.__soup = BeautifulSoup(BeautifulSoup(self.__html).prettify())
+    
+    def __getClasses(self):
+        """
+        Private method to extract all classes of the HTML text.
+        
+        @return list of tuples containing the tag name and its classes
+            as a blank separated string (list of tuples of two strings)
+        """
+        classes = [(t.name, " ".join(t["class"])) for t in
+                   self.__soup.find_all(True, {"class": True})]
+        return sorted(list(set(classes)))
+    
+    def __getIds(self):
+        """
+        Private method to extract all IDs of the HTML text.
+        
+        @return list of tuples containing the tag name and its ID
+            (list of tuples of two strings)
+        """
+        ids = [(t.name, t["id"]) for t in
+               self.__soup.find_all(True, {"id": True})]
+        return sorted(list(set(ids)))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ProjectWeb/Html5ToJsConverterParameterDialog.py	Wed Dec 31 20:38:35 2014 +0100
@@ -0,0 +1,41 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2014 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a dialog to enter the JavaScript conversion parameters.
+"""
+
+from PyQt5.QtWidgets import QDialog
+
+from .Ui_Html5ToJsConverterParameterDialog import \
+    Ui_Html5ToJsConverterParameterDialog
+
+
+class Html5ToJsConverterParameterDialog(
+        QDialog, Ui_Html5ToJsConverterParameterDialog):
+    """
+    Class implementing a dialog to enter the JavaScript conversion parameters.
+    """
+    def __init__(self, parent=None):
+        """
+        Constructor
+        
+        @param parent reference to the parent widget (QWidget)
+        """
+        super(Html5ToJsConverterParameterDialog, self).__init__(parent)
+        self.setupUi(self)
+        
+        msh = self.minimumSizeHint()
+        self.resize(max(self.width(), msh.width()), msh.height())
+    
+    def getData(self):
+        """
+        Public method to get the entered data.
+        
+        @return tuple of indentation string (string) and a flag indicating to
+            enclose the code by 'script' tags (boolean)
+        """
+        return (" " * self.indentationSpinBox.value(),
+                self.scriptCheckBox.isChecked())
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ProjectWeb/Html5ToJsConverterParameterDialog.ui	Wed Dec 31 20:38:35 2014 +0100
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Html5ToJsConverterParameterDialog</class>
+ <widget class="QDialog" name="Html5ToJsConverterParameterDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>317</width>
+    <height>102</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Conversion Parameters</string>
+  </property>
+  <property name="sizeGripEnabled">
+   <bool>true</bool>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="0">
+    <widget class="QLabel" name="label">
+     <property name="text">
+      <string>JS Indentation Spaces:</string>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="1">
+    <widget class="QSpinBox" name="indentationSpinBox">
+     <property name="toolTip">
+      <string>Enter the amount of spaces to be used as indentation</string>
+     </property>
+     <property name="minimum">
+      <number>2</number>
+     </property>
+     <property name="maximum">
+      <number>8</number>
+     </property>
+     <property name="singleStep">
+      <number>2</number>
+     </property>
+     <property name="value">
+      <number>4</number>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="2">
+    <spacer name="horizontalSpacer">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>220</width>
+       <height>20</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="2" column="0" colspan="3">
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="0" colspan="3">
+    <widget class="QCheckBox" name="scriptCheckBox">
+     <property name="toolTip">
+      <string>Select to enclose the generated JavaScript code by 'script' tags</string>
+     </property>
+     <property name="text">
+      <string>Enclose by 'script' HTML tags</string>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>Html5ToJsConverterParameterDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>Html5ToJsConverterParameterDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>

eric ide

mercurial