From 38ae99300d08eaf21a5cfb1a9977fcdb08446530 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B3=A0=EB=82=A8=ED=98=84?= Date: Tue, 20 Oct 2020 17:58:58 +0900 Subject: [PATCH] add support GTK server --- lib/dompath.js | 157 ++++++++++++++++++++++++++++++++++++++++++++++ lib/gtkserver.js | 112 +++++++++++++++++++++++++++++++++ lib/httpserver.js | 20 +++--- lib/oldbrowser.js | 4 +- 4 files changed, 284 insertions(+), 9 deletions(-) create mode 100644 lib/dompath.js create mode 100644 lib/gtkserver.js diff --git a/lib/dompath.js b/lib/dompath.js new file mode 100644 index 0000000..edc404f --- /dev/null +++ b/lib/dompath.js @@ -0,0 +1,157 @@ +// https://stackoverflow.com/a/58677712/3702603 + +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +Elements = {}; +Elements.DOMPath = {}; + +/** + * @param {!Node} node + * @param {boolean=} optimized + * @return {string} + */ +Elements.DOMPath.xPath = function (node, optimized) { + if (node.nodeType === Node.DOCUMENT_NODE) { + return '/'; + } + + const steps = []; + let contextNode = node; + while (contextNode) { + const step = Elements.DOMPath._xPathValue(contextNode, optimized); + if (!step) { + break; + } // Error - bail out early. + steps.push(step); + if (step.optimized) { + break; + } + contextNode = contextNode.parentNode; + } + + steps.reverse(); + return (steps.length && steps[0].optimized ? '' : '/') + steps.join('/'); +}; + +/** + * @param {!Node} node + * @param {boolean=} optimized + * @return {?Elements.DOMPath.Step} + */ +Elements.DOMPath._xPathValue = function (node, optimized) { + let ownValue; + const ownIndex = Elements.DOMPath._xPathIndex(node); + if (ownIndex === -1) { + return null; + } // Error. + + switch (node.nodeType) { + case Node.ELEMENT_NODE: + if (optimized && node.getAttribute('id')) { + return new Elements.DOMPath.Step('//*[@id="' + node.getAttribute('id') + '"]', true); + } + ownValue = node.localName; + break; + case Node.ATTRIBUTE_NODE: + ownValue = '@' + node.nodeName; + break; + case Node.TEXT_NODE: + case Node.CDATA_SECTION_NODE: + ownValue = 'text()'; + break; + case Node.PROCESSING_INSTRUCTION_NODE: + ownValue = 'processing-instruction()'; + break; + case Node.COMMENT_NODE: + ownValue = 'comment()'; + break; + case Node.DOCUMENT_NODE: + ownValue = ''; + break; + default: + ownValue = ''; + break; + } + + if (ownIndex > 0) { + ownValue += '[' + ownIndex + ']'; + } + + return new Elements.DOMPath.Step(ownValue, node.nodeType === Node.DOCUMENT_NODE); +}; + +/** + * @param {!Node} node + * @return {number} + */ +Elements.DOMPath._xPathIndex = function (node) { + // Returns -1 in case of error, 0 if no siblings matching the same expression, + // otherwise. + function areNodesSimilar(left, right) { + if (left === right) { + return true; + } + + if (left.nodeType === Node.ELEMENT_NODE && right.nodeType === Node.ELEMENT_NODE) { + return left.localName === right.localName; + } + + if (left.nodeType === right.nodeType) { + return true; + } + + // XPath treats CDATA as text nodes. + const leftType = left.nodeType === Node.CDATA_SECTION_NODE ? Node.TEXT_NODE : left.nodeType; + const rightType = right.nodeType === Node.CDATA_SECTION_NODE ? Node.TEXT_NODE : right.nodeType; + return leftType === rightType; + } + + const siblings = node.parentNode ? node.parentNode.children : null; + if (!siblings) { + return 0; + } // Root node - no siblings. + let hasSameNamedElements; + for (let i = 0; i < siblings.length; ++i) { + if (areNodesSimilar(node, siblings[i]) && siblings[i] !== node) { + hasSameNamedElements = true; + break; + } + } + if (!hasSameNamedElements) { + return 0; + } + let ownIndex = 1; // XPath indices start with 1. + for (let i = 0; i < siblings.length; ++i) { + if (areNodesSimilar(node, siblings[i])) { + if (siblings[i] === node) { + return ownIndex; + } + ++ownIndex; + } + } + return -1; // An error occurred: |node| not found in parent's children. +}; + +/** + * @unrestricted + */ +Elements.DOMPath.Step = class { + /** + * @param {string} value + * @param {boolean} optimized + */ + constructor(value, optimized) { + this.value = value; + this.optimized = optimized || false; + } + + /** + * @override + * @return {string} + */ + toString() { + return this.value; + } +}; diff --git a/lib/gtkserver.js b/lib/gtkserver.js new file mode 100644 index 0000000..023952d --- /dev/null +++ b/lib/gtkserver.js @@ -0,0 +1,112 @@ +//////////////////////////////////////////////////////////////////////// +// GTKServer API +//////////////////////////////////////////////////////////////////////// + +// Common (Elements) +var GTKElements = []; + +// Common (Element) +var GTKElement = function(elementType) { + this.Width = 0; + this.Height = 0; + + this.setWidth = function(width) { + this.Width = width; + }; + this.setHeight = function(height) { + this.Height = height; + }; + + this,onchange = function() {}; + this.onclick = function() {}; + this.onmouseover = function() {}; + this.onmouseout = function() {}; + this.onkeydown = function() {}; + this.onload = function() {}; + this.addEventListener = function(ev, fn) { + if (typeof(fn) == "function") { + this['on' + ev] = fn; + } else { + throw new TypeError("listener must be a function"); + } + }; + + GTKElements.push(this); +}; + +// Window +var Window = function() { + GTKElement.apply(this, arguments); + + this.Title = "WelsonJS GTK GUI Application"; + this.setTitle = function(title) { + this.Title = title; + }; +}; +Window.prototype = new GTKElement(); +Window.prototype.constructor = Window; + +// Table +var Table = function() { + GTKElement.apply(this, arguments); + this.attach = function(element, left, right, top, buttom) { + // TODO: Table.Attach() + }; +}; +Table.prototype = new GTKElement(); +Table.prototype.constructor = Table; + +// Button +var Button = function() { + GTKElement.apply(this, arguments); + this.Text = "Button"; + this.setText = function(text) { + this.Text = text; + }; + +}; +Button.prototype = new GTKElement(); +Button.prototype.constructor = Button; + +// Label +var Label = function() { + GTKElement.apply(this, arguments); + this.Text = "Label"; + this.setText = function(text) { + this.Text = text; + }; +}; +Label.prototype = new GTKElement(); +Label.prototype.constructor = Label; + +// RadioBox +var RadioBox = function() { + GTKElement.apply(this, arguments); + this.Text = "RadioBox"; + this.setText = function(text) { + this.Text = text; + }; +}; +RadioBox.prototype = new GTKElement(); +RadioBox.prototype.constructor = RadioBox; + +// CheckBox +var CheckBox = function() { + GTKElement.apply(this, arguments); + this.Text = "CheckBox"; + this.setText = function(text) { + this.Text = text; + }; +}; +CheckBox.prototype = new GTKElement(); +CheckBox.prototype.constructor = CheckBox; + +// TextBox +var TextBox = function() { + this.Text = "TextBox"; + this.setText = function(text) { + this.Text = text; + }; +}; +TextBox.prototype = new GTKElement(); +TextBox.prototype.constructor = TextBox; diff --git a/lib/httpserver.js b/lib/httpserver.js index 8aa1e64..64314d5 100644 --- a/lib/httpserver.js +++ b/lib/httpserver.js @@ -1,7 +1,6 @@ //////////////////////////////////////////////////////////////////////// // HTTPServer API /////////////////////////////////////////////////////////////////////// - var HTTPServer = { _this: this, // Avoid conflicts between HTTPServer and Winsock variables @@ -24,24 +23,31 @@ var HTTPServer = { Connections: {}, + CreateWinsockObject: function() { + return CreateObject([ + "MSWinsock.Winsock.1", + "MSWinsock.Winsock" + ], "listener_"); + }, + Bind: function(port) { try { - _this.Listener = CreateObject(["MSWinsock.Winsock.1", "MSWinsock.Winsock"], "listener_"); + _this.Listener = _this.CreateWinsockObject(); _this.Listener.localPort = port; _this.Listener.bind(); _this.Listener.listen(); console.info("Listening port: " + port); - } catch(e) { + } catch (e) { console.error("port " + port " could not bind: " + e.message); } }, - OnRequest : function(request, response) { + OnRequest: function(request, response) { console.log("HTTPServer.OnRequest() dose not implemented"); }, CreateServer: function(OnRequest) { - if(typeof OnRequest !== "function") { + if (typeof OnRequest !== "function") { throw new TypeError("OnRequest() must be a function."); } _this.OnRequest = OnRequest; @@ -53,11 +59,11 @@ var HTTPServer = { console.info("Connection request " + requestID); _this.Connections[requestID] = { - Listener: CreateObject(["MSWinsock.Winsock.1", "MSWinsock.Winsock"], "listener_"); + Listener: _this.CreateWinsockObject() }; _this.Connections[requestID].Listener.accept(requestID); }, - + DataArrival: function(length) { // TODO: DataArrival }, diff --git a/lib/oldbrowser.js b/lib/oldbrowser.js index 273623a..5579dd7 100644 --- a/lib/oldbrowser.js +++ b/lib/oldbrowser.js @@ -10,7 +10,7 @@ exports.require = global.require; // only less than IE 9 //////////////////////////////////////////////////////////////////////// if (!window.addEventListener) { - Element = function() {}; + global.Element = function() {}; (function(WindowPrototype, DocumentPrototype, ElementPrototype, registry) { if (!DocumentPrototype.head) { @@ -111,7 +111,7 @@ if (!window.addEventListener) { element[key] = ElementPrototype[key]; return element; } - })(window, document, Element.prototype, []); + })(window, document, global.Element.prototype, []); } ////////////////////////////////////////////////////////////////////////