diff --git a/.gitignore b/.gitignore new file mode 100755 index 000000000..76040ef8f --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.DS_Store +*node_modules/ +*dist/ \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..72f5433d2 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // 使用 IntelliSense 了解相关属性。 + // 悬停以查看现有属性的描述。 + // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + + { + "type": "node", + "request": "launch" + } + ] +} diff --git a/webGL/001/001.html b/webGL/001/001.html new file mode 100644 index 000000000..4215b414b --- /dev/null +++ b/webGL/001/001.html @@ -0,0 +1,16 @@ + + + + + Basic JavaScript module example + + + + + + + \ No newline at end of file diff --git a/webGL/001/001.js b/webGL/001/001.js new file mode 100644 index 000000000..2b7e0c20f --- /dev/null +++ b/webGL/001/001.js @@ -0,0 +1,18 @@ +// 从这里开始 +class main { + constructor(id){ + this.canvas = document.querySelector(id) + this.gl = gl = canvas.getContext("webgl"); + } + render(){ + if (!this.gl) { + throw new Error("无法初始化WebGL,你的浏览器、操作系统或硬件等可能不支持WebGL。"); + } + // 使用完全不透明的黑色清除所有图像 + this.gl.clearColor(0.0, 0.0, 0.0, 1.0); + // 用上面指定的颜色清除缓冲区 + this.gl.clear(gl.COLOR_BUFFER_BIT); + } +} + +module.exports = main; \ No newline at end of file diff --git a/webGL/001/main.mjs b/webGL/001/main.mjs new file mode 100644 index 000000000..4a821a3e2 --- /dev/null +++ b/webGL/001/main.mjs @@ -0,0 +1,13 @@ +import { create, createReportList } from './modules/canvas.js'; +import { name, draw, reportArea, reportPerimeter } from './modules/square.js'; +import randomSquare from './modules/square.js'; + +let myCanvas = create('myCanvas', document.body, 480, 320); +let reportList = createReportList(myCanvas.id); + +let square1 = draw(myCanvas.ctx, 50, 50, 100, 'blue'); +reportArea(square1.length, reportList); +reportPerimeter(square1.length, reportList); + +// Use the default +let square2 = randomSquare(myCanvas.ctx); \ No newline at end of file diff --git a/webGL/001/modules/canvas.js b/webGL/001/modules/canvas.js new file mode 100644 index 000000000..6164cf86e --- /dev/null +++ b/webGL/001/modules/canvas.js @@ -0,0 +1,29 @@ +function create(id, parent, width, height) { + let divWrapper = document.createElement('div'); + let canvasElem = document.createElement('canvas'); + parent.appendChild(divWrapper); + divWrapper.appendChild(canvasElem); + + divWrapper.id = id; + canvasElem.width = width; + canvasElem.height = height; + + let ctx = canvasElem.getContext('2d'); + + return { + ctx: ctx, + id: id + }; + } + + function createReportList(wrapperId) { + let list = document.createElement('ul'); + list.id = wrapperId + '-reporter'; + + let canvasWrapper = document.getElementById(wrapperId); + canvasWrapper.appendChild(list); + + return list.id; + } + + export { create, createReportList }; \ No newline at end of file diff --git a/webGL/001/modules/square.js b/webGL/001/modules/square.js new file mode 100644 index 000000000..d10885fc4 --- /dev/null +++ b/webGL/001/modules/square.js @@ -0,0 +1,57 @@ +const name = 'square'; + +function draw(ctx, length, x, y, color) { + ctx.fillStyle = color; + ctx.fillRect(x, y, length, length); + + return { + length: length, + x: x, + y: y, + color: color + }; +} + +function random(min, max) { + let num = Math.floor(Math.random() * (max - min)) + min; + return num; +} + +function reportArea(length, listId) { + let listItem = document.createElement('li'); + listItem.textContent = `${name} area is ${length * length}px squared.` + + let list = document.getElementById(listId); + list.appendChild(listItem); +} + +function reportPerimeter(length, listId) { + let listItem = document.createElement('li'); + listItem.textContent = `${name} perimeter is ${length * 4}px.` + + let list = document.getElementById(listId); + list.appendChild(listItem); +} + +function randomSquare(ctx) { + let color1 = random(0, 255); + let color2 = random(0, 255); + let color3 = random(0, 255); + let color = `rgb(${color1},${color2},${color3})` + ctx.fillStyle = color; + + let x = random(0, 480); + let y = random(0, 320); + let length = random(10, 100); + ctx.fillRect(x, y, length, length); + + return { + length: length, + x: x, + y: y, + color: color + }; +} + +export { name, draw, reportArea, reportPerimeter }; +export default randomSquare; \ No newline at end of file diff --git a/webGL/002/1.js b/webGL/002/1.js new file mode 100644 index 000000000..29cbdd8d3 --- /dev/null +++ b/webGL/002/1.js @@ -0,0 +1,27 @@ +var name = 'World!'; +(function () { +if (typeof name === 'undefined') { + var name = 'Jack'; + console.log('Goodbye ' + name); +} else { + console.log('Hello ' + name); +} +})(); +var str = 'World!'; +(function (name) { +if (typeof name === 'undefined') { + var name = 'Jack'; + console.log('Goodbye ' + name); +} else { + console.log('Hello ' + name); +} +})(str) + + +var END = Math.pow(2, 53); +var START = END - 100; +var count = 0; +for (var i = START; i <= END; i++) { + count++; +} +console.log(count); diff --git a/webGL/002/fastclick.js b/webGL/002/fastclick.js new file mode 100644 index 000000000..fe117b41a --- /dev/null +++ b/webGL/002/fastclick.js @@ -0,0 +1,841 @@ +;(function () { + 'use strict'; + + /** + * @preserve FastClick: polyfill to remove click delays on browsers with touch UIs. + * + * @codingstandard ftlabs-jsv2 + * @copyright The Financial Times Limited [All Rights Reserved] + * @license MIT License (see LICENSE.txt) + */ + + /*jslint browser:true, node:true*/ + /*global define, Event, Node*/ + + + /** + * Instantiate fast-clicking listeners on the specified layer. + * + * @constructor + * @param {Element} layer The layer to listen on + * @param {Object} [options={}] The options to override the defaults + */ + function FastClick(layer, options) { + var oldOnClick; + + options = options || {}; + + /** + * Whether a click is currently being tracked. + * + * @type boolean + */ + this.trackingClick = false; + + + /** + * Timestamp for when click tracking started. + * + * @type number + */ + this.trackingClickStart = 0; + + + /** + * The element being tracked for a click. + * + * @type EventTarget + */ + this.targetElement = null; + + + /** + * X-coordinate of touch start event. + * + * @type number + */ + this.touchStartX = 0; + + + /** + * Y-coordinate of touch start event. + * + * @type number + */ + this.touchStartY = 0; + + + /** + * ID of the last touch, retrieved from Touch.identifier. + * + * @type number + */ + this.lastTouchIdentifier = 0; + + + /** + * Touchmove boundary, beyond which a click will be cancelled. + * + * @type number + */ + this.touchBoundary = options.touchBoundary || 10; + + + /** + * The FastClick layer. + * + * @type Element + */ + this.layer = layer; + + /** + * The minimum time between tap(touchstart and touchend) events + * + * @type number + */ + this.tapDelay = options.tapDelay || 200; + + /** + * The maximum time for a tap + * + * @type number + */ + this.tapTimeout = options.tapTimeout || 700; + + if (FastClick.notNeeded(layer)) { + return; + } + + // Some old versions of Android don't have Function.prototype.bind + function bind(method, context) { + return function() { return method.apply(context, arguments); }; + } + + + var methods = ['onMouse', 'onClick', 'onTouchStart', 'onTouchMove', 'onTouchEnd', 'onTouchCancel']; + var context = this; + for (var i = 0, l = methods.length; i < l; i++) { + context[methods[i]] = bind(context[methods[i]], context); + } + + // Set up event handlers as required + if (deviceIsAndroid) { + layer.addEventListener('mouseover', this.onMouse, true); + layer.addEventListener('mousedown', this.onMouse, true); + layer.addEventListener('mouseup', this.onMouse, true); + } + + layer.addEventListener('click', this.onClick, true); + layer.addEventListener('touchstart', this.onTouchStart, false); + layer.addEventListener('touchmove', this.onTouchMove, false); + layer.addEventListener('touchend', this.onTouchEnd, false); + layer.addEventListener('touchcancel', this.onTouchCancel, false); + + // Hack is required for browsers that don't support Event#stopImmediatePropagation (e.g. Android 2) + // which is how FastClick normally stops click events bubbling to callbacks registered on the FastClick + // layer when they are cancelled. + if (!Event.prototype.stopImmediatePropagation) { + layer.removeEventListener = function(type, callback, capture) { + var rmv = Node.prototype.removeEventListener; + if (type === 'click') { + rmv.call(layer, type, callback.hijacked || callback, capture); + } else { + rmv.call(layer, type, callback, capture); + } + }; + + layer.addEventListener = function(type, callback, capture) { + var adv = Node.prototype.addEventListener; + if (type === 'click') { + adv.call(layer, type, callback.hijacked || (callback.hijacked = function(event) { + if (!event.propagationStopped) { + callback(event); + } + }), capture); + } else { + adv.call(layer, type, callback, capture); + } + }; + } + + // If a handler is already declared in the element's onclick attribute, it will be fired before + // FastClick's onClick handler. Fix this by pulling out the user-defined handler function and + // adding it as listener. + if (typeof layer.onclick === 'function') { + + // Android browser on at least 3.2 requires a new reference to the function in layer.onclick + // - the old one won't work if passed to addEventListener directly. + oldOnClick = layer.onclick; + layer.addEventListener('click', function(event) { + oldOnClick(event); + }, false); + layer.onclick = null; + } + } + + /** + * Windows Phone 8.1 fakes user agent string to look like Android and iPhone. + * + * @type boolean + */ + var deviceIsWindowsPhone = navigator.userAgent.indexOf("Windows Phone") >= 0; + + /** + * Android requires exceptions. + * + * @type boolean + */ + var deviceIsAndroid = navigator.userAgent.indexOf('Android') > 0 && !deviceIsWindowsPhone; + + + /** + * iOS requires exceptions. + * + * @type boolean + */ + var deviceIsIOS = /iP(ad|hone|od)/.test(navigator.userAgent) && !deviceIsWindowsPhone; + + + /** + * iOS 4 requires an exception for select elements. + * + * @type boolean + */ + var deviceIsIOS4 = deviceIsIOS && (/OS 4_\d(_\d)?/).test(navigator.userAgent); + + + /** + * iOS 6.0-7.* requires the target element to be manually derived + * + * @type boolean + */ + var deviceIsIOSWithBadTarget = deviceIsIOS && (/OS [6-7]_\d/).test(navigator.userAgent); + + /** + * BlackBerry requires exceptions. + * + * @type boolean + */ + var deviceIsBlackBerry10 = navigator.userAgent.indexOf('BB10') > 0; + + /** + * Determine whether a given element requires a native click. + * + * @param {EventTarget|Element} target Target DOM element + * @returns {boolean} Returns true if the element needs a native click + */ + FastClick.prototype.needsClick = function(target) { + switch (target.nodeName.toLowerCase()) { + + // Don't send a synthetic click to disabled inputs (issue #62) + case 'button': + case 'select': + case 'textarea': + if (target.disabled) { + return true; + } + + break; + case 'input': + + // File inputs need real clicks on iOS 6 due to a browser bug (issue #68) + if ((deviceIsIOS && target.type === 'file') || target.disabled) { + return true; + } + + break; + case 'label': + case 'iframe': // iOS8 homescreen apps can prevent events bubbling into frames + case 'video': + return true; + } + + return (/\bneedsclick\b/).test(target.className); + }; + + + /** + * Determine whether a given element requires a call to focus to simulate click into element. + * + * @param {EventTarget|Element} target Target DOM element + * @returns {boolean} Returns true if the element requires a call to focus to simulate native click. + */ + FastClick.prototype.needsFocus = function(target) { + switch (target.nodeName.toLowerCase()) { + case 'textarea': + return true; + case 'select': + return !deviceIsAndroid; + case 'input': + switch (target.type) { + case 'button': + case 'checkbox': + case 'file': + case 'image': + case 'radio': + case 'submit': + return false; + } + + // No point in attempting to focus disabled inputs + return !target.disabled && !target.readOnly; + default: + return (/\bneedsfocus\b/).test(target.className); + } + }; + + + /** + * Send a click event to the specified element. + * + * @param {EventTarget|Element} targetElement + * @param {Event} event + */ + FastClick.prototype.sendClick = function(targetElement, event) { + var clickEvent, touch; + + // On some Android devices activeElement needs to be blurred otherwise the synthetic click will have no effect (#24) + if (document.activeElement && document.activeElement !== targetElement) { + document.activeElement.blur(); + } + + touch = event.changedTouches[0]; + + // Synthesise a click event, with an extra attribute so it can be tracked + clickEvent = document.createEvent('MouseEvents'); + clickEvent.initMouseEvent(this.determineEventType(targetElement), true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null); + clickEvent.forwardedTouchEvent = true; + targetElement.dispatchEvent(clickEvent); + }; + + FastClick.prototype.determineEventType = function(targetElement) { + + //Issue #159: Android Chrome Select Box does not open with a synthetic click event + if (deviceIsAndroid && targetElement.tagName.toLowerCase() === 'select') { + return 'mousedown'; + } + + return 'click'; + }; + + + /** + * @param {EventTarget|Element} targetElement + */ + FastClick.prototype.focus = function(targetElement) { + var length; + + // Issue #160: on iOS 7, some input elements (e.g. date datetime month) throw a vague TypeError on setSelectionRange. These elements don't have an integer value for the selectionStart and selectionEnd properties, but unfortunately that can't be used for detection because accessing the properties also throws a TypeError. Just check the type instead. Filed as Apple bug #15122724. + if (deviceIsIOS && targetElement.setSelectionRange && targetElement.type.indexOf('date') !== 0 && targetElement.type !== 'time' && targetElement.type !== 'month' && targetElement.type !== 'email') { + length = targetElement.value.length; + targetElement.setSelectionRange(length, length); + } else { + targetElement.focus(); + } + }; + + + /** + * Check whether the given target element is a child of a scrollable layer and if so, set a flag on it. + * + * @param {EventTarget|Element} targetElement + */ + FastClick.prototype.updateScrollParent = function(targetElement) { + var scrollParent, parentElement; + + scrollParent = targetElement.fastClickScrollParent; + + // Attempt to discover whether the target element is contained within a scrollable layer. Re-check if the + // target element was moved to another parent. + if (!scrollParent || !scrollParent.contains(targetElement)) { + parentElement = targetElement; + do { + if (parentElement.scrollHeight > parentElement.offsetHeight) { + scrollParent = parentElement; + targetElement.fastClickScrollParent = parentElement; + break; + } + + parentElement = parentElement.parentElement; + } while (parentElement); + } + + // Always update the scroll top tracker if possible. + if (scrollParent) { + scrollParent.fastClickLastScrollTop = scrollParent.scrollTop; + } + }; + + + /** + * @param {EventTarget} targetElement + * @returns {Element|EventTarget} + */ + FastClick.prototype.getTargetElementFromEventTarget = function(eventTarget) { + + // On some older browsers (notably Safari on iOS 4.1 - see issue #56) the event target may be a text node. + if (eventTarget.nodeType === Node.TEXT_NODE) { + return eventTarget.parentNode; + } + + return eventTarget; + }; + + + /** + * On touch start, record the position and scroll offset. + * + * @param {Event} event + * @returns {boolean} + */ + FastClick.prototype.onTouchStart = function(event) { + var targetElement, touch, selection; + + // Ignore multiple touches, otherwise pinch-to-zoom is prevented if both fingers are on the FastClick element (issue #111). + if (event.targetTouches.length > 1) { + return true; + } + + targetElement = this.getTargetElementFromEventTarget(event.target); + touch = event.targetTouches[0]; + + if (deviceIsIOS) { + + // Only trusted events will deselect text on iOS (issue #49) + selection = window.getSelection(); + if (selection.rangeCount && !selection.isCollapsed) { + return true; + } + + if (!deviceIsIOS4) { + + // Weird things happen on iOS when an alert or confirm dialog is opened from a click event callback (issue #23): + // when the user next taps anywhere else on the page, new touchstart and touchend events are dispatched + // with the same identifier as the touch event that previously triggered the click that triggered the alert. + // Sadly, there is an issue on iOS 4 that causes some normal touch events to have the same identifier as an + // immediately preceeding touch event (issue #52), so this fix is unavailable on that platform. + // Issue 120: touch.identifier is 0 when Chrome dev tools 'Emulate touch events' is set with an iOS device UA string, + // which causes all touch events to be ignored. As this block only applies to iOS, and iOS identifiers are always long, + // random integers, it's safe to to continue if the identifier is 0 here. + if (touch.identifier && touch.identifier === this.lastTouchIdentifier) { + event.preventDefault(); + return false; + } + + this.lastTouchIdentifier = touch.identifier; + + // If the target element is a child of a scrollable layer (using -webkit-overflow-scrolling: touch) and: + // 1) the user does a fling scroll on the scrollable layer + // 2) the user stops the fling scroll with another tap + // then the event.target of the last 'touchend' event will be the element that was under the user's finger + // when the fling scroll was started, causing FastClick to send a click event to that layer - unless a check + // is made to ensure that a parent layer was not scrolled before sending a synthetic click (issue #42). + this.updateScrollParent(targetElement); + } + } + + this.trackingClick = true; + this.trackingClickStart = event.timeStamp; + this.targetElement = targetElement; + + this.touchStartX = touch.pageX; + this.touchStartY = touch.pageY; + + // Prevent phantom clicks on fast double-tap (issue #36) + if ((event.timeStamp - this.lastClickTime) < this.tapDelay) { + event.preventDefault(); + } + + return true; + }; + + + /** + * Based on a touchmove event object, check whether the touch has moved past a boundary since it started. + * + * @param {Event} event + * @returns {boolean} + */ + FastClick.prototype.touchHasMoved = function(event) { + var touch = event.changedTouches[0], boundary = this.touchBoundary; + + if (Math.abs(touch.pageX - this.touchStartX) > boundary || Math.abs(touch.pageY - this.touchStartY) > boundary) { + return true; + } + + return false; + }; + + + /** + * Update the last position. + * + * @param {Event} event + * @returns {boolean} + */ + FastClick.prototype.onTouchMove = function(event) { + if (!this.trackingClick) { + return true; + } + + // If the touch has moved, cancel the click tracking + if (this.targetElement !== this.getTargetElementFromEventTarget(event.target) || this.touchHasMoved(event)) { + this.trackingClick = false; + this.targetElement = null; + } + + return true; + }; + + + /** + * Attempt to find the labelled control for the given label element. + * + * @param {EventTarget|HTMLLabelElement} labelElement + * @returns {Element|null} + */ + FastClick.prototype.findControl = function(labelElement) { + + // Fast path for newer browsers supporting the HTML5 control attribute + if (labelElement.control !== undefined) { + return labelElement.control; + } + + // All browsers under test that support touch events also support the HTML5 htmlFor attribute + if (labelElement.htmlFor) { + return document.getElementById(labelElement.htmlFor); + } + + // If no for attribute exists, attempt to retrieve the first labellable descendant element + // the list of which is defined here: http://www.w3.org/TR/html5/forms.html#category-label + return labelElement.querySelector('button, input:not([type=hidden]), keygen, meter, output, progress, select, textarea'); + }; + + + /** + * On touch end, determine whether to send a click event at once. + * + * @param {Event} event + * @returns {boolean} + */ + FastClick.prototype.onTouchEnd = function(event) { + var forElement, trackingClickStart, targetTagName, scrollParent, touch, targetElement = this.targetElement; + + if (!this.trackingClick) { + return true; + } + + // Prevent phantom clicks on fast double-tap (issue #36) + if ((event.timeStamp - this.lastClickTime) < this.tapDelay) { + this.cancelNextClick = true; + return true; + } + + if ((event.timeStamp - this.trackingClickStart) > this.tapTimeout) { + return true; + } + + // Reset to prevent wrong click cancel on input (issue #156). + this.cancelNextClick = false; + + this.lastClickTime = event.timeStamp; + + trackingClickStart = this.trackingClickStart; + this.trackingClick = false; + this.trackingClickStart = 0; + + // On some iOS devices, the targetElement supplied with the event is invalid if the layer + // is performing a transition or scroll, and has to be re-detected manually. Note that + // for this to function correctly, it must be called *after* the event target is checked! + // See issue #57; also filed as rdar://13048589 . + if (deviceIsIOSWithBadTarget) { + touch = event.changedTouches[0]; + + // In certain cases arguments of elementFromPoint can be negative, so prevent setting targetElement to null + targetElement = document.elementFromPoint(touch.pageX - window.pageXOffset, touch.pageY - window.pageYOffset) || targetElement; + targetElement.fastClickScrollParent = this.targetElement.fastClickScrollParent; + } + + targetTagName = targetElement.tagName.toLowerCase(); + if (targetTagName === 'label') { + forElement = this.findControl(targetElement); + if (forElement) { + this.focus(targetElement); + if (deviceIsAndroid) { + return false; + } + + targetElement = forElement; + } + } else if (this.needsFocus(targetElement)) { + + // Case 1: If the touch started a while ago (best guess is 100ms based on tests for issue #36) then focus will be triggered anyway. Return early and unset the target element reference so that the subsequent click will be allowed through. + // Case 2: Without this exception for input elements tapped when the document is contained in an iframe, then any inputted text won't be visible even though the value attribute is updated as the user types (issue #37). + if ((event.timeStamp - trackingClickStart) > 100 || (deviceIsIOS && window.top !== window && targetTagName === 'input')) { + this.targetElement = null; + return false; + } + + this.focus(targetElement); + this.sendClick(targetElement, event); + + // Select elements need the event to go through on iOS 4, otherwise the selector menu won't open. + // Also this breaks opening selects when VoiceOver is active on iOS6, iOS7 (and possibly others) + if (!deviceIsIOS || targetTagName !== 'select') { + this.targetElement = null; + event.preventDefault(); + } + + return false; + } + + if (deviceIsIOS && !deviceIsIOS4) { + + // Don't send a synthetic click event if the target element is contained within a parent layer that was scrolled + // and this tap is being used to stop the scrolling (usually initiated by a fling - issue #42). + scrollParent = targetElement.fastClickScrollParent; + if (scrollParent && scrollParent.fastClickLastScrollTop !== scrollParent.scrollTop) { + return true; + } + } + + // Prevent the actual click from going though - unless the target node is marked as requiring + // real clicks or if it is in the allowlist in which case only non-programmatic clicks are permitted. + if (!this.needsClick(targetElement)) { + event.preventDefault(); + this.sendClick(targetElement, event); + } + + return false; + }; + + + /** + * On touch cancel, stop tracking the click. + * + * @returns {void} + */ + FastClick.prototype.onTouchCancel = function() { + this.trackingClick = false; + this.targetElement = null; + }; + + + /** + * Determine mouse events which should be permitted. + * + * @param {Event} event + * @returns {boolean} + */ + FastClick.prototype.onMouse = function(event) { + + // If a target element was never set (because a touch event was never fired) allow the event + if (!this.targetElement) { + return true; + } + + if (event.forwardedTouchEvent) { + return true; + } + + // Programmatically generated events targeting a specific element should be permitted + if (!event.cancelable) { + return true; + } + + // Derive and check the target element to see whether the mouse event needs to be permitted; + // unless explicitly enabled, prevent non-touch click events from triggering actions, + // to prevent ghost/doubleclicks. + if (!this.needsClick(this.targetElement) || this.cancelNextClick) { + + // Prevent any user-added listeners declared on FastClick element from being fired. + if (event.stopImmediatePropagation) { + event.stopImmediatePropagation(); + } else { + + // Part of the hack for browsers that don't support Event#stopImmediatePropagation (e.g. Android 2) + event.propagationStopped = true; + } + + // Cancel the event + event.stopPropagation(); + event.preventDefault(); + + return false; + } + + // If the mouse event is permitted, return true for the action to go through. + return true; + }; + + + /** + * On actual clicks, determine whether this is a touch-generated click, a click action occurring + * naturally after a delay after a touch (which needs to be cancelled to avoid duplication), or + * an actual click which should be permitted. + * + * @param {Event} event + * @returns {boolean} + */ + FastClick.prototype.onClick = function(event) { + var permitted; + + // It's possible for another FastClick-like library delivered with third-party code to fire a click event before FastClick does (issue #44). In that case, set the click-tracking flag back to false and return early. This will cause onTouchEnd to return early. + if (this.trackingClick) { + this.targetElement = null; + this.trackingClick = false; + return true; + } + + // Very odd behaviour on iOS (issue #18): if a submit element is present inside a form and the user hits enter in the iOS simulator or clicks the Go button on the pop-up OS keyboard the a kind of 'fake' click event will be triggered with the submit-type input element as the target. + if (event.target.type === 'submit' && event.detail === 0) { + return true; + } + + permitted = this.onMouse(event); + + // Only unset targetElement if the click is not permitted. This will ensure that the check for !targetElement in onMouse fails and the browser's click doesn't go through. + if (!permitted) { + this.targetElement = null; + } + + // If clicks are permitted, return true for the action to go through. + return permitted; + }; + + + /** + * Remove all FastClick's event listeners. + * + * @returns {void} + */ + FastClick.prototype.destroy = function() { + var layer = this.layer; + + if (deviceIsAndroid) { + layer.removeEventListener('mouseover', this.onMouse, true); + layer.removeEventListener('mousedown', this.onMouse, true); + layer.removeEventListener('mouseup', this.onMouse, true); + } + + layer.removeEventListener('click', this.onClick, true); + layer.removeEventListener('touchstart', this.onTouchStart, false); + layer.removeEventListener('touchmove', this.onTouchMove, false); + layer.removeEventListener('touchend', this.onTouchEnd, false); + layer.removeEventListener('touchcancel', this.onTouchCancel, false); + }; + + + /** + * Check whether FastClick is needed. + * + * @param {Element} layer The layer to listen on + */ + FastClick.notNeeded = function(layer) { + var metaViewport; + var chromeVersion; + var blackberryVersion; + var firefoxVersion; + + // Devices that don't support touch don't need FastClick + if (typeof window.ontouchstart === 'undefined') { + return true; + } + + // Chrome version - zero for other browsers + chromeVersion = +(/Chrome\/([0-9]+)/.exec(navigator.userAgent) || [,0])[1]; + + if (chromeVersion) { + + if (deviceIsAndroid) { + metaViewport = document.querySelector('meta[name=viewport]'); + + if (metaViewport) { + // Chrome on Android with user-scalable="no" doesn't need FastClick (issue #89) + if (metaViewport.content.indexOf('user-scalable=no') !== -1) { + return true; + } + // Chrome 32 and above with width=device-width or less don't need FastClick + if (chromeVersion > 31 && document.documentElement.scrollWidth <= window.outerWidth) { + return true; + } + } + + // Chrome desktop doesn't need FastClick (issue #15) + } else { + return true; + } + } + + if (deviceIsBlackBerry10) { + blackberryVersion = navigator.userAgent.match(/Version\/([0-9]*)\.([0-9]*)/); + + // BlackBerry 10.3+ does not require Fastclick library. + // https://github.com/ftlabs/fastclick/issues/251 + if (blackberryVersion[1] >= 10 && blackberryVersion[2] >= 3) { + metaViewport = document.querySelector('meta[name=viewport]'); + + if (metaViewport) { + // user-scalable=no eliminates click delay. + if (metaViewport.content.indexOf('user-scalable=no') !== -1) { + return true; + } + // width=device-width (or less than device-width) eliminates click delay. + if (document.documentElement.scrollWidth <= window.outerWidth) { + return true; + } + } + } + } + + // IE10 with -ms-touch-action: none or manipulation, which disables double-tap-to-zoom (issue #97) + if (layer.style.msTouchAction === 'none' || layer.style.touchAction === 'manipulation') { + return true; + } + + // Firefox version - zero for other browsers + firefoxVersion = +(/Firefox\/([0-9]+)/.exec(navigator.userAgent) || [,0])[1]; + + if (firefoxVersion >= 27) { + // Firefox 27+ does not have tap delay if the content is not zoomable - https://bugzilla.mozilla.org/show_bug.cgi?id=922896 + + metaViewport = document.querySelector('meta[name=viewport]'); + if (metaViewport && (metaViewport.content.indexOf('user-scalable=no') !== -1 || document.documentElement.scrollWidth <= window.outerWidth)) { + return true; + } + } + + // IE11: prefixed -ms-touch-action is no longer supported and it's recomended to use non-prefixed version + // http://msdn.microsoft.com/en-us/library/windows/apps/Hh767313.aspx + if (layer.style.touchAction === 'none' || layer.style.touchAction === 'manipulation') { + return true; + } + + return false; + }; + + + /** + * Factory method for creating a FastClick object + * + * @param {Element} layer The layer to listen on + * @param {Object} [options={}] The options to override the defaults + */ + FastClick.attach = function(layer, options) { + return new FastClick(layer, options); + }; + + + if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) { + + // AMD. Register as an anonymous module. + define(function() { + return FastClick; + }); + } else if (typeof module !== 'undefined' && module.exports) { + module.exports = FastClick.attach; + module.exports.FastClick = FastClick; + } else { + window.FastClick = FastClick; + } +}()); \ No newline at end of file diff --git a/webGL/datastructs/algorithms/backtracking/rat-in-maze.js b/webGL/datastructs/algorithms/backtracking/rat-in-maze.js new file mode 100644 index 000000000..ff4331305 --- /dev/null +++ b/webGL/datastructs/algorithms/backtracking/rat-in-maze.js @@ -0,0 +1,41 @@ +function isSafe(maze, x, y) { + const n = maze.length; + if (x >= 0 && y >= 0 && x < n && y < n && maze[x][y] !== 0) { + return true; + } + return false; +} + +function findPath(maze, x, y, solution) { + const n = maze.length; + if (x === n - 1 && y === n - 1) { + solution[x][y] = 1; + return true; + } + if (isSafe(maze, x, y) === true) { + solution[x][y] = 1; + if (findPath(maze, x + 1, y, solution)) { + return true; + } + if (findPath(maze, x, y + 1, solution)) { + return true; + } + solution[x][y] = 0; + return false; + } + return false; +} + +export function ratInAMaze(maze) { + const solution = []; + for (let i = 0; i < maze.length; i++) { + solution[i] = []; + for (let j = 0; j < maze[i].length; j++) { + solution[i][j] = 0; + } + } + if (findPath(maze, 0, 0, solution) === true) { + return solution; + } + return 'NO PATH FOUND'; +} diff --git a/webGL/datastructs/algorithms/backtracking/sudoku-solver.js b/webGL/datastructs/algorithms/backtracking/sudoku-solver.js new file mode 100644 index 000000000..6e1a76fca --- /dev/null +++ b/webGL/datastructs/algorithms/backtracking/sudoku-solver.js @@ -0,0 +1,76 @@ +const UNASSIGNED = 0; + +function usedInRow(matrix, row, num) { + for (let col = 0; col < matrix.length; col++) { + if (matrix[row][col] === num) { + return true; + } + } + return false; +} + +function usedInCol(matrix, col, num) { + for (let row = 0; row < matrix.length; row++) { + if (matrix[row][col] === num) { + return true; + } + } + return false; +} + +function usedInBox(matrix, boxStartRow, boxStartCol, num) { + for (let row = 0; row < 3; row++) { + for (let col = 0; col < 3; col++) { + if (matrix[row + boxStartRow][col + boxStartCol] === num) { + return true; + } + } + } + return false; +} + +function isSafe(matrix, row, col, num) { + return ( + !usedInRow(matrix, row, num) + && !usedInCol(matrix, col, num) + && !usedInBox(matrix, row - (row % 3), col - (col % 3), num) + ); +} +function solveSudoku(matrix) { + let row = 0; + let col = 0; + let checkBlankSpaces = false; + + for (row = 0; row < matrix.length; row++) { + for (col = 0; col < matrix[row].length; col++) { + if (matrix[row][col] === UNASSIGNED) { + checkBlankSpaces = true; + break; + } + } + if (checkBlankSpaces === true) { + break; + } + } + if (checkBlankSpaces === false) { + return true; + } + + for (let num = 1; num <= 9; num++) { + if (isSafe(matrix, row, col, num)) { + matrix[row][col] = num; + if (solveSudoku(matrix)) { + return true; + } + matrix[row][col] = UNASSIGNED; + } + } + return false; +} + +export function sudokuSolver(matrix) { + if (solveSudoku(matrix) === true) { + return matrix; + } + return 'NO SOLUTION EXISTS!'; +} diff --git a/webGL/datastructs/algorithms/dynamic-programing/knapsack-recursive.js b/webGL/datastructs/algorithms/dynamic-programing/knapsack-recursive.js new file mode 100644 index 000000000..fbe646e11 --- /dev/null +++ b/webGL/datastructs/algorithms/dynamic-programing/knapsack-recursive.js @@ -0,0 +1,11 @@ +export function knapSack(capacity, weights, values, n) { + if (n === 0 || capacity === 0) { + return 0; + } + if (weights[n - 1] > capacity) { + return knapSack(capacity, weights, values, n - 1); + } + const a = values[n - 1] + knapSack(capacity - weights[n - 1], weights, values, n - 1); + const b = knapSack(capacity, weights, values, n - 1); + return a > b ? a : b; +} diff --git a/webGL/datastructs/algorithms/dynamic-programing/knapsack.js b/webGL/datastructs/algorithms/dynamic-programing/knapsack.js new file mode 100644 index 000000000..9c979360a --- /dev/null +++ b/webGL/datastructs/algorithms/dynamic-programing/knapsack.js @@ -0,0 +1,41 @@ +function findValues(n, capacity, kS) { + let i = n; + let k = capacity; + // console.log('Items that are part of the solution:'); + while (i > 0 && k > 0) { + if (kS[i][k] !== kS[i - 1][k]) { + // console.log( + // item ' + i + ' can be part of solution w,v: ' + weights[i - 1] + ',' + values[i - 1] + // ); + i--; + k -= kS[i][k]; + } else { + i--; + } + } +} + +export function knapSack(capacity, weights, values, n) { + const kS = []; + for (let i = 0; i <= n; i++) { + kS[i] = []; + } + for (let i = 0; i <= n; i++) { + for (let w = 0; w <= capacity; w++) { + if (i === 0 || w === 0) { + kS[i][w] = 0; + } else if (weights[i - 1] <= w) { + const a = values[i - 1] + kS[i - 1][w - weights[i - 1]]; + const b = kS[i - 1][w]; + kS[i][w] = a > b ? a : b; // max(a,b) + // console.log(a + ' can be part of the solution'); + } else { + kS[i][w] = kS[i - 1][w]; + } + } + // console.log(kS[i].join()); + } + // extra algorithm to find the items that are part of the solution + findValues(n, capacity, kS); + return kS[n][capacity]; +} diff --git a/webGL/datastructs/algorithms/dynamic-programing/longest-common-subsequence-print.js b/webGL/datastructs/algorithms/dynamic-programing/longest-common-subsequence-print.js new file mode 100644 index 000000000..e18c6e11b --- /dev/null +++ b/webGL/datastructs/algorithms/dynamic-programing/longest-common-subsequence-print.js @@ -0,0 +1,51 @@ +function printSolution(solution, wordX, m, n) { + let a = m; + let b = n; + let x = solution[a][b]; + let answer = ''; + while (x !== '0') { + if (solution[a][b] === 'diagonal') { + answer = wordX[a - 1] + answer; + a--; + b--; + } else if (solution[a][b] === 'left') { + b--; + } else if (solution[a][b] === 'top') { + a--; + } + x = solution[a][b]; + } + return answer; +} +export function lcs(wordX, wordY) { + const m = wordX.length; + const n = wordY.length; + const l = []; + const solution = []; + for (let i = 0; i <= m; i++) { + l[i] = []; + solution[i] = []; + for (let j = 0; j <= n; j++) { + l[i][j] = 0; + solution[i][j] = '0'; + } + } + for (let i = 0; i <= m; i++) { + for (let j = 0; j <= n; j++) { + if (i === 0 || j === 0) { + l[i][j] = 0; + } else if (wordX[i - 1] === wordY[j - 1]) { + l[i][j] = l[i - 1][j - 1] + 1; + solution[i][j] = 'diagonal'; + } else { + const a = l[i - 1][j]; + const b = l[i][j - 1]; + l[i][j] = a > b ? a : b; // max(a,b) + solution[i][j] = l[i][j] === l[i - 1][j] ? 'top' : 'left'; + } + } + // console.log(l[i].join()); + // console.log(solution[i].join()); + } + return printSolution(solution, wordX, m, n); +} diff --git a/webGL/datastructs/algorithms/dynamic-programing/longest-common-subsequence.js b/webGL/datastructs/algorithms/dynamic-programing/longest-common-subsequence.js new file mode 100644 index 000000000..762c70c6c --- /dev/null +++ b/webGL/datastructs/algorithms/dynamic-programing/longest-common-subsequence.js @@ -0,0 +1,26 @@ +export function lcs(wordX, wordY) { + const m = wordX.length; + const n = wordY.length; + const l = []; + for (let i = 0; i <= m; i++) { + l[i] = []; + for (let j = 0; j <= n; j++) { + l[i][j] = 0; + } + } + for (let i = 0; i <= m; i++) { + for (let j = 0; j <= n; j++) { + if (i === 0 || j === 0) { + l[i][j] = 0; + } else if (wordX[i - 1] === wordY[j - 1]) { + l[i][j] = l[i - 1][j - 1] + 1; + } else { + const a = l[i - 1][j]; + const b = l[i][j - 1]; + l[i][j] = a > b ? a : b; // max(a,b) + } + } + // console.log(l[i].join()); + } + return l[m][n]; +} diff --git a/webGL/datastructs/algorithms/dynamic-programing/matrix-chain-multiplication.js b/webGL/datastructs/algorithms/dynamic-programing/matrix-chain-multiplication.js new file mode 100644 index 000000000..143f5772b --- /dev/null +++ b/webGL/datastructs/algorithms/dynamic-programing/matrix-chain-multiplication.js @@ -0,0 +1,45 @@ +function printOptimalParenthesis(s, i, j) { + if (i === j) { + // console.log('A[' + i + ']'); + } else { + // console.log('('); + printOptimalParenthesis(s, i, s[i][j]); + printOptimalParenthesis(s, s[i][j] + 1, j); + // console.log(')'); + } +} + +export function matrixChainOrder(p) { + const n = p.length; + const m = []; + const s = []; + for (let i = 1; i <= n; i++) { + m[i] = []; + m[i][i] = 0; + } + for (let i = 0; i <= n; i++) { + // to help printing the optimal solution + s[i] = []; // auxiliary + for (let j = 0; j <= n; j++) { + s[i][j] = 0; + } + } + for (let l = 2; l < n; l++) { + for (let i = 1; i <= (n - l) + 1; i++) { + const j = (i + l) - 1; + m[i][j] = Number.MAX_SAFE_INTEGER; + for (let k = i; k <= j - 1; k++) { + // q = cost/scalar multiplications + const q = m[i][k] + m[k + 1][j] + ((p[i - 1] * p[k]) * p[j]); + if (q < m[i][j]) { + m[i][j] = q; + s[i][j] = k; // s[i,j] = Second auxiliary table that stores k + } + } + } + } + // console.log(m); + // console.log(s); + printOptimalParenthesis(s, 1, n - 1); + return m[1][n - 1]; +} diff --git a/webGL/datastructs/algorithms/dynamic-programing/min-coin-change.js b/webGL/datastructs/algorithms/dynamic-programing/min-coin-change.js new file mode 100644 index 000000000..a477c8040 --- /dev/null +++ b/webGL/datastructs/algorithms/dynamic-programing/min-coin-change.js @@ -0,0 +1,32 @@ +export function minCoinChange(coins, amount) { + const cache = []; + + const makeChange = (value) => { + if (!value) { + return []; + } + if (cache[value]) { + return cache[value]; + } + let min = []; + let newMin; + let newAmount; + for (let i = 0; i < coins.length; i++) { + const coin = coins[i]; + newAmount = value - coin; + if (newAmount >= 0) { + newMin = makeChange(newAmount); + } + if ( + newAmount >= 0 + && (newMin.length < min.length - 1 || !min.length) + && (newMin.length || !newAmount) + ) { + min = [coin].concat(newMin); + // console.log('new Min ' + min + ' for ' + amount); + } + } + return (cache[value] = min); + }; + return makeChange(amount); +} diff --git a/webGL/datastructs/algorithms/graph/breadth-first-search.js b/webGL/datastructs/algorithms/graph/breadth-first-search.js new file mode 100644 index 000000000..7cf3f3953 --- /dev/null +++ b/webGL/datastructs/algorithms/graph/breadth-first-search.js @@ -0,0 +1,74 @@ +import Queue from '../../data-structures/queue'; + +const Colors = { + WHITE: 0, + GREY: 1, + BLACK: 2 +}; + +const initializeColor = vertices => { + const color = {}; + for (let i = 0; i < vertices.length; i++) { + color[vertices[i]] = Colors.WHITE; + } + return color; +}; + +export const breadthFirstSearch = (graph, startVertex, callback) => { + const vertices = graph.getVertices(); + const adjList = graph.getAdjList(); + const color = initializeColor(vertices); + const queue = new Queue(); + + queue.enqueue(startVertex); + + while (!queue.isEmpty()) { + const u = queue.dequeue(); + const neighbors = adjList.get(u); + color[u] = Colors.GREY; + for (let i = 0; i < neighbors.length; i++) { + const w = neighbors[i]; + if (color[w] === Colors.WHITE) { + color[w] = Colors.GREY; + queue.enqueue(w); + } + } + color[u] = Colors.BLACK; + if (callback) { + callback(u); + } + } +}; + +export const BFS = (graph, startVertex) => { + const vertices = graph.getVertices(); + const adjList = graph.getAdjList(); + const color = initializeColor(vertices); + const queue = new Queue(); + const distances = {}; + const predecessors = {}; + queue.enqueue(startVertex); + for (let i = 0; i < vertices.length; i++) { + distances[vertices[i]] = 0; + predecessors[vertices[i]] = null; + } + while (!queue.isEmpty()) { + const u = queue.dequeue(); + const neighbors = adjList.get(u); + color[u] = Colors.GREY; + for (let i = 0; i < neighbors.length; i++) { + const w = neighbors[i]; + if (color[w] === Colors.WHITE) { + color[w] = Colors.GREY; + distances[w] = distances[u] + 1; + predecessors[w] = u; + queue.enqueue(w); + } + } + color[u] = Colors.BLACK; + } + return { + distances, + predecessors + }; +}; diff --git a/webGL/datastructs/algorithms/graph/depth-first-search.js b/webGL/datastructs/algorithms/graph/depth-first-search.js new file mode 100644 index 000000000..8427659f6 --- /dev/null +++ b/webGL/datastructs/algorithms/graph/depth-first-search.js @@ -0,0 +1,86 @@ +// import Graph from '../../data-structures/graph'; + +const Colors = { + WHITE: 0, + GREY: 1, + BLACK: 2 +}; + +const initializeColor = vertices => { + const color = {}; + for (let i = 0; i < vertices.length; i++) { + color[vertices[i]] = Colors.WHITE; + } + return color; +}; + +const depthFirstSearchVisit = (u, color, adjList, callback) => { + color[u] = Colors.GREY; + if (callback) { + callback(u); + } + // console.log('Discovered ' + u); + const neighbors = adjList.get(u); + for (let i = 0; i < neighbors.length; i++) { + const w = neighbors[i]; + if (color[w] === Colors.WHITE) { + depthFirstSearchVisit(w, color, adjList, callback); + } + } + color[u] = Colors.BLACK; + // console.log('explored ' + u); +}; + +export const depthFirstSearch = (graph, callback) => { + const vertices = graph.getVertices(); + const adjList = graph.getAdjList(); + const color = initializeColor(vertices); + + for (let i = 0; i < vertices.length; i++) { + if (color[vertices[i]] === Colors.WHITE) { + depthFirstSearchVisit(vertices[i], color, adjList, callback); + } + } +}; + +const DFSVisit = (u, color, d, f, p, time, adjList) => { + // console.log('discovered ' + u); + color[u] = Colors.GREY; + d[u] = ++time.count; + const neighbors = adjList.get(u); + for (let i = 0; i < neighbors.length; i++) { + const w = neighbors[i]; + if (color[w] === Colors.WHITE) { + p[w] = u; + DFSVisit(w, color, d, f, p, time, adjList); + } + } + color[u] = Colors.BLACK; + f[u] = ++time.count; + // console.log('explored ' + u); +}; + +export const DFS = graph => { + const vertices = graph.getVertices(); + const adjList = graph.getAdjList(); + const color = initializeColor(vertices); + const d = {}; + const f = {}; + const p = {}; + const time = { count: 0 }; + for (let i = 0; i < vertices.length; i++) { + f[vertices[i]] = 0; + d[vertices[i]] = 0; + p[vertices[i]] = null; + } + for (let i = 0; i < vertices.length; i++) { + if (color[vertices[i]] === Colors.WHITE) { + DFSVisit(vertices[i], color, d, f, p, time, adjList); + } + } + return { + discovery: d, + finished: f, + predecessors: p + }; +}; diff --git a/webGL/datastructs/algorithms/graph/dijkstra.js b/webGL/datastructs/algorithms/graph/dijkstra.js new file mode 100644 index 000000000..ec223687b --- /dev/null +++ b/webGL/datastructs/algorithms/graph/dijkstra.js @@ -0,0 +1,32 @@ +const INF = Number.MAX_SAFE_INTEGER; +const minDistance = (dist, visited) => { + let min = INF; + let minIndex = -1; + for (let v = 0; v < dist.length; v++) { + if (visited[v] === false && dist[v] <= min) { + min = dist[v]; + minIndex = v; + } + } + return minIndex; +}; +export const dijkstra = (graph, src) => { + const dist = []; + const visited = []; + const { length } = graph; + for (let i = 0; i < length; i++) { + dist[i] = INF; + visited[i] = false; + } + dist[src] = 0; + for (let i = 0; i < length - 1; i++) { + const u = minDistance(dist, visited); + visited[u] = true; + for (let v = 0; v < length; v++) { + if (!visited[v] && graph[u][v] !== 0 && dist[u] !== INF && dist[u] + graph[u][v] < dist[v]) { + dist[v] = dist[u] + graph[u][v]; + } + } + } + return dist; +}; diff --git a/webGL/datastructs/algorithms/graph/floyd-warshall.js b/webGL/datastructs/algorithms/graph/floyd-warshall.js new file mode 100644 index 000000000..d8bb875e8 --- /dev/null +++ b/webGL/datastructs/algorithms/graph/floyd-warshall.js @@ -0,0 +1,26 @@ +export const floydWarshall = graph => { + const dist = []; + const { length } = graph; + for (let i = 0; i < length; i++) { + dist[i] = []; + for (let j = 0; j < length; j++) { + if (i === j) { + dist[i][j] = 0; + } else if (!isFinite(graph[i][j])) { + dist[i][j] = Infinity; + } else { + dist[i][j] = graph[i][j]; + } + } + } + for (let k = 0; k < length; k++) { + for (let i = 0; i < length; i++) { + for (let j = 0; j < length; j++) { + if (dist[i][k] + dist[k][j] < dist[i][j]) { + dist[i][j] = dist[i][k] + dist[k][j]; + } + } + } + } + return dist; +}; diff --git a/webGL/datastructs/algorithms/graph/kruskal.js b/webGL/datastructs/algorithms/graph/kruskal.js new file mode 100644 index 000000000..d1435c28a --- /dev/null +++ b/webGL/datastructs/algorithms/graph/kruskal.js @@ -0,0 +1,57 @@ +const INF = Number.MAX_SAFE_INTEGER; +const find = (i, parent) => { + while (parent[i]) { + i = parent[i]; // eslint-disable-line prefer-destructuring + } + return i; +}; +const union = (i, j, parent) => { + if (i !== j) { + parent[j] = i; + return true; + } + return false; +}; +const initializeCost = graph => { + const cost = []; + const { length } = graph; + for (let i = 0; i < length; i++) { + cost[i] = []; + for (let j = 0; j < length; j++) { + if (graph[i][j] === 0) { + cost[i][j] = INF; + } else { + cost[i][j] = graph[i][j]; + } + } + } + return cost; +}; +export const kruskal = graph => { + const { length } = graph; + const parent = []; + let ne = 0; + let a; + let b; + let u; + let v; + const cost = initializeCost(graph); + while (ne < length - 1) { + for (let i = 0, min = INF; i < length; i++) { + for (let j = 0; j < length; j++) { + if (cost[i][j] < min) { + min = cost[i][j]; + a = u = i; + b = v = j; + } + } + } + u = find(u, parent); + v = find(v, parent); + if (union(u, v, parent)) { + ne++; + } + cost[a][b] = cost[b][a] = INF; + } + return parent; +}; diff --git a/webGL/datastructs/algorithms/graph/prim.js b/webGL/datastructs/algorithms/graph/prim.js new file mode 100644 index 000000000..bbb54e953 --- /dev/null +++ b/webGL/datastructs/algorithms/graph/prim.js @@ -0,0 +1,36 @@ +const INF = Number.MAX_SAFE_INTEGER; +const minKey = (graph, key, visited) => { + // Initialize min value + let min = INF; + let minIndex = 0; + for (let v = 0; v < graph.length; v++) { + if (visited[v] === false && key[v] < min) { + min = key[v]; + minIndex = v; + } + } + return minIndex; +}; +export const prim = graph => { + const parent = []; + const key = []; + const visited = []; + const { length } = graph; + for (let i = 0; i < length; i++) { + key[i] = INF; + visited[i] = false; + } + key[0] = 0; + parent[0] = -1; + for (let i = 0; i < length - 1; i++) { + const u = minKey(graph, key, visited); + visited[u] = true; + for (let v = 0; v < length; v++) { + if (graph[u][v] && !visited[v] && graph[u][v] < key[v]) { + parent[v] = u; + key[v] = graph[u][v]; + } + } + } + return parent; +}; diff --git a/webGL/datastructs/algorithms/greedy/knapsack.js b/webGL/datastructs/algorithms/greedy/knapsack.js new file mode 100644 index 000000000..294def52b --- /dev/null +++ b/webGL/datastructs/algorithms/greedy/knapsack.js @@ -0,0 +1,18 @@ +export function knapSack(capacity, weights, values) { + const n = values.length; + let load = 0; + let val = 0; + for (let i = 0; i < n && load < capacity; i++) { + if (weights[i] <= capacity - load) { + val += values[i]; + load += weights[i]; + // console.log('using item ' + (i + 1) + ' for the solution'); + } else { + const r = (capacity - load) / weights[i]; + val += r * values[i]; + load += weights[i]; + // console.log('using ratio of ' + r + ' for item ' + (i + 1) + ' for the solution'); + } + } + return val; +} diff --git a/webGL/datastructs/algorithms/greedy/longest-common-subsequence.js b/webGL/datastructs/algorithms/greedy/longest-common-subsequence.js new file mode 100644 index 000000000..f7ec82725 --- /dev/null +++ b/webGL/datastructs/algorithms/greedy/longest-common-subsequence.js @@ -0,0 +1,11 @@ +export function lcs(wordX, wordY, m = wordX.length, n = wordY.length) { + if (m === 0 || n === 0) { + return 0; + } + if (wordX[m - 1] === wordY[n - 1]) { + return 1 + lcs(wordX, wordY, m - 1, n - 1); + } + const a = lcs(wordX, wordY, m, n - 1); + const b = lcs(wordX, wordY, m - 1, n); + return a > b ? a : b; +} diff --git a/webGL/datastructs/algorithms/greedy/matrix-chain-multiplication.js b/webGL/datastructs/algorithms/greedy/matrix-chain-multiplication.js new file mode 100644 index 000000000..63c5b4ae8 --- /dev/null +++ b/webGL/datastructs/algorithms/greedy/matrix-chain-multiplication.js @@ -0,0 +1,14 @@ +export function matrixChainOrder(p, i = 1, j = p.length - 1) { + if (i === j) { + return 0; + } + let min = Number.MAX_SAFE_INTEGER; + for (let k = i; k < j; k++) { + const count = matrixChainOrder(p, i, k) + + matrixChainOrder(p, k + 1, j) + ((p[i - 1] * p[k]) * p[j]); + if (count < min) { + min = count; + } + } + return min; +} diff --git a/webGL/datastructs/algorithms/greedy/min-coin-change.js b/webGL/datastructs/algorithms/greedy/min-coin-change.js new file mode 100644 index 000000000..61abfe919 --- /dev/null +++ b/webGL/datastructs/algorithms/greedy/min-coin-change.js @@ -0,0 +1,12 @@ +export function minCoinChange(coins, amount) { + const change = []; + let total = 0; + for (let i = coins.length; i >= 0; i--) { + const coin = coins[i]; + while (total + coin <= amount) { + change.push(coin); + total += coin; + } + } + return change; +} diff --git a/webGL/datastructs/algorithms/search/binary-search-recursive.js b/webGL/datastructs/algorithms/search/binary-search-recursive.js new file mode 100644 index 000000000..d8daa4396 --- /dev/null +++ b/webGL/datastructs/algorithms/search/binary-search-recursive.js @@ -0,0 +1,24 @@ +import { Compare, defaultCompare, DOES_NOT_EXIST } from '../../util'; +import { quickSort } from '../sorting/quicksort'; + +function binarySearchRecursive(array, value, low, high, compareFn = defaultCompare) { + if (low <= high) { + const mid = Math.floor((low + high) / 2); + const element = array[mid]; + if (compareFn(element, value) === Compare.LESS_THAN) { + return binarySearchRecursive(array, value, mid + 1, high, compareFn); + } + if (compareFn(element, value) === Compare.BIGGER_THAN) { + return binarySearchRecursive(array, value, low, mid - 1, compareFn); + } + return mid; + } + return DOES_NOT_EXIST; +} + +export function binarySearch(array, value, compareFn = defaultCompare) { + const sortedArray = quickSort(array); + const low = 0; + const high = sortedArray.length - 1; + return binarySearchRecursive(array, value, low, high, compareFn); +} diff --git a/webGL/datastructs/algorithms/search/binary-search.js b/webGL/datastructs/algorithms/search/binary-search.js new file mode 100644 index 000000000..0c2f9fbae --- /dev/null +++ b/webGL/datastructs/algorithms/search/binary-search.js @@ -0,0 +1,24 @@ +import { Compare, defaultCompare, DOES_NOT_EXIST } from '../../util'; +import { quickSort } from '../sorting/quicksort'; + +export function binarySearch(array, value, compareFn = defaultCompare) { + const sortedArray = quickSort(array); + let low = 0; + let high = sortedArray.length - 1; + while (low <= high) { + const mid = Math.floor((low + high) / 2); + const element = sortedArray[mid]; + // console.log('mid element is ' + element); + if (compareFn(element, value) === Compare.LESS_THAN) { + low = mid + 1; + // console.log('low is ' + low); + } else if (compareFn(element, value) === Compare.BIGGER_THAN) { + high = mid - 1; + // console.log('high is ' + high); + } else { + // console.log('found it'); + return mid; + } + } + return DOES_NOT_EXIST; +} diff --git a/webGL/datastructs/algorithms/search/interpolation-search.js b/webGL/datastructs/algorithms/search/interpolation-search.js new file mode 100644 index 000000000..2f9f7278b --- /dev/null +++ b/webGL/datastructs/algorithms/search/interpolation-search.js @@ -0,0 +1,40 @@ +import { + biggerEquals, + Compare, + defaultCompare, + defaultEquals, + defaultDiff, + DOES_NOT_EXIST, + lesserEquals +} from '../../util'; + +export function interpolationSearch( + array, + value, + compareFn = defaultCompare, + equalsFn = defaultEquals, + diffFn = defaultDiff +) { + const { length } = array; + let low = 0; + let high = length - 1; + let position = -1; + let delta = -1; + while ( + low <= high + && biggerEquals(value, array[low], compareFn) + && lesserEquals(value, array[high], compareFn) + ) { + delta = diffFn(value, array[low]) / diffFn(array[high], array[low]); + position = low + Math.floor((high - low) * delta); + if (equalsFn(array[position], value)) { + return position; + } + if (compareFn(array[position], value) === Compare.LESS_THAN) { + low = position + 1; + } else { + high = position - 1; + } + } + return DOES_NOT_EXIST; +} diff --git a/webGL/datastructs/algorithms/search/min-max-search.js b/webGL/datastructs/algorithms/search/min-max-search.js new file mode 100644 index 000000000..ddefb1131 --- /dev/null +++ b/webGL/datastructs/algorithms/search/min-max-search.js @@ -0,0 +1,26 @@ +import { defaultCompare, Compare } from '../../util'; + +export function findMaxValue(array, compareFn = defaultCompare) { + if (array && array.length > 0) { + let max = array[0]; + for (let i = 1; i < array.length; i++) { + if (compareFn(max, array[i]) === Compare.LESS_THAN) { + max = array[i]; + } + } + return max; + } + return undefined; +} +export function findMinValue(array, compareFn = defaultCompare) { + if (array && array.length > 0) { + let min = array[0]; + for (let i = 1; i < array.length; i++) { + if (compareFn(min, array[i]) === Compare.BIGGER_THAN) { + min = array[i]; + } + } + return min; + } + return undefined; +} diff --git a/webGL/datastructs/algorithms/search/sequential-search.js b/webGL/datastructs/algorithms/search/sequential-search.js new file mode 100644 index 000000000..346c23ac7 --- /dev/null +++ b/webGL/datastructs/algorithms/search/sequential-search.js @@ -0,0 +1,10 @@ +import { defaultEquals, DOES_NOT_EXIST } from '../../util'; + +export function sequentialSearch(array, value, equalsFn = defaultEquals) { + for (let i = 0; i < array.length; i++) { + if (equalsFn(value, array[i])) { + return i; + } + } + return DOES_NOT_EXIST; +} diff --git "a/webGL/datastructs/algorithms/shuffle/fisher\342\200\223yates.js" "b/webGL/datastructs/algorithms/shuffle/fisher\342\200\223yates.js" new file mode 100644 index 000000000..f951a3ca3 --- /dev/null +++ "b/webGL/datastructs/algorithms/shuffle/fisher\342\200\223yates.js" @@ -0,0 +1,11 @@ +import { swap } from '../../util'; + +export function shuffle(array) { + let currentIndex = array.length; + while (currentIndex !== 0) { + const randomIndex = Math.floor(Math.random() * currentIndex); + currentIndex--; + swap(array, currentIndex, randomIndex); + } + return array; +} diff --git a/webGL/datastructs/algorithms/sorting/bubble-sort-improved.js b/webGL/datastructs/algorithms/sorting/bubble-sort-improved.js new file mode 100644 index 000000000..a0aba370e --- /dev/null +++ b/webGL/datastructs/algorithms/sorting/bubble-sort-improved.js @@ -0,0 +1,16 @@ +import { Compare, defaultCompare, swap } from '../../util'; + +export function modifiedBubbleSort(array, compareFn = defaultCompare) { + const { length } = array; + for (let i = 0; i < length; i++) { + // console.log('--- '); + for (let j = 0; j < length - 1 - i; j++) { + // console.log('compare ' + array[j] + ' with ' + array[j + 1]); + if (compareFn(array[j], array[j + 1]) === Compare.BIGGER_THAN) { + // console.log('swap ' + array[j] + ' with ' + array[j + 1]); + swap(array, j, j + 1); + } + } + } + return array; +} diff --git a/webGL/datastructs/algorithms/sorting/bubble-sort.js b/webGL/datastructs/algorithms/sorting/bubble-sort.js new file mode 100644 index 000000000..7d5b928e4 --- /dev/null +++ b/webGL/datastructs/algorithms/sorting/bubble-sort.js @@ -0,0 +1,16 @@ +import { Compare, defaultCompare, swap } from '../../util'; + +export function bubbleSort(array, compareFn = defaultCompare) { + const { length } = array; + for (let i = 0; i < length; i++) { + // console.log('--- '); + for (let j = 0; j < length - 1; j++) { + // console.log('compare ' + array[j] + ' with ' + array[j + 1]); + if (compareFn(array[j], array[j + 1]) === Compare.BIGGER_THAN) { + // console.log('swap ' + array[j] + ' with ' + array[j + 1]); + swap(array, j, j + 1); + } + } + } + return array; +} diff --git a/webGL/datastructs/algorithms/sorting/bucket-sort.js b/webGL/datastructs/algorithms/sorting/bucket-sort.js new file mode 100644 index 000000000..1a11b6999 --- /dev/null +++ b/webGL/datastructs/algorithms/sorting/bucket-sort.js @@ -0,0 +1,39 @@ +import { insertionSort } from './insertion-sort'; + +function createBuckets(array, bucketSize) { + let minValue = array[0]; + let maxValue = array[0]; + for (let i = 1; i < array.length; i++) { + if (array[i] < minValue) { + minValue = array[i]; + } else if (array[i] > maxValue) { + maxValue = array[i]; + } + } + const bucketCount = Math.floor((maxValue - minValue) / bucketSize) + 1; + const buckets = []; + for (let i = 0; i < bucketCount; i++) { + buckets[i] = []; + } + for (let i = 0; i < array.length; i++) { + buckets[Math.floor((array[i] - minValue) / bucketSize)].push(array[i]); + } + return buckets; +} +function sortBuckets(buckets) { + const sortedArray = []; + for (let i = 0; i < buckets.length; i++) { + if (buckets[i] != null) { + insertionSort(buckets[i]); + sortedArray.push(...buckets[i]); + } + } + return sortedArray; +} +export function bucketSort(array, bucketSize = 5) { + if (array.length < 2) { + return array; + } + const buckets = createBuckets(array, bucketSize); + return sortBuckets(buckets); +} diff --git a/webGL/datastructs/algorithms/sorting/counting-sort.js b/webGL/datastructs/algorithms/sorting/counting-sort.js new file mode 100644 index 000000000..9a19201bb --- /dev/null +++ b/webGL/datastructs/algorithms/sorting/counting-sort.js @@ -0,0 +1,24 @@ +import { findMaxValue } from '../search/min-max-search'; + +export function countingSort(array) { + if (array.length < 2) { + return array; + } + const maxValue = findMaxValue(array); + let sortedIndex = 0; + const counts = new Array(maxValue + 1); + array.forEach(element => { + if (!counts[element]) { + counts[element] = 0; + } + counts[element]++; + }); + // console.log('Frequencies: ' + counts.join()); + counts.forEach((element, i) => { + while (element > 0) { + array[sortedIndex++] = i; + element--; + } + }); + return array; +} diff --git a/webGL/datastructs/algorithms/sorting/heap-sort.js b/webGL/datastructs/algorithms/sorting/heap-sort.js new file mode 100644 index 000000000..ff1c10f14 --- /dev/null +++ b/webGL/datastructs/algorithms/sorting/heap-sort.js @@ -0,0 +1,34 @@ +import { defaultCompare, swap } from '../../util'; + +function heapify(array, index, heapSize, compareFn) { + let largest = index; + const left = (2 * index) + 1; + const right = (2 * index) + 2; + if (left < heapSize && compareFn(array[left], array[index]) > 0) { + largest = left; + } + if (right < heapSize && compareFn(array[right], array[largest]) > 0) { + largest = right; + } + if (largest !== index) { + swap(array, index, largest); + heapify(array, largest, heapSize, compareFn); + } +} + +function buildMaxHeap(array, compareFn) { + for (let i = Math.floor(array.length / 2); i >= 0; i -= 1) { + heapify(array, i, array.length, compareFn); + } + return array; +} + +export default function heapSort(array, compareFn = defaultCompare) { + let heapSize = array.length; + buildMaxHeap(array, compareFn); + while (heapSize > 1) { + swap(array, 0, --heapSize); + heapify(array, 0, heapSize, compareFn); + } + return array; +} diff --git a/webGL/datastructs/algorithms/sorting/insertion-sort.js b/webGL/datastructs/algorithms/sorting/insertion-sort.js new file mode 100644 index 000000000..e48689e60 --- /dev/null +++ b/webGL/datastructs/algorithms/sorting/insertion-sort.js @@ -0,0 +1,19 @@ +import { Compare, defaultCompare } from '../../util'; + +export const insertionSort = (array, compareFn = defaultCompare) => { + const { length } = array; + let temp; + for (let i = 1; i < length; i++) { + let j = i; + temp = array[i]; + // console.log('to be inserted ' + temp); + while (j > 0 && compareFn(array[j - 1], temp) === Compare.BIGGER_THAN) { + // console.log('shift ' + array[j - 1]); + array[j] = array[j - 1]; + j--; + } + // console.log('insert ' + temp); + array[j] = temp; + } + return array; +}; diff --git a/webGL/datastructs/algorithms/sorting/merge-sort.js b/webGL/datastructs/algorithms/sorting/merge-sort.js new file mode 100644 index 000000000..5371e7144 --- /dev/null +++ b/webGL/datastructs/algorithms/sorting/merge-sort.js @@ -0,0 +1,21 @@ +import { Compare, defaultCompare } from '../../util'; + +function merge(left, right, compareFn) { + let i = 0; + let j = 0; + const result = []; + while (i < left.length && j < right.length) { + result.push(compareFn(left[i], right[j]) === Compare.LESS_THAN ? left[i++] : right[j++]); + } + return result.concat(i < left.length ? left.slice(i) : right.slice(j)); +} +export function mergeSort(array, compareFn = defaultCompare) { + if (array.length > 1) { + const { length } = array; + const middle = Math.floor(length / 2); + const left = mergeSort(array.slice(0, middle), compareFn); + const right = mergeSort(array.slice(middle, length), compareFn); + array = merge(left, right, compareFn); + } + return array; +} diff --git a/webGL/datastructs/algorithms/sorting/quicksort.js b/webGL/datastructs/algorithms/sorting/quicksort.js new file mode 100644 index 000000000..6e27167c7 --- /dev/null +++ b/webGL/datastructs/algorithms/sorting/quicksort.js @@ -0,0 +1,38 @@ +import { Compare, defaultCompare, swap } from '../../util'; + +function partition(array, left, right, compareFn) { + const pivot = array[Math.floor((right + left) / 2)]; + let i = left; + let j = right; + + while (i <= j) { + while (compareFn(array[i], pivot) === Compare.LESS_THAN) { + i++; + } + while (compareFn(array[j], pivot) === Compare.BIGGER_THAN) { + j--; + } + if (i <= j) { + swap(array, i, j); + i++; + j--; + } + } + return i; +} +function quick(array, left, right, compareFn) { + let index; + if (array.length > 1) { + index = partition(array, left, right, compareFn); + if (left < index - 1) { + quick(array, left, index - 1, compareFn); + } + if (index < right) { + quick(array, index, right, compareFn); + } + } + return array; +} +export function quickSort(array, compareFn = defaultCompare) { + return quick(array, 0, array.length - 1, compareFn); +} diff --git a/webGL/datastructs/algorithms/sorting/radix-sort.js b/webGL/datastructs/algorithms/sorting/radix-sort.js new file mode 100644 index 000000000..db21c37a7 --- /dev/null +++ b/webGL/datastructs/algorithms/sorting/radix-sort.js @@ -0,0 +1,44 @@ +import { findMaxValue, findMinValue } from '../search/min-max-search'; + +const getBucketIndex = (value, minValue, significantDigit, radixBase) => + Math.floor(((value - minValue) / significantDigit) % radixBase); + +const countingSortForRadix = (array, radixBase, significantDigit, minValue) => { + let bucketsIndex; + const buckets = []; + const aux = []; + for (let i = 0; i < radixBase; i++) { + buckets[i] = 0; + } + for (let i = 0; i < array.length; i++) { + bucketsIndex = getBucketIndex(array[i], minValue, significantDigit, radixBase); + buckets[bucketsIndex]++; + } + for (let i = 1; i < radixBase; i++) { + buckets[i] += buckets[i - 1]; + } + for (let i = array.length - 1; i >= 0; i--) { + bucketsIndex = getBucketIndex(array[i], minValue, significantDigit, radixBase); + aux[--buckets[bucketsIndex]] = array[i]; + } + for (let i = 0; i < array.length; i++) { + array[i] = aux[i]; + } + return array; +}; +export function radixSort(array, radixBase = 10) { + if (array.length < 2) { + return array; + } + const minValue = findMinValue(array); + const maxValue = findMaxValue(array); + // Perform counting sort for each significant digit, starting at 1 + let significantDigit = 1; + while ((maxValue - minValue) / significantDigit >= 1) { + // console.log('radix sort for digit ' + significantDigit); + array = countingSortForRadix(array, radixBase, significantDigit, minValue); + // console.log(array.join()); + significantDigit *= radixBase; + } + return array; +} diff --git a/webGL/datastructs/algorithms/sorting/selection-sort.js b/webGL/datastructs/algorithms/sorting/selection-sort.js new file mode 100644 index 000000000..55a9c2c0f --- /dev/null +++ b/webGL/datastructs/algorithms/sorting/selection-sort.js @@ -0,0 +1,21 @@ +import { Compare, defaultCompare, swap } from '../../util'; + +export const selectionSort = (array, compareFn = defaultCompare) => { + const { length } = array; + let indexMin; + for (let i = 0; i < length - 1; i++) { + indexMin = i; + // console.log('index ' + array[i]); + for (let j = i; j < length; j++) { + if (compareFn(array[indexMin], array[j]) === Compare.BIGGER_THAN) { + // console.log('new index min ' + array[j]); + indexMin = j; + } + } + if (i !== indexMin) { + // console.log('swap ' + array[i] + ' with ' + array[indexMin]); + swap(array, i, indexMin); + } + } + return array; +}; diff --git a/webGL/datastructs/algorithms/sorting/shell-sort.js b/webGL/datastructs/algorithms/sorting/shell-sort.js new file mode 100644 index 000000000..e13127f14 --- /dev/null +++ b/webGL/datastructs/algorithms/sorting/shell-sort.js @@ -0,0 +1,22 @@ +import { Compare, defaultCompare } from '../../util'; + +export function shellSort(array, compareFn = defaultCompare) { + let increment = array.length / 2; + while (increment > 0) { + for (let i = increment; i < array.length; i++) { + let j = i; + const temp = array[i]; + while (j >= increment && compareFn(array[j - increment], temp) === Compare.BIGGER_THAN) { + array[j] = array[j - increment]; + j -= increment; + } + array[j] = temp; + } + if (increment === 2) { + increment = 1; + } else { + increment = Math.floor((increment * 5) / 11); + } + } + return array; +} diff --git a/webGL/datastructs/data-structures/avl-tree.js b/webGL/datastructs/data-structures/avl-tree.js new file mode 100644 index 000000000..8ea3cfb9d --- /dev/null +++ b/webGL/datastructs/data-structures/avl-tree.js @@ -0,0 +1,169 @@ +import { Compare, defaultCompare } from '../util'; +import BinarySearchTree from './binary-search-tree'; +import { Node } from './models/node'; + +const BalanceFactor = { + UNBALANCED_RIGHT: 1, + SLIGHTLY_UNBALANCED_RIGHT: 2, + BALANCED: 3, + SLIGHTLY_UNBALANCED_LEFT: 4, + UNBALANCED_LEFT: 5 +}; + +export default class AVLTree extends BinarySearchTree { + constructor(compareFn = defaultCompare) { + super(compareFn); + this.compareFn = compareFn; + this.root = null; + } + + getNodeHeight(node) { + if (node == null) { + return -1; + } + return Math.max(this.getNodeHeight(node.left), this.getNodeHeight(node.right)) + 1; + } + + /** + * Left left case: rotate right + * + * b a + * / \ / \ + * a e -> rotationLL(b) -> c b + * / \ / \ + * c d d e + * + * @param node Node + */ + rotationLL(node) { + const tmp = node.left; + node.left = tmp.right; + tmp.right = node; + return tmp; + } + + /** + * Right right case: rotate left + * + * a b + * / \ / \ + * c b -> rotationRR(a) -> a e + * / \ / \ + * d e c d + * + * @param node Node + */ + rotationRR(node) { + const tmp = node.right; + node.right = tmp.left; + tmp.left = node; + return tmp; + } + + /** + * Left right case: rotate left then right + * @param node Node + */ + rotationLR(node) { + node.left = this.rotationRR(node.left); + return this.rotationLL(node); + } + + /** + * Right left case: rotate right then left + * @param node Node + */ + rotationRL(node) { + node.right = this.rotationLL(node.right); + return this.rotationRR(node); + } + + getBalanceFactor(node) { + const heightDifference = this.getNodeHeight(node.left) - this.getNodeHeight(node.right); + switch (heightDifference) { + case -2: + return BalanceFactor.UNBALANCED_RIGHT; + case -1: + return BalanceFactor.SLIGHTLY_UNBALANCED_RIGHT; + case 1: + return BalanceFactor.SLIGHTLY_UNBALANCED_LEFT; + case 2: + return BalanceFactor.UNBALANCED_LEFT; + default: + return BalanceFactor.BALANCED; + } + } + + insert(key) { + this.root = this.insertNode(this.root, key); + } + + insertNode(node, key) { + if (node == null) { + return new Node(key); + } if (this.compareFn(key, node.key) === Compare.LESS_THAN) { + node.left = this.insertNode(node.left, key); + } else if (this.compareFn(key, node.key) === Compare.BIGGER_THAN) { + node.right = this.insertNode(node.right, key); + } else { + return node; // duplicated key + } + // verify if tree is balanced + const balanceFactor = this.getBalanceFactor(node); + if (balanceFactor === BalanceFactor.UNBALANCED_LEFT) { + if (this.compareFn(key, node.left.key) === Compare.LESS_THAN) { + // Left left case + node = this.rotationLL(node); + } else { + // Left right case + return this.rotationLR(node); + } + } + if (balanceFactor === BalanceFactor.UNBALANCED_RIGHT) { + if (this.compareFn(key, node.right.key) === Compare.BIGGER_THAN) { + // Right right case + node = this.rotationRR(node); + } else { + // Right left case + return this.rotationRL(node); + } + } + return node; + } + + removeNode(node, key) { + node = super.removeNode(node, key); // {1} + if (node == null) { + return node; + } + // verify if tree is balanced + const balanceFactor = this.getBalanceFactor(node); + if (balanceFactor === BalanceFactor.UNBALANCED_LEFT) { + // Left left case + if ( + this.getBalanceFactor(node.left) === BalanceFactor.BALANCED + || this.getBalanceFactor(node.left) === BalanceFactor.SLIGHTLY_UNBALANCED_LEFT + ) { + return this.rotationLL(node); + } + // Left right case + if (this.getBalanceFactor(node.left) === BalanceFactor.SLIGHTLY_UNBALANCED_RIGHT) { + return this.rotationLR(node.left); + } + } + if (balanceFactor === BalanceFactor.UNBALANCED_RIGHT) { + // Right right case + if ( + this.getBalanceFactor(node.right) === BalanceFactor.BALANCED + || this.getBalanceFactor(node.right) === BalanceFactor.SLIGHTLY_UNBALANCED_RIGHT + ) { + return this.rotationRR(node); + } + // Right left case + if (this.getBalanceFactor(node.right) === BalanceFactor.SLIGHTLY_UNBALANCED_LEFT) { + return this.rotationRL(node.right); + } + } + return node; + } +} diff --git a/webGL/datastructs/data-structures/binary-search-tree.js b/webGL/datastructs/data-structures/binary-search-tree.js new file mode 100644 index 000000000..98795a169 --- /dev/null +++ b/webGL/datastructs/data-structures/binary-search-tree.js @@ -0,0 +1,152 @@ +import { Compare, defaultCompare } from '../util'; +import { Node } from './models/node'; + +export default class BinarySearchTree { + constructor(compareFn = defaultCompare) { + this.compareFn = compareFn; + this.root = undefined; + } + + insert(key) { + // special case: first key + if (this.root == null) { + this.root = new Node(key); + } else { + this.insertNode(this.root, key); + } + } + + insertNode(node, key) { + if (this.compareFn(key, node.key) === Compare.LESS_THAN) { + if (node.left == null) { + node.left = new Node(key); + } else { + this.insertNode(node.left, key); + } + } else if (node.right == null) { + node.right = new Node(key); + } else { + this.insertNode(node.right, key); + } + } + + getRoot() { + return this.root; + } + + search(key) { + return this.searchNode(this.root, key); + } + + searchNode(node, key) { + if (node == null) { + return false; + } + if (this.compareFn(key, node.key) === Compare.LESS_THAN) { + return this.searchNode(node.left, key); + } if (this.compareFn(key, node.key) === Compare.BIGGER_THAN) { + return this.searchNode(node.right, key); + } + return true; + } + + inOrderTraverse(callback) { + this.inOrderTraverseNode(this.root, callback); + } + + inOrderTraverseNode(node, callback) { + if (node != null) { + this.inOrderTraverseNode(node.left, callback); + callback(node.key); + this.inOrderTraverseNode(node.right, callback); + } + } + + preOrderTraverse(callback) { + this.preOrderTraverseNode(this.root, callback); + } + + preOrderTraverseNode(node, callback) { + if (node != null) { + callback(node.key); + this.preOrderTraverseNode(node.left, callback); + this.preOrderTraverseNode(node.right, callback); + } + } + + postOrderTraverse(callback) { + this.postOrderTraverseNode(this.root, callback); + } + + postOrderTraverseNode(node, callback) { + if (node != null) { + this.postOrderTraverseNode(node.left, callback); + this.postOrderTraverseNode(node.right, callback); + callback(node.key); + } + } + + min() { + return this.minNode(this.root); + } + + minNode(node) { + let current = node; + while (current != null && current.left != null) { + current = current.left; + } + return current; + } + + max() { + return this.maxNode(this.root); + } + + maxNode(node) { + let current = node; + while (current != null && current.right != null) { + current = current.right; + } + return current; + } + + remove(key) { + this.root = this.removeNode(this.root, key); + } + + removeNode(node, key) { + if (node == null) { + return undefined; + } + if (this.compareFn(key, node.key) === Compare.LESS_THAN) { + node.left = this.removeNode(node.left, key); + return node; + } if (this.compareFn(key, node.key) === Compare.BIGGER_THAN) { + node.right = this.removeNode(node.right, key); + return node; + } + // key is equal to node.item + // handle 3 special conditions + // 1 - a leaf node + // 2 - a node with only 1 child + // 3 - a node with 2 children + // case 1 + if (node.left == null && node.right == null) { + node = undefined; + return node; + } + // case 2 + if (node.left == null) { + node = node.right; + return node; + } if (node.right == null) { + node = node.left; + return node; + } + // case 3 + const aux = this.minNode(node.right); + node.key = aux.key; + node.right = this.removeNode(node.right, aux.key); + return node; + } +} diff --git a/webGL/datastructs/data-structures/circular-linked-list.js b/webGL/datastructs/data-structures/circular-linked-list.js new file mode 100644 index 000000000..4209087af --- /dev/null +++ b/webGL/datastructs/data-structures/circular-linked-list.js @@ -0,0 +1,75 @@ +import { defaultEquals } from '../util'; +import LinkedList from './linked-list'; +import { Node } from './models/linked-list-models'; + +export default class CircularLinkedList extends LinkedList { + constructor(equalsFn = defaultEquals) { + super(equalsFn); + } + + push(element) { + const node = new Node(element); + let current; + if (this.head == null) { + this.head = node; + } else { + current = this.getElementAt(this.size() - 1); + current.next = node; + } + // set node.next to head - to have circular list + node.next = this.head; + this.count++; + } + + insert(element, index) { + if (index >= 0 && index <= this.count) { + const node = new Node(element); + let current = this.head; + if (index === 0) { + if (this.head == null) { + // if no node in list + this.head = node; + node.next = this.head; + } else { + node.next = current; + current = this.getElementAt(this.size()); + // update last element + this.head = node; + current.next = this.head; + } + } else { + const previous = this.getElementAt(index - 1); + node.next = previous.next; + previous.next = node; + } + this.count++; + return true; + } + return false; + } + + removeAt(index) { + if (index >= 0 && index < this.count) { + let current = this.head; + if (index === 0) { + if (this.size() === 1) { + this.head = undefined; + } else { + const removed = this.head; + current = this.getElementAt(this.size() - 1); + this.head = this.head.next; + current.next = this.head; + current = removed; + } + } else { + // no need to update last element for circular list + const previous = this.getElementAt(index - 1); + current = previous.next; + previous.next = current.next; + } + this.count--; + return current.element; + } + return undefined; + } +} diff --git a/webGL/datastructs/data-structures/deque.js b/webGL/datastructs/data-structures/deque.js new file mode 100644 index 000000000..82b50617e --- /dev/null +++ b/webGL/datastructs/data-structures/deque.js @@ -0,0 +1,88 @@ +// @ts-check + +export default class Deque { + constructor() { + this.count = 0; + this.lowestCount = 0; + this.items = {}; + } + + addFront(element) { + if (this.isEmpty()) { + this.addBack(element); + } else if (this.lowestCount > 0) { + this.lowestCount--; + this.items[this.lowestCount] = element; + } else { + for (let i = this.count; i > 0; i--) { + this.items[i] = this.items[i - 1]; + } + this.count++; + this.items[0] = element; + } + } + + addBack(element) { + this.items[this.count] = element; + this.count++; + } + + removeFront() { + if (this.isEmpty()) { + return undefined; + } + const result = this.items[this.lowestCount]; + delete this.items[this.lowestCount]; + this.lowestCount++; + return result; + } + + removeBack() { + if (this.isEmpty()) { + return undefined; + } + this.count--; + const result = this.items[this.count]; + delete this.items[this.count]; + return result; + } + + peekFront() { + if (this.isEmpty()) { + return undefined; + } + return this.items[this.lowestCount]; + } + + peekBack() { + if (this.isEmpty()) { + return undefined; + } + return this.items[this.count - 1]; + } + + isEmpty() { + return this.size() === 0; + } + + clear() { + this.items = {}; + this.count = 0; + this.lowestCount = 0; + } + + size() { + return this.count - this.lowestCount; + } + + toString() { + if (this.isEmpty()) { + return ''; + } + let objString = `${this.items[this.lowestCount]}`; + for (let i = this.lowestCount + 1; i < this.count; i++) { + objString = `${objString},${this.items[i]}`; + } + return objString; + } +} diff --git a/webGL/datastructs/data-structures/dictionary.js b/webGL/datastructs/data-structures/dictionary.js new file mode 100644 index 000000000..2b0568bda --- /dev/null +++ b/webGL/datastructs/data-structures/dictionary.js @@ -0,0 +1,81 @@ +import { defaultToString } from '../util'; +import { ValuePair } from './models/value-pair'; + +export default class Dictionary { + constructor(toStrFn = defaultToString) { + this.toStrFn = toStrFn; + this.table = {}; + } + + set(key, value) { + if (key != null && value != null) { + const tableKey = this.toStrFn(key); + this.table[tableKey] = new ValuePair(key, value); + return true; + } + return false; + } + + get(key) { + const valuePair = this.table[this.toStrFn(key)]; + return valuePair == null ? undefined : valuePair.value; + } + + hasKey(key) { + return this.table[this.toStrFn(key)] != null; + } + + remove(key) { + if (this.hasKey(key)) { + delete this.table[this.toStrFn(key)]; + return true; + } + return false; + } + + values() { + return this.keyValues().map(valuePair => valuePair.value); + } + + keys() { + return this.keyValues().map(valuePair => valuePair.key); + } + + keyValues() { + return Object.values(this.table); + } + + forEach(callbackFn) { + const valuePairs = this.keyValues(); + for (let i = 0; i < valuePairs.length; i++) { + const result = callbackFn(valuePairs[i].key, valuePairs[i].value); + if (result === false) { + break; + } + } + } + + isEmpty() { + return this.size() === 0; + } + + size() { + return Object.keys(this.table).length; + } + + clear() { + this.table = {}; + } + + toString() { + if (this.isEmpty()) { + return ''; + } + const valuePairs = this.keyValues(); + let objString = `${valuePairs[0].toString()}`; + for (let i = 1; i < valuePairs.length; i++) { + objString = `${objString},${valuePairs[i].toString()}`; + } + return objString; + } +} diff --git a/webGL/datastructs/data-structures/doubly-linked-list.js b/webGL/datastructs/data-structures/doubly-linked-list.js new file mode 100644 index 000000000..e6547ec44 --- /dev/null +++ b/webGL/datastructs/data-structures/doubly-linked-list.js @@ -0,0 +1,138 @@ +import { defaultEquals } from '../util'; +import LinkedList from './linked-list'; +import { DoublyNode } from './models/linked-list-models'; + +export default class DoublyLinkedList extends LinkedList { + constructor(equalsFn = defaultEquals) { + super(equalsFn); + this.tail = undefined; + } + + push(element) { + const node = new DoublyNode(element); + if (this.head == null) { + this.head = node; + this.tail = node; // NEW + } else { + // attach to the tail node // NEW + this.tail.next = node; + node.prev = this.tail; + this.tail = node; + } + this.count++; + } + + insert(element, index) { + if (index >= 0 && index <= this.count) { + const node = new DoublyNode(element); + let current = this.head; + if (index === 0) { + if (this.head == null) { // NEW + this.head = node; + this.tail = node; // NEW + } else { + node.next = this.head; + this.head.prev = node; // NEW + this.head = node; + } + } else if (index === this.count) { // last item NEW + current = this.tail; + current.next = node; + node.prev = current; + this.tail = node; + } else { + const previous = this.getElementAt(index - 1); + current = previous.next; + node.next = current; + previous.next = node; + current.prev = node; // NEW + node.prev = previous; // NEW + } + this.count++; + return true; + } + return false; + } + + removeAt(index) { + if (index >= 0 && index < this.count) { + let current = this.head; + if (index === 0) { + this.head = this.head.next; + // if there is only one item, then we update tail as well //NEW + if (this.count === 1) { + // {2} + this.tail = undefined; + } else { + this.head.prev = undefined; + } + } else if (index === this.count - 1) { + // last item //NEW + current = this.tail; + this.tail = current.prev; + this.tail.next = undefined; + } else { + current = this.getElementAt(index); + const previous = current.prev; + // link previous with current's next - skip it to remove + previous.next = current.next; + current.next.prev = previous; // NEW + } + this.count--; + return current.element; + } + return undefined; + } + + indexOf(element) { + let current = this.head; + let index = 0; + while (current != null) { + if (this.equalsFn(element, current.element)) { + return index; + } + index++; + current = current.next; + } + return -1; + } + + getHead() { + return this.head; + } + + getTail() { + return this.tail; + } + + clear() { + super.clear(); + this.tail = undefined; + } + + toString() { + if (this.head == null) { + return ''; + } + let objString = `${this.head.element}`; + let current = this.head.next; + while (current != null) { + objString = `${objString},${current.element}`; + current = current.next; + } + return objString; + } + + inverseToString() { + if (this.tail == null) { + return ''; + } + let objString = `${this.tail.element}`; + let previous = this.tail.prev; + while (previous != null) { + objString = `${objString},${previous.element}`; + previous = previous.prev; + } + return objString; + } +} diff --git a/webGL/datastructs/data-structures/graph.js b/webGL/datastructs/data-structures/graph.js new file mode 100644 index 000000000..f9bfbe516 --- /dev/null +++ b/webGL/datastructs/data-structures/graph.js @@ -0,0 +1,50 @@ +import Dictionary from './dictionary'; + +export default class Graph { + constructor(isDirected = false) { + this.isDirected = isDirected; + this.vertices = []; + this.adjList = new Dictionary(); + } + + addVertex(v) { + if (!this.vertices.includes(v)) { + this.vertices.push(v); + this.adjList.set(v, []); // initialize adjacency list with array as well; + } + } + + addEdge(a, b) { + if (!this.adjList.get(a)) { + this.addVertex(a); + } + if (!this.adjList.get(b)) { + this.addVertex(b); + } + this.adjList.get(a).push(b); + if (this.isDirected !== true) { + this.adjList.get(b).push(a); + } + } + + getVertices() { + return this.vertices; + } + + getAdjList() { + return this.adjList; + } + + toString() { + let s = ''; + for (let i = 0; i < this.vertices.length; i++) { + s += `${this.vertices[i]} -> `; + const neighbors = this.adjList.get(this.vertices[i]); + for (let j = 0; j < neighbors.length; j++) { + s += `${neighbors[j]} `; + } + s += '\n'; + } + return s; + } +} diff --git a/webGL/datastructs/data-structures/hash-table-linear-probing-lazy.js b/webGL/datastructs/data-structures/hash-table-linear-probing-lazy.js new file mode 100644 index 000000000..d7314f0ed --- /dev/null +++ b/webGL/datastructs/data-structures/hash-table-linear-probing-lazy.js @@ -0,0 +1,132 @@ +import { defaultToString } from '../util'; +import { ValuePairLazy } from './models/value-pair-lazy'; + +export default class HashTableLinearProbingLazy { + constructor(toStrFn = defaultToString) { + this.toStrFn = toStrFn; + this.table = {}; + } + + loseloseHashCode(key) { + if (typeof key === 'number') { + return key; + } + const tableKey = this.toStrFn(key); + let hash = 0; + for (let i = 0; i < tableKey.length; i++) { + hash += tableKey.charCodeAt(i); + } + return hash % 37; + } + + hashCode(key) { + return this.loseloseHashCode(key); + } + + put(key, value) { + if (key != null && value != null) { + const position = this.hashCode(key); + if ( + this.table[position] == null + || (this.table[position] != null && this.table[position].isDeleted) + ) { + this.table[position] = new ValuePairLazy(key, value); + } else { + let index = position + 1; + while (this.table[index] != null && !this.table[position].isDeleted) { + index++; + } + this.table[index] = new ValuePairLazy(key, value); + } + return true; + } + return false; + } + + get(key) { + const position = this.hashCode(key); + if (this.table[position] != null) { + if (this.table[position].key === key && !this.table[position].isDeleted) { + return this.table[position].value; + } + let index = position + 1; + while ( + this.table[index] != null + && (this.table[index].key !== key || this.table[index].isDeleted) + ) { + if (this.table[index].key === key && this.table[index].isDeleted) { + return undefined; + } + index++; + } + if ( + this.table[index] != null + && this.table[index].key === key + && !this.table[index].isDeleted + ) { + return this.table[position].value; + } + } + return undefined; + } + + remove(key) { + const position = this.hashCode(key); + if (this.table[position] != null) { + if (this.table[position].key === key && !this.table[position].isDeleted) { + this.table[position].isDeleted = true; + return true; + } + let index = position + 1; + while ( + this.table[index] != null + && (this.table[index].key !== key || this.table[index].isDeleted) + ) { + index++; + } + if ( + this.table[index] != null + && this.table[index].key === key + && !this.table[index].isDeleted + ) { + this.table[index].isDeleted = true; + return true; + } + } + return false; + } + + isEmpty() { + return this.size() === 0; + } + + size() { + let count = 0; + Object.values(this.table).forEach(valuePair => { + count += valuePair.isDeleted === true ? 0 : 1; + }); + return count; + } + + clear() { + this.table = {}; + } + + getTable() { + return this.table; + } + + toString() { + if (this.isEmpty()) { + return ''; + } + const keys = Object.keys(this.table); + let objString = `{${keys[0]} => ${this.table[keys[0]].toString()}}`; + for (let i = 1; i < keys.length; i++) { + objString = `${objString},{${keys[i]} => ${this.table[ + keys[i] + ].toString()}}`; + } + return objString; + } +} diff --git a/webGL/datastructs/data-structures/hash-table-linear-probing.js b/webGL/datastructs/data-structures/hash-table-linear-probing.js new file mode 100644 index 000000000..2b7af8b24 --- /dev/null +++ b/webGL/datastructs/data-structures/hash-table-linear-probing.js @@ -0,0 +1,124 @@ +import { defaultToString } from '../util'; +import { ValuePair } from './models/value-pair'; + +export default class HashTableLinearProbing { + constructor(toStrFn = defaultToString) { + this.toStrFn = toStrFn; + this.table = {}; + } + + loseloseHashCode(key) { + if (typeof key === 'number') { + return key; + } + const tableKey = this.toStrFn(key); + let hash = 0; + for (let i = 0; i < tableKey.length; i++) { + hash += tableKey.charCodeAt(i); + } + return hash % 37; + } + + hashCode(key) { + return this.loseloseHashCode(key); + } + + put(key, value) { + if (key != null && value != null) { + const position = this.hashCode(key); + if (this.table[position] == null) { + this.table[position] = new ValuePair(key, value); + } else { + let index = position + 1; + while (this.table[index] != null) { + index++; + } + this.table[index] = new ValuePair(key, value); + } + return true; + } + return false; + } + + get(key) { + const position = this.hashCode(key); + if (this.table[position] != null) { + if (this.table[position].key === key) { + return this.table[position].value; + } + let index = position + 1; + while (this.table[index] != null && this.table[index].key !== key) { + index++; + } + if (this.table[index] != null && this.table[index].key === key) { + return this.table[position].value; + } + } + return undefined; + } + + remove(key) { + const position = this.hashCode(key); + if (this.table[position] != null) { + if (this.table[position].key === key) { + delete this.table[position]; + this.verifyRemoveSideEffect(key, position); + return true; + } + let index = position + 1; + while (this.table[index] != null && this.table[index].key !== key) { + index++; + } + if (this.table[index] != null && this.table[index].key === key) { + delete this.table[index]; + this.verifyRemoveSideEffect(key, index); + return true; + } + } + return false; + } + + verifyRemoveSideEffect(key, removedPosition) { + const hash = this.hashCode(key); + let index = removedPosition + 1; + while (this.table[index] != null) { + const posHash = this.hashCode(this.table[index].key); + if (posHash <= hash || posHash <= removedPosition) { + this.table[removedPosition] = this.table[index]; + delete this.table[index]; + removedPosition = index; + } + index++; + } + } + + isEmpty() { + return this.size() === 0; + } + + size() { + return Object.keys(this.table).length; + } + + clear() { + this.table = {}; + } + + getTable() { + return this.table; + } + + toString() { + if (this.isEmpty()) { + return ''; + } + const keys = Object.keys(this.table); + let objString = `{${keys[0]} => ${this.table[keys[0]].toString()}}`; + for (let i = 1; i < keys.length; i++) { + objString = `${objString},{${keys[i]} => ${this.table[ + keys[i] + ].toString()}}`; + } + return objString; + } +} diff --git a/webGL/datastructs/data-structures/hash-table-separate-chaining.js b/webGL/datastructs/data-structures/hash-table-separate-chaining.js new file mode 100644 index 000000000..c8646ae9a --- /dev/null +++ b/webGL/datastructs/data-structures/hash-table-separate-chaining.js @@ -0,0 +1,106 @@ +import { defaultToString } from '../util'; +import LinkedList from './linked-list'; +import { ValuePair } from './models/value-pair'; + +export default class HashTableSeparateChaining { + constructor(toStrFn = defaultToString) { + this.toStrFn = toStrFn; + this.table = {}; + } + + loseloseHashCode(key) { + if (typeof key === 'number') { + return key; + } + const tableKey = this.toStrFn(key); + let hash = 0; + for (let i = 0; i < tableKey.length; i++) { + hash += tableKey.charCodeAt(i); + } + return hash % 37; + } + + hashCode(key) { + return this.loseloseHashCode(key); + } + + put(key, value) { + if (key != null && value != null) { + const position = this.hashCode(key); + if (this.table[position] == null) { + this.table[position] = new LinkedList(); + } + this.table[position].push(new ValuePair(key, value)); + return true; + } + return false; + } + + get(key) { + const position = this.hashCode(key); + const linkedList = this.table[position]; + if (linkedList != null && !linkedList.isEmpty()) { + let current = linkedList.getHead(); + while (current != null) { + if (current.element.key === key) { + return current.element.value; + } + current = current.next; + } + } + return undefined; + } + + remove(key) { + const position = this.hashCode(key); + const linkedList = this.table[position]; + if (linkedList != null && !linkedList.isEmpty()) { + let current = linkedList.getHead(); + while (current != null) { + if (current.element.key === key) { + linkedList.remove(current.element); + if (linkedList.isEmpty()) { + delete this.table[position]; + } + return true; + } + current = current.next; + } + } + return false; + } + + isEmpty() { + return this.size() === 0; + } + + size() { + let count = 0; + Object.values(this.table).forEach(linkedList => { + count += linkedList.size(); + }); + return count; + } + + clear() { + this.table = {}; + } + + getTable() { + return this.table; + } + + toString() { + if (this.isEmpty()) { + return ''; + } + const keys = Object.keys(this.table); + let objString = `{${keys[0]} => ${this.table[keys[0]].toString()}}`; + for (let i = 1; i < keys.length; i++) { + objString = `${objString},{${keys[i]} => ${this.table[ + keys[i] + ].toString()}}`; + } + return objString; + } +} diff --git a/webGL/datastructs/data-structures/hash-table.js b/webGL/datastructs/data-structures/hash-table.js new file mode 100644 index 000000000..79bc51fd5 --- /dev/null +++ b/webGL/datastructs/data-structures/hash-table.js @@ -0,0 +1,85 @@ +import { defaultToString } from '../util'; +import { ValuePair } from './models/value-pair'; + +export default class HashTable { + constructor(toStrFn = defaultToString) { + this.toStrFn = toStrFn; + this.table = {}; + } + + loseloseHashCode(key) { + if (typeof key === 'number') { + return key; + } + const tableKey = this.toStrFn(key); + let hash = 0; + for (let i = 0; i < tableKey.length; i++) { + hash += tableKey.charCodeAt(i); + } + return hash % 37; + } + + /* djb2HashCode(key) { + const tableKey = this.toStrFn(key); + let hash = 5381; + for (let i = 0; i < tableKey.length; i++) { + hash = (hash * 33) + tableKey.charCodeAt(i); + } + return hash % 1013; + } */ + hashCode(key) { + return this.loseloseHashCode(key); + } + + put(key, value) { + if (key != null && value != null) { + const position = this.hashCode(key); + this.table[position] = new ValuePair(key, value); + return true; + } + return false; + } + + get(key) { + const valuePair = this.table[this.hashCode(key)]; + return valuePair == null ? undefined : valuePair.value; + } + + remove(key) { + const hash = this.hashCode(key); + const valuePair = this.table[hash]; + if (valuePair != null) { + delete this.table[hash]; + return true; + } + return false; + } + + getTable() { + return this.table; + } + + isEmpty() { + return this.size() === 0; + } + + size() { + return Object.keys(this.table).length; + } + + clear() { + this.table = {}; + } + + toString() { + if (this.isEmpty()) { + return ''; + } + const keys = Object.keys(this.table); + let objString = `{${keys[0]} => ${this.table[keys[0]].toString()}}`; + for (let i = 1; i < keys.length; i++) { + objString = `${objString},{${keys[i]} => ${this.table[keys[i]].toString()}}`; + } + return objString; + } +} diff --git a/webGL/datastructs/data-structures/heap.js b/webGL/datastructs/data-structures/heap.js new file mode 100644 index 000000000..889e59571 --- /dev/null +++ b/webGL/datastructs/data-structures/heap.js @@ -0,0 +1,121 @@ +import { + Compare, defaultCompare, reverseCompare, swap +} from '../util'; + +export class MinHeap { + constructor(compareFn = defaultCompare) { + this.compareFn = compareFn; + this.heap = []; + } + + getLeftIndex(index) { + return (2 * index) + 1; + } + + getRightIndex(index) { + return (2 * index) + 2; + } + + getParentIndex(index) { + if (index === 0) { + return undefined; + } + return Math.floor((index - 1) / 2); + } + + size() { + return this.heap.length; + } + + isEmpty() { + return this.size() <= 0; + } + + clear() { + this.heap = []; + } + + findMinimum() { + return this.isEmpty() ? undefined : this.heap[0]; + } + + insert(value) { + if (value != null) { + const index = this.heap.length; + this.heap.push(value); + this.siftUp(index); + return true; + } + return false; + } + + siftDown(index) { + let element = index; + const left = this.getLeftIndex(index); + const right = this.getRightIndex(index); + const size = this.size(); + if ( + left < size + && this.compareFn(this.heap[element], this.heap[left]) === Compare.BIGGER_THAN + ) { + element = left; + } + if ( + right < size + && this.compareFn(this.heap[element], this.heap[right]) === Compare.BIGGER_THAN + ) { + element = right; + } + if (index !== element) { + swap(this.heap, index, element); + this.siftDown(element); + } + } + + siftUp(index) { + let parent = this.getParentIndex(index); + while ( + index > 0 + && this.compareFn(this.heap[parent], this.heap[index]) === Compare.BIGGER_THAN + ) { + swap(this.heap, parent, index); + index = parent; + parent = this.getParentIndex(index); + } + } + + extract() { + if (this.isEmpty()) { + return undefined; + } + if (this.size() === 1) { + return this.heap.shift(); + } + const removedValue = this.heap[0]; + this.heap[0] = this.heap.pop(); + this.siftDown(0); + return removedValue; + } + + heapify(array) { + if (array) { + this.heap = array; + } + const maxIndex = Math.floor(this.size() / 2) - 1; + for (let i = 0; i <= maxIndex; i++) { + this.siftDown(i); + } + return this.heap; + } + + getAsArray() { + return this.heap; + } +} +export class MaxHeap extends MinHeap { + constructor(compareFn = defaultCompare) { + super(compareFn); + this.compareFn = compareFn; + this.compareFn = reverseCompare(compareFn); + } +} diff --git a/webGL/datastructs/data-structures/linked-list.js b/webGL/datastructs/data-structures/linked-list.js new file mode 100644 index 000000000..fdd32d8b3 --- /dev/null +++ b/webGL/datastructs/data-structures/linked-list.js @@ -0,0 +1,117 @@ +import { defaultEquals } from '../util'; +import { Node } from './models/linked-list-models'; + +export default class LinkedList { + constructor(equalsFn = defaultEquals) { + this.equalsFn = equalsFn; + this.count = 0; + this.head = undefined; + } + + push(element) { + const node = new Node(element); + let current; + if (this.head == null) { + // catches null && undefined + this.head = node; + } else { + current = this.head; + while (current.next != null) { + current = current.next; + } + current.next = node; + } + this.count++; + } + + getElementAt(index) { + if (index >= 0 && index <= this.count) { + let node = this.head; + for (let i = 0; i < index && node != null; i++) { + node = node.next; + } + return node; + } + return undefined; + } + + insert(element, index) { + if (index >= 0 && index <= this.count) { + const node = new Node(element); + if (index === 0) { + const current = this.head; + node.next = current; + this.head = node; + } else { + const previous = this.getElementAt(index - 1); + node.next = previous.next; + previous.next = node; + } + this.count++; + return true; + } + return false; + } + + removeAt(index) { + if (index >= 0 && index < this.count) { + let current = this.head; + if (index === 0) { + this.head = current.next; + } else { + const previous = this.getElementAt(index - 1); + current = previous.next; + previous.next = current.next; + } + this.count--; + return current.element; + } + return undefined; + } + + remove(element) { + const index = this.indexOf(element); + return this.removeAt(index); + } + + indexOf(element) { + let current = this.head; + for (let i = 0; i < this.size() && current != null; i++) { + if (this.equalsFn(element, current.element)) { + return i; + } + current = current.next; + } + return -1; + } + + isEmpty() { + return this.size() === 0; + } + + size() { + return this.count; + } + + getHead() { + return this.head; + } + + clear() { + this.head = undefined; + this.count = 0; + } + + toString() { + if (this.head == null) { + return ''; + } + let objString = `${this.head.element}`; + let current = this.head.next; + for (let i = 1; i < this.size() && current != null; i++) { + objString = `${objString},${current.element}`; + current = current.next; + } + return objString; + } +} diff --git a/webGL/datastructs/data-structures/models/linked-list-models.js b/webGL/datastructs/data-structures/models/linked-list-models.js new file mode 100644 index 000000000..31f5dd957 --- /dev/null +++ b/webGL/datastructs/data-structures/models/linked-list-models.js @@ -0,0 +1,12 @@ +export class Node { + constructor(element, next) { + this.element = element; + this.next = next; + } +} +export class DoublyNode extends Node { + constructor(element, next, prev) { + super(element, next); + this.prev = prev; + } +} diff --git a/webGL/datastructs/data-structures/models/node.js b/webGL/datastructs/data-structures/models/node.js new file mode 100644 index 000000000..33b4f3711 --- /dev/null +++ b/webGL/datastructs/data-structures/models/node.js @@ -0,0 +1,11 @@ +export class Node { + constructor(key) { + this.key = key; + this.left = undefined; + this.right = undefined; + } + + toString() { + return `${this.key}`; + } +} diff --git a/webGL/datastructs/data-structures/models/value-pair-lazy.js b/webGL/datastructs/data-structures/models/value-pair-lazy.js new file mode 100644 index 000000000..ff2e43989 --- /dev/null +++ b/webGL/datastructs/data-structures/models/value-pair-lazy.js @@ -0,0 +1,10 @@ +import { ValuePair } from './value-pair'; + +export class ValuePairLazy extends ValuePair { + constructor(key, value, isDeleted = false) { + super(key, value); + this.key = key; + this.value = value; + this.isDeleted = isDeleted; + } +} diff --git a/webGL/datastructs/data-structures/models/value-pair.js b/webGL/datastructs/data-structures/models/value-pair.js new file mode 100644 index 000000000..7aa200252 --- /dev/null +++ b/webGL/datastructs/data-structures/models/value-pair.js @@ -0,0 +1,10 @@ +export class ValuePair { + constructor(key, value) { + this.key = key; + this.value = value; + } + + toString() { + return `[#${this.key}: ${this.value}]`; + } +} diff --git a/webGL/datastructs/data-structures/queue.js b/webGL/datastructs/data-structures/queue.js new file mode 100644 index 000000000..6c8790045 --- /dev/null +++ b/webGL/datastructs/data-structures/queue.js @@ -0,0 +1,56 @@ +// @ts-check + +export default class Queue { + constructor() { + this.count = 0; + this.lowestCount = 0; + this.items = {}; + } + + enqueue(element) { + this.items[this.count] = element; + this.count++; + } + + dequeue() { + if (this.isEmpty()) { + return undefined; + } + const result = this.items[this.lowestCount]; + delete this.items[this.lowestCount]; + this.lowestCount++; + return result; + } + + peek() { + if (this.isEmpty()) { + return undefined; + } + return this.items[this.lowestCount]; + } + + isEmpty() { + return this.size() === 0; + } + + clear() { + this.items = {}; + this.count = 0; + this.lowestCount = 0; + } + + size() { + return this.count - this.lowestCount; + } + + toString() { + if (this.isEmpty()) { + return ''; + } + let objString = `${this.items[this.lowestCount]}`; + for (let i = this.lowestCount + 1; i < this.count; i++) { + objString = `${objString},${this.items[i]}`; + } + return objString; + } +} diff --git a/webGL/datastructs/data-structures/set.js b/webGL/datastructs/data-structures/set.js new file mode 100644 index 000000000..0dc29a0c3 --- /dev/null +++ b/webGL/datastructs/data-structures/set.js @@ -0,0 +1,103 @@ +export default class Set { + constructor() { + this.items = {}; + } + + add(element) { + if (!this.has(element)) { + this.items[element] = element; + return true; + } + return false; + } + + delete(element) { + if (this.has(element)) { + delete this.items[element]; + return true; + } + return false; + } + + has(element) { + return Object.prototype.hasOwnProperty.call(this.items, element); + } + + values() { + return Object.values(this.items); + } + + union(otherSet) { + const unionSet = new Set(); + this.values().forEach(value => unionSet.add(value)); + otherSet.values().forEach(value => unionSet.add(value)); + return unionSet; + } + + intersection(otherSet) { + const intersectionSet = new Set(); + const values = this.values(); + const otherValues = otherSet.values(); + let biggerSet = values; + let smallerSet = otherValues; + if (otherValues.length - values.length > 0) { + biggerSet = otherValues; + smallerSet = values; + } + smallerSet.forEach(value => { + if (biggerSet.includes(value)) { + intersectionSet.add(value); + } + }); + return intersectionSet; + } + + difference(otherSet) { + const differenceSet = new Set(); + this.values().forEach(value => { + if (!otherSet.has(value)) { + differenceSet.add(value); + } + }); + return differenceSet; + } + + isSubsetOf(otherSet) { + if (this.size() > otherSet.size()) { + return false; + } + let isSubset = true; + this.values().every(value => { + if (!otherSet.has(value)) { + isSubset = false; + return false; + } + return true; + }); + return isSubset; + } + + isEmpty() { + return this.size() === 0; + } + + size() { + return Object.keys(this.items).length; + } + + clear() { + this.items = {}; + } + + toString() { + if (this.isEmpty()) { + return ''; + } + const values = this.values(); + let objString = `${values[0]}`; + for (let i = 1; i < values.length; i++) { + objString = `${objString},${values[i].toString()}`; + } + return objString; + } +} diff --git a/webGL/datastructs/data-structures/sorted-linked-list.js b/webGL/datastructs/data-structures/sorted-linked-list.js new file mode 100644 index 000000000..6712f6a80 --- /dev/null +++ b/webGL/datastructs/data-structures/sorted-linked-list.js @@ -0,0 +1,40 @@ +import { Compare, defaultCompare, defaultEquals } from '../util'; +import LinkedList from './linked-list'; + +export default class SortedLinkedList extends LinkedList { + constructor(equalsFn = defaultEquals, compareFn = defaultCompare) { + super(equalsFn); + this.equalsFn = equalsFn; + this.compareFn = compareFn; + } + + push(element) { + if (this.isEmpty()) { + super.push(element); + } else { + const index = this.getIndexNextSortedElement(element); + super.insert(element, index); + } + } + + insert(element, index = 0) { + if (this.isEmpty()) { + return super.insert(element, index === 0 ? index : 0); + } + const pos = this.getIndexNextSortedElement(element); + return super.insert(element, pos); + } + + getIndexNextSortedElement(element) { + let current = this.head; + let i = 0; + for (; i < this.size() && current; i++) { + const comp = this.compareFn(element, current.element); + if (comp === Compare.LESS_THAN) { + return i; + } + current = current.next; + } + return i; + } +} diff --git a/webGL/datastructs/data-structures/stack-array.js b/webGL/datastructs/data-structures/stack-array.js new file mode 100644 index 000000000..1491eb2cf --- /dev/null +++ b/webGL/datastructs/data-structures/stack-array.js @@ -0,0 +1,39 @@ +// @ts-check + +export default class StackArray { + constructor() { + this.items = []; + } + + push(element) { + this.items.push(element); + } + + pop() { + return this.items.pop(); + } + + peek() { + return this.items[this.items.length - 1]; + } + + isEmpty() { + return this.items.length === 0; + } + + size() { + return this.items.length; + } + + clear() { + this.items = []; + } + + toArray() { + return this.items; + } + + toString() { + return this.items.toString(); + } +} diff --git a/webGL/datastructs/data-structures/stack-linked-list.js b/webGL/datastructs/data-structures/stack-linked-list.js new file mode 100644 index 000000000..902a5d784 --- /dev/null +++ b/webGL/datastructs/data-structures/stack-linked-list.js @@ -0,0 +1,42 @@ +import DoublyLinkedList from './doubly-linked-list'; + +export default class StackLinkedList { + constructor() { + this.items = new DoublyLinkedList(); + } + + push(element) { + this.items.push(element); + } + + pop() { + if (this.isEmpty()) { + return undefined; + } + const result = this.items.removeAt(this.size() - 1); + return result; + } + + peek() { + if (this.isEmpty()) { + return undefined; + } + return this.items.getElementAt(this.size() - 1).element; + } + + isEmpty() { + return this.items.isEmpty(); + } + + size() { + return this.items.size(); + } + + clear() { + this.items.clear(); + } + + toString() { + return this.items.toString(); + } +} diff --git a/webGL/datastructs/data-structures/stack.js b/webGL/datastructs/data-structures/stack.js new file mode 100644 index 000000000..af9b297bd --- /dev/null +++ b/webGL/datastructs/data-structures/stack.js @@ -0,0 +1,57 @@ +// @ts-check + +export default class Stack { + constructor() { + this.count = 0; + this.items = {}; + } + + push(element) { + this.items[this.count] = element; + this.count++; + } + + pop() { + if (this.isEmpty()) { + return undefined; + } + this.count--; + const result = this.items[this.count]; + delete this.items[this.count]; + return result; + } + + peek() { + if (this.isEmpty()) { + return undefined; + } + return this.items[this.count - 1]; + } + + isEmpty() { + return this.count === 0; + } + + size() { + return this.count; + } + + clear() { + /* while (!this.isEmpty()) { + this.pop(); + } */ + this.items = {}; + this.count = 0; + } + + toString() { + if (this.isEmpty()) { + return ''; + } + let objString = `${this.items[0]}`; + for (let i = 1; i < this.count; i++) { + objString = `${objString},${this.items[i]}`; + } + return objString; + } +} diff --git a/webGL/datastructs/index.js b/webGL/datastructs/index.js new file mode 100644 index 000000000..fa359f814 --- /dev/null +++ b/webGL/datastructs/index.js @@ -0,0 +1,98 @@ +import * as _util from './util'; + +// chapters 05 and 07 +export const util = _util; + +// chapter 03 +export { default as StackArray } from './data-structures/stack-array'; +export { default as Stack } from './data-structures/stack'; +export { hanoi } from './others/hanoi'; +export { hanoiStack } from './others/hanoi'; +export { baseConverter } from './others/base-converter'; +export { decimalToBinary } from './others/base-converter'; +export { parenthesesChecker } from './others/balanced-symbols'; + +// chapter 04 +export { default as Queue } from './data-structures/queue'; +export { default as Deque } from './data-structures/deque'; +export { hotPotato } from './others/hot-potato'; +export { palindromeChecker } from './others/palindrome-checker'; + +// chapter 05 +export { default as LinkedList } from './data-structures/linked-list'; +export { default as DoublyLinkedList } from './data-structures/doubly-linked-list'; +export { default as CircularLinkedList } from './data-structures/circular-linked-list'; +export { default as SortedLinkedList } from './data-structures/sorted-linked-list'; +export { default as StackLinkedList } from './data-structures/stack-linked-list'; + +// chapter 06 +export { default as Set } from './data-structures/set'; + +// chapter 07 +export { default as Dictionary } from './data-structures/dictionary'; +export { default as HashTable } from './data-structures/hash-table'; +export { default as HashTableSeparateChaining } from './data-structures/hash-table-separate-chaining'; +export { default as HashTableLinearProbing } from './data-structures/hash-table-linear-probing'; +export { default as HashTableLinearProbingLazy } from './data-structures/hash-table-linear-probing-lazy'; + +// chapter 08 +export { factorialIterative } from './others/factorial'; +export { factorial } from './others/factorial'; +export { fibonacci } from './others/fibonacci'; +export { fibonacciIterative } from './others/fibonacci'; +export { fibonacciMemoization } from './others/fibonacci'; + +// chapter 09 +export { default as BinarySearchTree } from './data-structures/binary-search-tree'; +export { default as AVLTree } from './data-structures/avl-tree'; + +// chapter 10 +export { MinHeap } from './data-structures/heap'; +export { MaxHeap } from './data-structures/heap'; +export { default as heapSort } from './algorithms/sorting/heap-sort'; + +// chapter 11 +export { default as Graph } from './data-structures/graph'; +export { breadthFirstSearch } from './algorithms/graph/breadth-first-search'; +export { BFS } from './algorithms/graph/breadth-first-search'; +export { depthFirstSearch } from './algorithms/graph/depth-first-search'; +export { DFS } from './algorithms/graph/depth-first-search'; +export { dijkstra } from './algorithms/graph/dijkstra'; +export { floydWarshall } from './algorithms/graph/floyd-warshall'; +export { prim } from './algorithms/graph/prim'; +export { kruskal } from './algorithms/graph/kruskal'; + +// chapter 12 +export { shuffle } from './algorithms/shuffle/fisher–yates'; + +export { bubbleSort } from './algorithms/sorting/bubble-sort'; +export { modifiedBubbleSort } from './algorithms/sorting/bubble-sort-improved'; +export { bucketSort } from './algorithms/sorting/bucket-sort'; +export { countingSort } from './algorithms/sorting/counting-sort'; +export { insertionSort } from './algorithms/sorting/insertion-sort'; +export { mergeSort } from './algorithms/sorting/merge-sort'; +export { quickSort } from './algorithms/sorting/quicksort'; +export { radixSort } from './algorithms/sorting/radix-sort'; +export { selectionSort } from './algorithms/sorting/selection-sort'; +export { shellSort } from './algorithms/sorting/shell-sort'; + +export { binarySearch } from './algorithms/search/binary-search'; +export { interpolationSearch } from './algorithms/search/interpolation-search'; +export { sequentialSearch } from './algorithms/search/sequential-search'; +export { findMaxValue } from './algorithms/search/min-max-search'; +export { findMinValue } from './algorithms/search/min-max-search'; + +// chapter 14 +export { binarySearch as binarySearchRecursive } from './algorithms/search/binary-search-recursive'; +export { minCoinChange } from './algorithms/dynamic-programing/min-coin-change'; +export { minCoinChange as minCoinChangeGreedy } from './algorithms/greedy/min-coin-change'; +export { knapSack } from './algorithms/dynamic-programing/knapsack'; +export { knapSack as knapSackRecursive } from './algorithms/dynamic-programing/knapsack-recursive'; +export { knapSack as knapSackGreedy } from './algorithms/greedy/knapsack'; +export { lcs } from './algorithms/dynamic-programing/longest-common-subsequence'; +export { lcs as lcsPrint } from './algorithms/dynamic-programing/longest-common-subsequence-print'; +export { lcs as lcsRecursive } from './algorithms/greedy/longest-common-subsequence'; +export { matrixChainOrder } from './algorithms/dynamic-programing/matrix-chain-multiplication'; +export { matrixChainOrder as matrixChainOrderGreedy } from './algorithms/greedy/matrix-chain-multiplication'; +export { ratInAMaze } from './algorithms/backtracking/rat-in-maze'; +export { sudokuSolver } from './algorithms/backtracking/sudoku-solver'; diff --git a/webGL/datastructs/others/balanced-symbols.js b/webGL/datastructs/others/balanced-symbols.js new file mode 100644 index 000000000..70bcd27dc --- /dev/null +++ b/webGL/datastructs/others/balanced-symbols.js @@ -0,0 +1,28 @@ +// @ts-check +import Stack from '../data-structures/stack'; + +export function parenthesesChecker(symbols) { + const stack = new Stack(); + const opens = '([{'; + const closers = ')]}'; + let balanced = true; + let index = 0; + let symbol; + let top; + + while (index < symbols.length && balanced) { + symbol = symbols[index]; + if (opens.indexOf(symbol) >= 0) { + stack.push(symbol); + } else if (stack.isEmpty()) { + balanced = false; + } else { + top = stack.pop(); + if (!(opens.indexOf(top) === closers.indexOf(symbol))) { + balanced = false; + } + } + index++; + } + return balanced && stack.isEmpty(); +} diff --git a/webGL/datastructs/others/base-converter.js b/webGL/datastructs/others/base-converter.js new file mode 100644 index 000000000..0213b1d72 --- /dev/null +++ b/webGL/datastructs/others/base-converter.js @@ -0,0 +1,45 @@ +// @ts-check +import Stack from '../data-structures/stack'; + +export function decimalToBinary(decNumber) { + const remStack = new Stack(); + let number = decNumber; + let rem; + let binaryString = ''; + + while (number > 0) { + rem = Math.floor(number % 2); + remStack.push(rem); + number = Math.floor(number / 2); + } + + while (!remStack.isEmpty()) { + binaryString += remStack.pop().toString(); + } + + return binaryString; +} + +export function baseConverter(decNumber, base) { + const remStack = new Stack(); + const digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + let number = decNumber; + let rem; + let baseString = ''; + + if (!(base >= 2 && base <= 36)) { + return ''; + } + + while (number > 0) { + rem = Math.floor(number % base); + remStack.push(rem); + number = Math.floor(number / base); + } + + while (!remStack.isEmpty()) { + baseString += digits[remStack.pop()]; + } + + return baseString; +} diff --git a/webGL/datastructs/others/factorial.js b/webGL/datastructs/others/factorial.js new file mode 100644 index 000000000..8592c36ed --- /dev/null +++ b/webGL/datastructs/others/factorial.js @@ -0,0 +1,20 @@ +export function factorialIterative(number) { + if (number < 0) { + return undefined; + } + let total = 1; + for (let n = number; n > 1; n--) { + total *= n; + } + return total; +} + +export function factorial(n) { + if (n < 0) { + return undefined; + } + if (n === 1 || n === 0) { + return 1; + } + return n * factorial(n - 1); +} diff --git a/webGL/datastructs/others/fibonacci.js b/webGL/datastructs/others/fibonacci.js new file mode 100644 index 000000000..e0ded2f9d --- /dev/null +++ b/webGL/datastructs/others/fibonacci.js @@ -0,0 +1,32 @@ +export function fibonacci(n) { + if (n < 1) { + return 0; + } + if (n <= 2) { + return 1; + } + return fibonacci(n - 1) + fibonacci(n - 2); +} + +export function fibonacciIterative(n) { + if (n < 1) { return 0; } + let fibNMinus2 = 0; + let fibNMinus1 = 1; + let fibN = n; + for (let i = 2; i <= n; i++) { + fibN = fibNMinus1 + fibNMinus2; + fibNMinus2 = fibNMinus1; + fibNMinus1 = fibN; + } + return fibN; +} + +export function fibonacciMemoization(n) { + if (n < 1) { return 0; } + const memo = [0, 1]; + const fibonacciMem = num => { + if (memo[num] != null) { return memo[num]; } + return (memo[num] = fibonacciMem(num - 1) + fibonacciMem(num - 2)); + }; + return fibonacciMem(n); +} diff --git a/webGL/datastructs/others/hanoi.js b/webGL/datastructs/others/hanoi.js new file mode 100644 index 000000000..b1ab2d0e5 --- /dev/null +++ b/webGL/datastructs/others/hanoi.js @@ -0,0 +1,52 @@ +// @ts-check +import Stack from '../data-structures/stack'; + +function towerOfHanoi(plates, source, helper, dest, sourceName, helperName, destName, moves = []) { + if (plates <= 0) { + return moves; + } + if (plates === 1) { + dest.push(source.pop()); + const move = {}; + move[sourceName] = source.toString(); + move[helperName] = helper.toString(); + move[destName] = dest.toString(); + moves.push(move); + } else { + towerOfHanoi(plates - 1, source, dest, helper, sourceName, destName, helperName, moves); + dest.push(source.pop()); + const move = {}; + move[sourceName] = source.toString(); + move[helperName] = helper.toString(); + move[destName] = dest.toString(); + moves.push(move); + towerOfHanoi(plates - 1, helper, source, dest, helperName, sourceName, destName, moves); + } + return moves; +} + +export function hanoiStack(plates) { + const source = new Stack(); + const dest = new Stack(); + const helper = new Stack(); + + for (let i = plates; i > 0; i--) { + source.push(i); + } + + return towerOfHanoi(plates, source, helper, dest, 'source', 'helper', 'dest'); +} + +export function hanoi(plates, source, helper, dest, moves = []) { + if (plates <= 0) { + return moves; + } + if (plates === 1) { + moves.push([source, dest]); + } else { + hanoi(plates - 1, source, dest, helper, moves); + moves.push([source, dest]); + hanoi(plates - 1, helper, source, dest, moves); + } + return moves; +} diff --git a/webGL/datastructs/others/hot-potato.js b/webGL/datastructs/others/hot-potato.js new file mode 100644 index 000000000..b34fcc64d --- /dev/null +++ b/webGL/datastructs/others/hot-potato.js @@ -0,0 +1,22 @@ +import Queue from '../data-structures/queue'; + +export function hotPotato(elementsList, num) { + const queue = new Queue(); + const elimitatedList = []; + + for (let i = 0; i < elementsList.length; i++) { + queue.enqueue(elementsList[i]); + } + + while (queue.size() > 1) { + for (let i = 0; i < num; i++) { + queue.enqueue(queue.dequeue()); + } + elimitatedList.push(queue.dequeue()); + } + + return { + eliminated: elimitatedList, + winner: queue.dequeue() + }; +} diff --git a/webGL/datastructs/others/palindrome-checker.js b/webGL/datastructs/others/palindrome-checker.js new file mode 100644 index 000000000..1551e26a9 --- /dev/null +++ b/webGL/datastructs/others/palindrome-checker.js @@ -0,0 +1,29 @@ +import Deque from '../data-structures/deque'; + +export function palindromeChecker(aString) { + if ( + aString === undefined + || aString === null + || (aString !== null && aString.length === 0) + ) { + return false; + } + const deque = new Deque(); + const lowerString = aString.toLocaleLowerCase().split(' ').join(''); + let firstChar; + let lastChar; + + for (let i = 0; i < lowerString.length; i++) { + deque.addBack(lowerString.charAt(i)); + } + + while (deque.size() > 1) { + firstChar = deque.removeFront(); + lastChar = deque.removeBack(); + if (firstChar !== lastChar) { + return false; + } + } + + return true; +} diff --git a/webGL/datastructs/util.js b/webGL/datastructs/util.js new file mode 100644 index 000000000..9e780fbad --- /dev/null +++ b/webGL/datastructs/util.js @@ -0,0 +1,53 @@ +export const Compare = { + LESS_THAN: -1, + BIGGER_THAN: 1, + EQUALS: 0 +}; + +export const DOES_NOT_EXIST = -1; + +export function lesserEquals(a, b, compareFn) { + const comp = compareFn(a, b); + return comp === Compare.LESS_THAN || comp === Compare.EQUALS; +} + +export function biggerEquals(a, b, compareFn) { + const comp = compareFn(a, b); + return comp === Compare.BIGGER_THAN || comp === Compare.EQUALS; +} + +export function defaultCompare(a, b) { + if (a === b) { + return Compare.EQUALS; + } + return a < b ? Compare.LESS_THAN : Compare.BIGGER_THAN; +} + +export function defaultEquals(a, b) { + return a === b; +} + +export function defaultToString(item) { + if (item === null) { + return 'NULL'; + } if (item === undefined) { + return 'UNDEFINED'; + } if (typeof item === 'string' || item instanceof String) { + return `${item}`; + } + return item.toString(); +} + +export function swap(array, a, b) { + /* const temp = array[a]; + array[a] = array[b]; + array[b] = temp; */ + [array[a], array[b]] = [array[b], array[a]]; +} +export function reverseCompare(compareFn) { + return (a, b) => compareFn(b, a); +} + +export function defaultDiff(a, b) { + return Number(a) - Number(b); +} diff --git a/webGL/learn/001.js b/webGL/learn/001.js new file mode 100644 index 000000000..627ad78b9 --- /dev/null +++ b/webGL/learn/001.js @@ -0,0 +1,28 @@ +let nums1 = [4,6,7,8],nums2 = [3,4,5] +const fn = (nums1,nums2)=>{ + + let len1 = nums1.length-1,len2 = nums2.length-1 + let len = len1+len2+1,leng = len+1; + let res = 0 + while(len2>=0){ + if(len1<0){ + nums1[len--] = nums2[len2--] + continue + } + nums1[len--]= nums1[len1] >= nums2[len2]?nums1[len1--]:nums2[len2--] + } + + if(leng%2==0){ + let i = leng/2 + res = (nums1[i]+nums1[i-1])/2 + + }else{ + let i = Math.floor(leng/2) + res = nums1[i] + } + console.log('aaa',res,nums1); + return res +} + +let res=fn(nums2,nums1) +console.log('a--',res); diff --git a/webGL/learn/1010/1.html b/webGL/learn/1010/1.html new file mode 100644 index 000000000..7faa77d99 --- /dev/null +++ b/webGL/learn/1010/1.html @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + +
+ + + \ No newline at end of file diff --git a/webGL/learn/1010/a.js b/webGL/learn/1010/a.js new file mode 100644 index 000000000..9bc65eb8b --- /dev/null +++ b/webGL/learn/1010/a.js @@ -0,0 +1,16 @@ +//2 5 4 3 1 + + +setTimeout(function() { + console.log(1) + }, 0); + new Promise(function(resolve, reject) { + console.log(2); + resolve() + }).then(function() { + console.log(3) + }); + process.nextTick(function () { + console.log(4) + }) + console.log(5) \ No newline at end of file diff --git a/webGL/learn/1010/b.js b/webGL/learn/1010/b.js new file mode 100644 index 000000000..4f9c6e9cd --- /dev/null +++ b/webGL/learn/1010/b.js @@ -0,0 +1,11 @@ +//闭包 +const fn =()=>{ + let a = 0 + return ()=> ++a; +} + +let f = fn() +// f() +// f() + +console.log(f(),f()); diff --git a/webGL/learn/1010/class.js b/webGL/learn/1010/class.js new file mode 100644 index 000000000..1b1a0a6b2 --- /dev/null +++ b/webGL/learn/1010/class.js @@ -0,0 +1,44 @@ +class Person { + constructor(firstName, lastName, age, address){ + this.lastName = lastName; + this.firstName = firstName; + this.age = age; + this.address = address; + } + + static self() { + return this; + } + + toString(){ + return "[object Person]"; + } + + get describe(){ + return `aaaaaaa` + } + + getFullName(){ + return `${this.firstName} ${this.lastName}`; + } +} +class Employee extends Person { //Inherits from "Person" class + constructor(firstName, lastName, age, address, jobTitle, yearStarted) { + super(firstName, lastName, age, address); + this.jobTitle = jobTitle; + this.yearStarted = yearStarted; + } + + describe() { + return `I am ${this.getFullName()} and I have a position of ${this.jobTitle} and I started at ${this.yearStarted}`; + } + + toString() { // Overriding the "toString" method of "Person" + return "[object Employee]"; + } +} + +const p = new Person('w' ,'y' , 38, '北京') +const p2 = new Employee('w' ,'y' , 38, '北京','IT','17') +console.log(p.getFullName(),p.describe, p.toString(), p2.describe()); + diff --git a/webGL/learn/1010/curry.js b/webGL/learn/1010/curry.js new file mode 100644 index 000000000..5f03dc105 --- /dev/null +++ b/webGL/learn/1010/curry.js @@ -0,0 +1,70 @@ +// 函数柯里化 +function curry(fn, args, holes) { + length = fn.length; + + args = args || []; + + holes = holes || []; + + return function() { + + var _args = args.slice(0), + _holes = holes.slice(0), + argsLen = args.length, + holesLen = holes.length, + arg, i, index = 0; + + for (i = 0; i < arguments.length; i++) { + arg = arguments[i]; + // 处理类似 fn(1, _, _, 4)(_, 3) 这种情况,index 需要指向 holes 正确的下标 + if (arg === _ && holesLen) { + index++ + if (index > holesLen) { + _args.push(arg); + _holes.push(argsLen - 1 + index - holesLen) + } + } + // 处理类似 fn(1)(_) 这种情况 + else if (arg === _) { + _args.push(arg); + _holes.push(argsLen + i); + } + // 处理类似 fn(_, 2)(1) 这种情况 + else if (holesLen) { + // fn(_, 2)(_, 3) + if (index >= holesLen) { + _args.push(arg); + } + // fn(_, 2)(1) 用参数 1 替换占位符 + else { + _args.splice(_holes[index], 1, arg); + _holes.splice(index, 1) + } + } + else { + _args.push(arg); + } + + } + if (_holes.length || _args.length < length) { + return curry.call(this, fn, _args, _holes); + } + else { + return fn.apply(this, _args); + } + } +} + +var _ = {}; + +var fn = curry(function(a, b, c, d, e) { + console.log([a, b, c, d, e]); +}); + +// 验证 输出全部都是 [1, 2, 3, 4, 5] +fn(1, 2, 3, 4, 5); +fn(_, 2, 3, 4, 5)(1); +fn(1, _, 3, 4, 5)(2); +fn(1, _, 3)(_, 4)(2)(5); +fn(1, _, _, 4)(_, 3)(2)(5); +fn(_, 2)(_, _, 4)(1)(3)(5) \ No newline at end of file diff --git a/webGL/learn/1010/debounce.html b/webGL/learn/1010/debounce.html new file mode 100644 index 000000000..cef7be1ae --- /dev/null +++ b/webGL/learn/1010/debounce.html @@ -0,0 +1,49 @@ + + + + + Title + + + +

这是一个事件节流的🌰 呵呵哒

+
Block 1
+
Block 2
+
Block 3
+
Block 4
+ + + + + \ No newline at end of file diff --git a/webGL/learn/1010/debounce.js b/webGL/learn/1010/debounce.js new file mode 100644 index 000000000..1a34ed47e --- /dev/null +++ b/webGL/learn/1010/debounce.js @@ -0,0 +1,20 @@ +// 函数防抖的实现 +function debounce(fn, wait) { + var timer = null; + + return function() { + var context = this, + args = arguments; + + // 如果此时存在定时器的话,则取消之前的定时器重新记时 + if (timer) { + clearTimeout(timer); + timer = null; + } + + // 设置定时器,使事件间隔指定事件后执行 + timer = setTimeout(() => { + fn.apply(context, args); + }, wait); + }; + } \ No newline at end of file diff --git a/webGL/learn/1010/deepclone.js b/webGL/learn/1010/deepclone.js new file mode 100644 index 000000000..25a7b90b6 --- /dev/null +++ b/webGL/learn/1010/deepclone.js @@ -0,0 +1,147 @@ +const mapTag = '[object Map]'; +const setTag = '[object Set]'; +const arrayTag = '[object Array]'; +const objectTag = '[object Object]'; +const argsTag = '[object Arguments]'; + +const boolTag = '[object Boolean]'; +const dateTag = '[object Date]'; +const numberTag = '[object Number]'; +const stringTag = '[object String]'; +const symbolTag = '[object Symbol]'; +const errorTag = '[object Error]'; +const regexpTag = '[object RegExp]'; +const funcTag = '[object Function]'; + +const deepTag = [mapTag, setTag, arrayTag, objectTag, argsTag]; + + +function forEach(array, iteratee) { + let index = -1; + const length = array.length; + while (++index < length) { + iteratee(array[index], index); + } + return array; +} + +function isObject(target) { + const type = typeof target; + return target !== null && (type === 'object' || type === 'function'); +} + +function getType(target) { + return Object.prototype.toString.call(target); +} + +function getInit(target) { + const Ctor = target.constructor; + return new Ctor(); +} + +function cloneSymbol(targe) { + return Object(Symbol.prototype.valueOf.call(targe)); +} + +function cloneReg(targe) { + const reFlags = /\w*$/; + const result = new targe.constructor(targe.source, reFlags.exec(targe)); + result.lastIndex = targe.lastIndex; + return result; +} + +function cloneFunction(func) { + const bodyReg = /(?<={)(.|\n)+(?=})/m; + const paramReg = /(?<=\().+(?=\)\s+{)/; + const funcString = func.toString(); + if (func.prototype) { + const param = paramReg.exec(funcString); + const body = bodyReg.exec(funcString); + if (body) { + if (param) { + const paramArr = param[0].split(','); + return new Function(...paramArr, body[0]); + } else { + return new Function(body[0]); + } + } else { + return null; + } + } else { + return eval(funcString); + } +} + +function cloneOtherType(targe, type) { + const Ctor = targe.constructor; + switch (type) { + case boolTag: + case numberTag: + case stringTag: + case errorTag: + case dateTag: + return new Ctor(targe); + case regexpTag: + return cloneReg(targe); + case symbolTag: + return cloneSymbol(targe); + case funcTag: + return cloneFunction(targe); + default: + return null; + } +} + +function clone(target, map = new WeakMap()) { + + // 克隆原始类型 + if (!isObject(target)) { + return target; + } + + // 初始化 + const type = getType(target); + let cloneTarget; + if (deepTag.includes(type)) { + cloneTarget = getInit(target, type); + } else { + return cloneOtherType(target, type); + } + + // 防止循环引用 + if (map.get(target)) { + return map.get(target); + } + map.set(target, cloneTarget); + + // 克隆set + if (type === setTag) { + target.forEach(value => { + cloneTarget.add(clone(value, map)); + }); + return cloneTarget; + } + + // 克隆map + if (type === mapTag) { + target.forEach((value, key) => { + cloneTarget.set(key, clone(value, map)); + }); + return cloneTarget; + } + + // 克隆对象和数组 + const keys = type === arrayTag ? undefined : Object.keys(target); + forEach(keys || target, (value, key) => { + if (keys) { + key = value; + } + cloneTarget[key] = clone(target[key], map); + }); + + return cloneTarget; +} + +module.exports = { + clone +}; \ No newline at end of file diff --git a/webGL/learn/1010/linkchain.js b/webGL/learn/1010/linkchain.js new file mode 100644 index 000000000..eaac9e1a3 --- /dev/null +++ b/webGL/learn/1010/linkchain.js @@ -0,0 +1,91 @@ + +class Node { + constructor(element, next) { + this.element = element; + this.next = next; + } +} +class DoublyNode extends Node { + constructor(element, next, prev) { + super(element, next); + this.prev = prev; + } +} + +class LinkNode{ + constructor(equalsFn = true) { + this.equalsFn = equalsFn; + this.count = 0; + this.head = null; + } + push(element) { + const node = new Node(element); + let current; + if (this.head == null) { + // catches null && undefined + this.head = node; + } else { + current = this.head; + while (current.next != null) { + current = current.next; + } + current.next = node; + } + this.count++; + } + removeAt(index){ + let i = 0 + let current = this.head + if(index' + node=node.next + }else{ + str += node.element + node.element = null + } + } + console.log(str); + } + + get Header() { + return this.head.element; + } + + clear() { + this.head = null; + this.count = 0; + } + +} + +let ls = new LinkNode() +ls.push('a') +ls.push('b') +ls.push('c') +ls.push('d') +ls.removeAt(3) +ls.removeAt(3) +console.log(ls.Header); +console.log(ls.count); + +ls.print() + +// console.log(ls) \ No newline at end of file diff --git a/webGL/learn/1010/promise.js b/webGL/learn/1010/promise.js new file mode 100644 index 000000000..542aba233 --- /dev/null +++ b/webGL/learn/1010/promise.js @@ -0,0 +1,39 @@ +function myPromise(constructor){ + let self=this; + self.status="pending" //定义状态改变前的初始状态 + self.value=undefined;//定义状态为resolved的时候的状态 + self.reason=undefined;//定义状态为rejected的时候的状态 + function resolve(value){ + //两个==="pending",保证了状态的改变是不可逆的 + if(self.status==="pending"){ + self.value=value; + self.status="resolved"; + } + } + function reject(reason){ + //两个==="pending",保证了状态的改变是不可逆的 + if(self.status==="pending"){ + self.reason=reason; + self.status="rejected"; + } + } + //捕获构造异常 + try{ + constructor(resolve,reject); + }catch(e){ + reject(e); + } +} +// 定义链式调用的then方法 +myPromise.prototype.then=function(onFullfilled,onRejected){ + let self=this; + switch(self.status){ + case "resolved": + onFullfilled(self.value); + break; + case "rejected": + onRejected(self.reason); + break; + default: + } +} diff --git a/webGL/learn/1010/throttle.html b/webGL/learn/1010/throttle.html new file mode 100644 index 000000000..762c8c92e --- /dev/null +++ b/webGL/learn/1010/throttle.html @@ -0,0 +1,54 @@ + + + + + Title + + + +

这是一个事件防抖的🌰 呵呵哒

+
normal resize events
+
Debounced resize events
+ + + + + \ No newline at end of file diff --git a/webGL/learn/1010/throttle.js b/webGL/learn/1010/throttle.js new file mode 100644 index 000000000..10149582c --- /dev/null +++ b/webGL/learn/1010/throttle.js @@ -0,0 +1,17 @@ +// 函数节流的实现; +function throttle(fn, delay) { + var preTime = Date.now(); + + return function() { + var context = this, + args = arguments, + nowTime = Date.now(); + + // 如果两次时间间隔超过了指定时间,则执行函数。 + if (nowTime - preTime >= delay) { + preTime = Date.now(); + return fn.apply(context, args); + } + }; + } + \ No newline at end of file diff --git a/webGL/learn/1225/promise.js b/webGL/learn/1225/promise.js new file mode 100644 index 000000000..8ca237fd8 --- /dev/null +++ b/webGL/learn/1225/promise.js @@ -0,0 +1,18 @@ +function wait(){ + return new Promise(resolve=>{ + setTimeout(resolve,10*1000) + }) +} +async function main(){ + console.time() + const x = wait() + const y = wait() + const z = wait() + await x; + await y; + await z; + console.timeEnd() +} + +main() +console.time();console.timeEnd() \ No newline at end of file diff --git a/webGL/learn/1225/test.js b/webGL/learn/1225/test.js new file mode 100644 index 000000000..163e2323b --- /dev/null +++ b/webGL/learn/1225/test.js @@ -0,0 +1,3 @@ +console.time(); +console.log('a'); +console.timeEnd() \ No newline at end of file diff --git a/webGL/learn/IntersectionObserver.html b/webGL/learn/IntersectionObserver.html new file mode 100644 index 000000000..374793284 --- /dev/null +++ b/webGL/learn/IntersectionObserver.html @@ -0,0 +1,56 @@ + + + + + + IntersectionObserver + + + +
+
+
+ + + \ No newline at end of file diff --git a/webGL/learn/leetcode125.js b/webGL/learn/leetcode125.js new file mode 100644 index 000000000..d076b2b2a --- /dev/null +++ b/webGL/learn/leetcode125.js @@ -0,0 +1,20 @@ +var isPalindrome = function(str) { + let s = str.replace(/[^0-9a-zA-Z]/g,'').toLowerCase() + console.log('---',s,str); + let len = s.length-1,ind = 0,flag = true + + while(len >= ind){ + console.log(s[len],s[ind]); + if(s[len]!==s[ind]){ + flag = false + } + len-- + ind++ + } + return flag +}; + + +console.log(isPalindrome(",; W;:GlG:;l ;,")); + +console.log(isPalindrome('ab ab A')); diff --git a/webGL/learn/leetcode125.ts b/webGL/learn/leetcode125.ts new file mode 100644 index 000000000..201c088e6 --- /dev/null +++ b/webGL/learn/leetcode125.ts @@ -0,0 +1,16 @@ +function isPalindrome(s: string): boolean { + const formatS = s.replace(/[^0-9a-zA-Z]/g, '').toLowerCase() + + const slen = formatS.length + if (!slen) { + return true + } + let i = 0 + let j = slen - 1 + while(i < j) { + if (formatS[i++] !== formatS[j--]) { + return false + } + } + return true +}; diff --git a/webGL/learn/listClass.js b/webGL/learn/listClass.js new file mode 100644 index 000000000..ddf82dba3 --- /dev/null +++ b/webGL/learn/listClass.js @@ -0,0 +1,24 @@ +class List { + constructor(...arg){ + this.list=[...arg] + } + get length(){ + return this.list.length + } + add(...arg){ + this.list = [...this.list,...arg] + } + [Symbol.iterator]() { + return this.list.entries() + } + all() { + return this.list + } +} + +let a = new List('a','b','c') +a.add('d','e') +console.log(a.length,a.all()); +for(let [i,v] of a){ + console.log('aa',v); +} diff --git a/webGL/learn/promiseall.js b/webGL/learn/promiseall.js new file mode 100644 index 000000000..44713cbd6 --- /dev/null +++ b/webGL/learn/promiseall.js @@ -0,0 +1,37 @@ +const promiseAll = (promises)=> { + return new Promise(function (resolve, reject) { + if (!Array.isArray(promises)) { + return reject(new TypeError('arguments must be an array')); + } + var resolvedCounter = 0; + var promiseNum = promises.length; + var resolvedValues = new Array(promiseNum); + for (var i = 0; i < promiseNum; i++) { + (function (i) { + Promise.resolve(promises[i]).then(function (value) { + + resolvedCounter++ + resolvedValues[i] = value + if (resolvedCounter == promiseNum) { + return resolve(resolvedValues) + } + }, function (reason) { + return reject(reason) + }) + })(i) + } + }) +} + + +var p1 = Promise.resolve(1).then(res=>{ + console.log('aaaa---',res) + }), + p2 = Promise.resolve(2).then(res=>{ + console.log('aaaa---',res) + }) + p3 = Promise.reject(3).then(res=>{ + console.log('aaaa---',res) + }) + +promiseAll([p1,p2,p3]) \ No newline at end of file diff --git a/webGL/learn/sort.js b/webGL/learn/sort.js new file mode 100644 index 000000000..9ad77a317 --- /dev/null +++ b/webGL/learn/sort.js @@ -0,0 +1,44 @@ + +// 对象数组排序 +const sort = (arr,k1,k2,k3)=>{ + const merge = (left,right)=>{ + let result = []; + while (left.length > 0 && right.length > 0) { + if (left[0][k1] > right[0][k1]) { + result.push(left.shift()); + } else if(left[0][k1] == right[0][k1]){ + if(left[0][k2] > right[0][k2]){ + result.push(left.shift()); + }else if(left[0][k2] == right[0][k2]){ + if(left[0][k3] > right[0][k3]){ + result.push(left.shift()); + }else{ + result.push(right.shift()); + } + }else{ + result.push(right.shift()); + } + } else { + result.push(right.shift()); + } + } + + while (left.length) result.push(left.shift()); + while (right.length) result.push(right.shift()); + + return result; + } + const mergesort = (seq)=>{ + let len = seq.length; + if (len < 2) return seq; + let mid = Math.floor(len / 2); + let left = seq.slice(0, mid); + let right = seq.slice(mid); + + return merge(mergesort(left), mergesort(right)); + } + return mergesort(arr) +} + +const arr = [{a:13,b:3,c:11},{a:13,b:4,c:10},{a:13,b:3,c:10}] +console.log(sort(arr,'a','b','c')); diff --git a/webGL/learn/test.js b/webGL/learn/test.js new file mode 100644 index 000000000..fe06c86d1 --- /dev/null +++ b/webGL/learn/test.js @@ -0,0 +1,23 @@ +let c = Symbol.for('c') +let a = Symbol.for('c') +let obj = { + [Symbol('a')]:'www', + [Symbol.for('b')]:'bbb', + 'a':'aaa', + c:'ccc', + a: 'AAA', + 'a':'aaa2', +} + +console.log(a===c); +console.log(obj['a']); +console.log(obj['a']); +console.log(obj['c']); +console.log(obj[Symbol.keyFor(a)]); + +if (!Number.isNaN) { + Number.isNaN = function isNaN(x) { + return x !== x; + }; +} + diff --git a/webGL/main.js b/webGL/main.js new file mode 100644 index 000000000..e69de29bb diff --git a/webGL/package-lock.json b/webGL/package-lock.json new file mode 100644 index 000000000..9257922da --- /dev/null +++ b/webGL/package-lock.json @@ -0,0 +1,163 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.1.1.tgz", + "dev": true, + "requires": { + "ms": "^2.1.1" + }, + "dependencies": { + "ms": { + "version": "https://registry.npm.taobao.org/ms/download/ms-2.1.2.tgz" + } + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npm.taobao.org/depd/download/depd-1.1.2.tgz", + "dev": true + }, + "http-errors": { + "version": "1.8.0", + "resolved": "https://registry.npm.taobao.org/http-errors/download/http-errors-1.8.0.tgz", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "dependencies": { + "depd": { + "version": "https://registry.npm.taobao.org/depd/download/depd-1.1.2.tgz" + }, + "inherits": { + "version": "https://registry.npm.taobao.org/inherits/download/inherits-2.0.4.tgz" + }, + "setprototypeof": { + "version": "https://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.2.0.tgz" + }, + "statuses": { + "version": "https://registry.npm.taobao.org/statuses/download/statuses-1.5.0.tgz" + }, + "toidentifier": { + "version": "https://registry.npm.taobao.org/toidentifier/download/toidentifier-1.0.0.tgz" + } + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npm.taobao.org/inherits/download/inherits-2.0.4.tgz", + "dev": true + }, + "koa-send": { + "version": "5.0.1", + "resolved": "https://registry.npm.taobao.org/koa-send/download/koa-send-5.0.1.tgz", + "dev": true, + "requires": { + "debug": "^4.1.1", + "http-errors": "^1.7.3", + "resolve-path": "^1.4.0" + }, + "dependencies": { + "debug": { + "version": "https://registry.npm.taobao.org/debug/download/debug-4.1.1.tgz" + }, + "http-errors": { + "version": "https://registry.npm.taobao.org/http-errors/download/http-errors-1.8.0.tgz" + }, + "resolve-path": { + "version": "https://registry.npm.taobao.org/resolve-path/download/resolve-path-1.4.0.tgz" + } + } + }, + "koa-static": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/koa-static/-/koa-static-5.0.0.tgz", + "integrity": "sha512-UqyYyH5YEXaJrf9S8E23GoJFQZXkBVJ9zYYMPGz919MSX1KuvAcycIuS0ci150HCoPf4XQVhQ84Qf8xRPWxFaQ==", + "dev": true, + "requires": { + "debug": "^3.1.0", + "koa-send": "^5.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.2.tgz", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npm.taobao.org/path-is-absolute/download/path-is-absolute-1.0.1.tgz", + "dev": true + }, + "resolve-path": { + "version": "1.4.0", + "resolved": "https://registry.npm.taobao.org/resolve-path/download/resolve-path-1.4.0.tgz", + "dev": true, + "requires": { + "http-errors": "~1.6.2", + "path-is-absolute": "1.0.1" + }, + "dependencies": { + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "path-is-absolute": { + "version": "https://registry.npm.taobao.org/path-is-absolute/download/path-is-absolute-1.0.1.tgz" + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + } + } + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.2.0.tgz", + "dev": true + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npm.taobao.org/statuses/download/statuses-1.5.0.tgz", + "dev": true + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/toidentifier/download/toidentifier-1.0.0.tgz", + "dev": true + } + } +} diff --git a/webGL/package.json b/webGL/package.json new file mode 100644 index 000000000..18e8dccff --- /dev/null +++ b/webGL/package.json @@ -0,0 +1,5 @@ +{ + "devDependencies": { + "koa-static": "^5.0.0" + } +} diff --git a/webGL/server.js b/webGL/server.js new file mode 100644 index 000000000..f27880455 --- /dev/null +++ b/webGL/server.js @@ -0,0 +1,16 @@ +// 导入koa,和koa 1.x不同,在koa2中,我们导入的是一个class,因此用大写的Koa表示: +const Koa = require('koa'); + +// 创建一个Koa对象表示web app本身: +const app = new Koa(); + +// 对于任何请求,app将调用该异步函数处理请求: +app.use(async (ctx, next) => { + await next(); + ctx.response.type = 'text/html'; + ctx.response.body = '

Hello, koa2!

'; +}); + +// 在端口3000监听: +app.listen(3000); +console.log('app started at port 3000...'); \ No newline at end of file diff --git a/webGL/yarn.lock b/webGL/yarn.lock new file mode 100644 index 000000000..fb57ccd13 --- /dev/null +++ b/webGL/yarn.lock @@ -0,0 +1,4 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + diff --git "a/webGL/\345\276\256\344\273\273\345\212\241\345\256\217\344\273\273\345\212\241.md" "b/webGL/\345\276\256\344\273\273\345\212\241\345\256\217\344\273\273\345\212\241.md" new file mode 100644 index 000000000..92aebf03f --- /dev/null +++ "b/webGL/\345\276\256\344\273\273\345\212\241\345\256\217\344\273\273\345\212\241.md" @@ -0,0 +1,43 @@ +```js + +console.log('sync1'); + +setTimeout(function () { + console.log('setTimeout1') +}, 0); + +var promise = new Promise(function (resolve, reject) { + setTimeout(function () { + console.log('setTimeoutPromise') + }, 0); + console.log('promise'); + resolve(); +}); + + +promise.then(() => { + console.log('pro_then'); + setTimeout(() => { + console.log('pro_timeout'); + }, 0) +}) + +setTimeout(function () { + console.log('last_setTimeout') +}, 0); +console.log('sync2'); +``` +宏任务 1 + 微任务 1 + sync 1 + promisesync 2 + 微任务 2 + pro_then +宏任务 2 + setTimeout1 +宏任务 3 + setTimeoutPromise +宏任务 4 + last_setTimeout +宏任务 5 + pro_timeout \ No newline at end of file diff --git a/week01/NOTE.md b/week01/NOTE.md index 50de30414..f176eb01a 100644 --- a/week01/NOTE.md +++ b/week01/NOTE.md @@ -1 +1,45 @@ -学习笔记 \ No newline at end of file +### 学习笔记 + +#### 00 -JS语言通识 +1. 泛用语言分类方法 +2. 什么是产生式 +3. 深入理解产生式 +4. 现代语言的分类 +5. 编程语言的性质 +6. 一般命令式编程语言的设计方式 +#### 01 - JS类型 +7. Number +8. String +9. Boolean Undefind Null Symbio +10. 对象的基础知识 Object +11. JS中的对象 +#### 02 - JS表达式 +1. 运算符和表达式 优先级由大到小》》》 + > ![Atom](/week01/assets/021/02.png) + > ![Atom](/week01/assets/021/01.png) + > ![Atom](/week01/assets/021/03.png) + > ![Atom](/week01/assets/021/04.png) + > ![Atom](/week01/assets/021/05.png) + > ![Atom](/week01/assets/021/06.png) + > ![Atom](/week01/assets/021/07.png) + > ![Atom](/week01/assets/021/08.png) + > ![Atom](/week01/assets/021/09.png) + > ![Atom](/week01/assets/021/10.png) + > ![Atom](/week01/assets/021/11.png) + > ![Atom](/week01/assets/021/12.png) +2. 类型转换 Type Convertion + > ![Atom](/week01/assets/022/01.png) + > ![Atom](/week01/assets/022/02.png) + > ![Atom](/week01/assets/022/03.png) + > ![Atom](/week01/assets/022/04.png) + > ![Atom](/week01/assets/022/05.png) + +#### 02 - JS语句 + +1. 运行时相关概念 + > ![Atom](/week01/assets/023/01.png) + > ![Atom](/week01/assets/023/02.png) +2. 简单语句和复合语句 +3. 声明 +4. 宏任务和微任务 +5. JS函数调用 \ No newline at end of file diff --git a/week01/assets/021/01.png b/week01/assets/021/01.png new file mode 100644 index 000000000..cac026e17 Binary files /dev/null and b/week01/assets/021/01.png differ diff --git a/week01/assets/021/02.png b/week01/assets/021/02.png new file mode 100644 index 000000000..aa3c18286 Binary files /dev/null and b/week01/assets/021/02.png differ diff --git a/week01/assets/021/03.png b/week01/assets/021/03.png new file mode 100644 index 000000000..4f0b01090 Binary files /dev/null and b/week01/assets/021/03.png differ diff --git a/week01/assets/021/04.png b/week01/assets/021/04.png new file mode 100644 index 000000000..f830d9a7c Binary files /dev/null and b/week01/assets/021/04.png differ diff --git a/week01/assets/021/05.png b/week01/assets/021/05.png new file mode 100644 index 000000000..2cdef503f Binary files /dev/null and b/week01/assets/021/05.png differ diff --git a/week01/assets/021/06.png b/week01/assets/021/06.png new file mode 100644 index 000000000..f22c0a3d5 Binary files /dev/null and b/week01/assets/021/06.png differ diff --git a/week01/assets/021/07.png b/week01/assets/021/07.png new file mode 100644 index 000000000..05d0e3ec3 Binary files /dev/null and b/week01/assets/021/07.png differ diff --git a/week01/assets/021/08.png b/week01/assets/021/08.png new file mode 100644 index 000000000..0610d2098 Binary files /dev/null and b/week01/assets/021/08.png differ diff --git a/week01/assets/021/09.png b/week01/assets/021/09.png new file mode 100644 index 000000000..cebdad5a1 Binary files /dev/null and b/week01/assets/021/09.png differ diff --git a/week01/assets/021/10.png b/week01/assets/021/10.png new file mode 100644 index 000000000..e696b8839 Binary files /dev/null and b/week01/assets/021/10.png differ diff --git a/week01/assets/021/11.png b/week01/assets/021/11.png new file mode 100644 index 000000000..a2c943631 Binary files /dev/null and b/week01/assets/021/11.png differ diff --git a/week01/assets/021/12.png b/week01/assets/021/12.png new file mode 100644 index 000000000..14a9fe72c Binary files /dev/null and b/week01/assets/021/12.png differ diff --git a/week01/assets/022/01.png b/week01/assets/022/01.png new file mode 100644 index 000000000..9bf992bb3 Binary files /dev/null and b/week01/assets/022/01.png differ diff --git a/week01/assets/022/02.png b/week01/assets/022/02.png new file mode 100644 index 000000000..9635a2e54 Binary files /dev/null and b/week01/assets/022/02.png differ diff --git a/week01/assets/022/03.png b/week01/assets/022/03.png new file mode 100644 index 000000000..ab8d03531 Binary files /dev/null and b/week01/assets/022/03.png differ diff --git a/week01/assets/022/04.png b/week01/assets/022/04.png new file mode 100644 index 000000000..fffa3c699 Binary files /dev/null and b/week01/assets/022/04.png differ diff --git a/week01/assets/022/05.png b/week01/assets/022/05.png new file mode 100644 index 000000000..270368dc1 Binary files /dev/null and b/week01/assets/022/05.png differ diff --git a/week01/assets/023/01.png b/week01/assets/023/01.png new file mode 100644 index 000000000..50e07e30a Binary files /dev/null and b/week01/assets/023/01.png differ diff --git a/week01/assets/023/02.png b/week01/assets/023/02.png new file mode 100644 index 000000000..f8163f2c8 Binary files /dev/null and b/week01/assets/023/02.png differ diff --git a/week01/assets/023/03.png b/week01/assets/023/03.png new file mode 100644 index 000000000..91da18574 Binary files /dev/null and b/week01/assets/023/03.png differ diff --git "a/week01/\345\211\215\347\253\257\346\212\200\346\234\257.png" "b/week01/\345\211\215\347\253\257\346\212\200\346\234\257.png" new file mode 100644 index 000000000..e5b844a37 Binary files /dev/null and "b/week01/\345\211\215\347\253\257\346\212\200\346\234\257.png" differ diff --git "a/week01/\345\211\215\347\253\257\346\212\200\346\234\257.xmind" "b/week01/\345\211\215\347\253\257\346\212\200\346\234\257.xmind" new file mode 100644 index 000000000..7313409d1 Binary files /dev/null and "b/week01/\345\211\215\347\253\257\346\212\200\346\234\257.xmind" differ diff --git "a/week01/\345\211\215\347\253\257\346\212\200\346\234\257_282_Week01.xmind" "b/week01/\345\211\215\347\253\257\346\212\200\346\234\257_282_Week01.xmind" new file mode 100644 index 000000000..165af2644 Binary files /dev/null and "b/week01/\345\211\215\347\253\257\346\212\200\346\234\257_282_Week01.xmind" differ diff --git a/week02/001.jpg b/week02/001.jpg new file mode 100644 index 000000000..36013a4e1 Binary files /dev/null and b/week02/001.jpg differ diff --git a/week02/001.js b/week02/001.js new file mode 100644 index 000000000..525c6e1b7 --- /dev/null +++ b/week02/001.js @@ -0,0 +1,63 @@ +function match (str){ + let state = start + for(let c of str){ + state = start(c) + } + return state==end + } + + function start(c) { + if(c ==='a'){ + return foundA + }else{ + return start(c) + } + } + + function end() { + return end + } + + function foundA(c){ + if(c ==='b'){ + return foundB + }else{ + return start(c) + } + } + + function foundB(c){ + if(c==='c'){ + return foundC + }else{ + return start(c) + } + } + + function foundC(c){ + if(c==='a'){ + return foundA2 + }else{ + return start(c) + } + } + + function foundA2(c){ + if(c==='b'){ + return foundB2 + }else{ + return start(c) + } + } + + function founB2 (c){ + if(c === 'x'){ + return end + }else{ + return foundB(c) + } + } + + console.log(match('abcabcabx')) + + //reconsume 重组技巧 \ No newline at end of file diff --git a/week02/002.js b/week02/002.js new file mode 100644 index 000000000..f09bb1b4f --- /dev/null +++ b/week02/002.js @@ -0,0 +1,72 @@ + +// ### 数组去重 +// const Uniq =(arr = []) => { +// return arr.reduce((t, v) => t.includes(v) ? t : [...t, v], []); +// } + +// console.log(Uniq([1,2,3,3])); + +//### 累加数组 例如 [1,2,3,3] 》 [1, 3, 6, 10] + +const runningSum = (nums=[]) => { + + + return nums.reduce((t,v,index) =>[...t, v+t[index]] ,[0]).slice(1) + + // return nums.reduce((t,v,index) =>[...t, v+t[index]] ,[0]) + // return nums.reduce((t,v) =>t.length> 0 ? [...t, v+t[t.length-1]] : [v] ,[]) +} +// console.log(runningSum([1,2,3,4])); + + +const maxSubArray =(nums=[]) =>{ + let sum1 = nums.reduce((t, v) =>t+v,0) + let flag = true + while(flag){ + if(nums.length===0){ + flag = false; + break + } + let arr2 = [...[],...nums] + arr2.shift() + let sum2 = arr2.reduce((t, v) =>t+v,0) + let arr3 = [...[],...nums] + arr3.pop() + let sum3 = arr3.reduce((t, v) =>t+v,0) + + if(sum3>sum1){ + sum1 = sum3 + if(sum3>sum2){ + nums.pop() + }else{ + nums.shift() + } + }else{ + if(sum2>sum1){ + sum1 = sum2 + nums.shift() + }else{ + nums.pop() + } + } + } + return sum1 +}; + +console.log(maxSubArray([-2,1,-3,4,-1,2,1,-5,4])); + +// const getMostMoney = (nums=[]) => { + +// return +// } + +// const getMostMoney = (List) => { +// let mostMoney = 0 + +// for(let i = List.length; i>0;i--){ +// mostMoney += List[i] + +// } + + +// } \ No newline at end of file diff --git a/week02/01.js b/week02/01.js new file mode 100644 index 000000000..019ef5522 --- /dev/null +++ b/week02/01.js @@ -0,0 +1,23 @@ +//用状态机实现:字符串“abcabx”的解析 + +const match = (str) => { + let state = start + for(let c of str){ + state = state(c) + } + return state === end + } + + const start = c => c ==='a'? foundA:start + const end = () => end + const foundA = c => c ==='b'? foundB : start(c) + const foundB = c => c ==='c'? foundC : start(c) + const foundC = c => c ==='a'? foundA2 : start(c) + const foundA2 = c => c ==='b'? foundB2 : start(c) + const foundB2 = c => c === 'x'? end : foundB(c) + + console.log(match('abcabcabx')) + console.log(match('abcaabcabx')) + console.log(match('abcaabbcabx')) + + //reconsume 重组技巧 diff --git a/week02/02.js b/week02/02.js new file mode 100644 index 000000000..55923a3c2 --- /dev/null +++ b/week02/02.js @@ -0,0 +1,25 @@ +// 使用状态机完成”abababx”的处理 + +const match = (str) => { + let state = start + for(let c of str){ + state = state(c) + } + return state === end + } + + const start = c => c ==='a'? foundA:start + const end = () => end + const foundA = c => c ==='b'? foundB : start(c) + const foundB = c => c ==='a'? foundA2 : start(c) + const foundA2 = c => c ==='b'? foundB2 : start(c) + const foundB2 = c => c ==='a'? foundA3 : start(c) + const foundA3 = c => c ==='b'? foundX : start(c) + const foundX = c => c === 'x'? end : foundB2(c) + + console.log(match('ababababx')) + console.log(match('abaaabababx')) + console.log(match('abababaabababx')) + console.log(match('abababaabaababx')) + + //reconsume 重组技巧 diff --git a/week02/NOTE.md b/week02/NOTE.md index 50de30414..3977bbede 100644 --- a/week02/NOTE.md +++ b/week02/NOTE.md @@ -1 +1,110 @@ -学习笔记 \ No newline at end of file +学习笔记 + +### 有限状态机 +每一个状态都是一个机器 +每一个机器知道下一个状态 + +### 用状态机实现:字符串“abcabx”的解析 +```js +const match = (str) => { + let state = start + for(let c of str){ + state = state(c) + } + return state === end + } + + const start = c => c ==='a'? foundA:start + const end = () => end + const foundA = c => c ==='b'? foundB : start(c) + const foundB = c => c ==='c'? foundC : start(c) + const foundC = c => c ==='a'? foundA2 : start(c) + const foundA2 = c => c ==='b'? foundB2 : start(c) + const foundB2 = c => c === 'x'? end : foundB(c) + + console.log(match('abcabcabx')) + console.log(match('abcaabcabx')) + console.log(match('abcaabbcabx')) +``` + ### 用状态机实现:字符串“abababx”的解析 +```js +const match = (str) => { + let state = start + for(let c of str){ + state = state(c) + } + return state === end + } + + const start = c => c ==='a'? foundA:start + const end = () => end + const foundA = c => c ==='b'? foundB : start(c) + const foundB = c => c ==='a'? foundA2 : start(c) + const foundA2 = c => c ==='b'? foundB2 : start(c) + const foundB2 = c => c ==='a'? foundA3 : start(c) + const foundA3 = c => c ==='b'? foundX : start(c) + const foundX = c => c === 'x'? end : foundB2(c) + + console.log(match('ababababx')) + console.log(match('abaaabababx')) + console.log(match('abababaabababx')) + console.log(match('abababaabaababx')) + //reconsume 重组技巧 + ``` +KMP资料阅读,按照JAVA版的改了下没有实现 ,js Class语法不熟悉 需要加强训练。 + +### HTTP请求 +#### HTTP协议解析 +#### 服务端环境准备 +#### 实现一个HTTP请求 +#### send函数编写了解response格式 +#### 发送请求 +#### response解析 + + +#### 浏览器架构图 +```mermaid +graph TD +A[URL] -->|HTTP| B(HTML) +B -->|parse| C(DOM) +C -->|css computing| D(DOM with CSS) +D -->|layout| E(DOM with position) +E -->|render| F(Bitmap) +``` +### 第一步 HTTP请求总结 + +- 设计一个HTTP请求的类 +- content type 是一个毕业的字段,要有默认值 +- body是KV格式 +- 不同的content-type影响body的格式 + +### 第二步 send函数总结 + +- 在Request的构造器中收集必要的信息 +- 设计一个send函数,把请求真实的发送到服务器 +- send函数应是异步的,所以要返回Promise + +> http 请求格式 +![](001.jpg) + + +### 第三步 发送请求 + +- 设计支持已有的connection或者自己新建connection +- 收到数据传给parser +- 根据parser的状态resolve Promise + +### 第四步 ResponseParser状态机总结 + +- Response必须分段构造,所以我们要用一个ResponseParser来“装配” +- ResponseParser分段处理ResponseText,我们用状态机来分析文本的结构 + +### 第四步 ResponseParser状态机总结 + +- Response必须分段构造,所以我们要用一个ResponseParser来“装配” +- ResponseParser分段处理ResponseText,我们用状态机来分析文本的结构 + +### 第五步 BodyParser状态机总结 + +- Response的body可能根据Content-Type有不同的结构,因此我们会采用子Parser的结构来解决问题 +- 以TrunkedBodyParser为例,我们同样用状态机来处理body的格式 diff --git a/week02/StateMachine.js b/week02/StateMachine.js new file mode 100644 index 000000000..56193aab8 --- /dev/null +++ b/week02/StateMachine.js @@ -0,0 +1,28 @@ +const match = (string) => { + let state = start + for (let c of string) { + state = state(c) + } + return state === end +} +const start =(c) => c === 'a' ? foundA : start +const end = (c) => end +const foundA = (c) => c === "b" ? foundB : start(c) +const foundB = (c) => c === "a" ? foundA2 : foundA +const foundA2 = (c) => c === "b" ? foundB2 : start(c) +const foundB2 = (c) => c === "a" ? foundA3 : foundA2 +const foundA3 = (c) => c === "b" ? foundB3 : start(c) +const foundB3 = (c) => c === "x" ? end : foundB2(c) + +// test +console.log(match("abababx")); +console.log(match("ababababx")); +console.log(match("abababababx")); +console.log(match("abababababababx")); +console.log(match("ababababababx")); +console.log(match("ababacabababx")); +console.log(match("ababaabababx")); +console.log(match("ababaababx")); +console.log(match("ababaababx")); +console.log(match("ababacbabx")); +console.log(match("ababaaabababbabababx")); diff --git a/week02/clint.js b/week02/clint.js new file mode 100644 index 000000000..7483e233e --- /dev/null +++ b/week02/clint.js @@ -0,0 +1,214 @@ + +const net = require('net') +const parser = require('./parser') + +class Request{ + constructor(options){ + this.method = options.method || "GET" + this.host = options.host + this.port = options.port || "8080" + this.path = options.path || "/" + this.headers = options.headers || {} + this.body = options.body || {} + if(!this.headers["content-type"]){ + this.headers["content-type"]="application/x-www-form-urlenconded" + } + if(this.headers["content-type"]==="application/json"){ + this.bodyText=JSON.stringify(this.body) + }else if(this.headers["content-type"]="application/x-www-form-urlenconded"){ + this.bodyText=Object.keys(this.body).map(key=>`${key}=${encodeURIComponent(this.body[key])}`).join('&') + } + this.headers["content-length"]=this.bodyText.length + } + send(connection){ + return new Promise((resolve,reject)=>{ + const parser = new ResponseParser; + if(connection){ + connection.write(this.toString()) + }else{ + connection = net.createConnection({ + host:this.host, + port:this.port + },()=>{ + connection.write(this.toString()) + }) + } + //监听 data + connection.on('data',(data)=>{ + console.log(data.toString()); + parser.receive(data.toString()) + if(parser.isFinshed){ + resolve(parser.response) + connection.end() + } + }) + connection.on('error',(err)=>{ + reject(err) + connection.end + }) + }) + } + toString(){ + return `${this.method} ${this.path} HTTP1.1\r + ${Object.keys(this.headers).map(key=>{ `${key}: ${this.headers[key]}`}).join('\r\n')} \r + \r + ${this.bodyText}` + } +} + +class ResponseParser{ + constructor(){ + this.WAITING_STATUS_LINE = 0 + this.WAITING_STATUS_LINE_END = 1 + this.WAITING_HEADER_NAME = 2 + this.WAITING_HEADER_SPACE = 3 + this.WAITING_HEADER_VALUE = 4 + this.WAITING_HEADER_LINE_END = 5 + this.WAITING_HEADER_BLOCK_END = 6 + this.WAITING_BODY = 7 + + this.current = this.WAITING_STATUS_LINE + this.statusLine="" + this.headers= {} + this.headerName = "" + this.headerValue = "" + this.bodyParser = null + } + get isFinshed(){ + return this.bodyParser && this.bodyParser.isFinshed + } + get response(){ + this.statusLine.match(/HTTP\/1.1 ([0-9]+)([\s\S]+)/) + return { + statusCode: RegExp.$1, + statusText: RegExp.$2, + headers: this.headers, + body: this.bodyParser.content.join(''), + } + } + receive(string){ + for(let i = 0;i{ +// for(let c,i of haystack){ +// kmp(needle,c) +// } +// } +// const kmp = (needle,c)=>{ +// for(let c2,ind of needle){ +// if(c===c2){ +// k = ind +// } +// } +// } +// }; + + +class Stt { + constructor(haystack, needle){ + this.ind = 0 + this.index = 0 + this.haystack = haystack + this.needle = needle + this.isF = false + } + kmp(c){ + // console.log(this.ind); + if(this.ind===this.needle.length-1) this.isF = true + for(let i = this.ind; i { + let body =[] + request.on('error',(err)=>{ + console.error(err); + }).on('data',(chunk)=>{ + body.push(chunk.toString()) + }).on('end',()=>{ + body.Buffer.contact(body).toString() + console.log('body',body); + response.writeHead(200,{'content-type':'text/html'}) + response.end('hello server \n') + }) +}).listen(8089) +console.log('serve started'); diff --git a/week03/NOTE.md b/week03/NOTE.md index 50de30414..5b7f74b81 100644 --- a/week03/NOTE.md +++ b/week03/NOTE.md @@ -1 +1,80 @@ -学习笔记 \ No newline at end of file + +### 根据使用创建接口 + +#### 浏览器架构图 +```mermaid +graph TD +A[URL] -->|HTTP| B(HTML) +B -->|parse| C(DOM) +C -->|css computing| D(DOM with CSS) +D -->|layout| E(DOM with position) +E -->|render| F(Bitmap) +``` + +# 构建DOM树 + +### 第一步总结 +- 为了方便文件管理,把parser单独拆到文件中 +- parser接收HTML文本作为参数,返回一棵DOM树🌲(老师的PPT单位(颗)写错了) + +### 第二步总结 +- 我们用FSM来实现HTML的分析 +- 在HTML标准中,已经规定了HTML的状态 +- Toy-Browser只挑选其中的一部分状态完成一个最简版本 + +### 第三步总结 +- 主要的标签有:开始标签,结束标签和自封闭标签 +- 这一步我们暂时忽略属性 + +### 第四步总结 +- 在状态机中,除了状态迁移,我们还会要加入业务逻辑 +- 我们在标签结束状态提交标签token + +### 第五步总结 +- 处理属性分为单引号、双引号、无引号三种写法,因此需要较多状态处理 +- 处理属性的方式跟标签类似 +- 属性结束时,我们把属性加到标签Token上 + +### 第六步总结 +- 从标签构建DOM树的基本技巧是使用栈 +- 遇到开始标签时创建元素并入栈,遇到结束标签时出栈 +- 自封闭节点可视为入栈后立刻出栈 +- 任何元素的父元素是他入栈前的栈顶 + +### 第七步总结 +- 文本节点与自封闭标签处理雷士 +- 多个文本节点需要合并 + +# DOM的渲染 CSS规则 + +### 第一步总结 +- 遇到style标签时,我们把CSS规则保存起来 +- 这里我们调用CSS Parser来分析CSS规则 +- 这里我们必须要仔细研究此库分析CSS规则的格式 + +### 第二步总结 +- 当我们创建一个元素后,立即计算CSS +- 理论上,当我们分析一个元素时,所有CSS规则已经收集完毕 +- 在真实浏览器中,可能遇到写在body的style标签,需要重新CSS计算的情况,这里我们忽略 + +### 第三步总结 +- 在computeCSS函数中,我们必须知道元素的所有父元素才能判断元素与规则是否匹配 +- 我们从上一步骤的stack,可以获取本元素所有的父元素 +- 因为我们首先获取的是“当前元素”,所以我们获得和计算父元素匹配的顺序是从内向外 + +### 第四步总结 +- 选择器也要从当前元素向外排列 +- 复杂选择器拆分针对单个元素的选择器,用循环匹配父元素队列 + +### 第五步总结 +- 根据选择器的类型和元素属性,计算是否与当前元素匹配 +- 这里仅仅实现了三种基本选择器,实际的浏览器中要处理复合选择器 +- 作业实现复合选择器,实现支持空格的Class选择器 + +### 第六步总结 +- 一旦选择匹配,就应用选择器到元素上,形成computedStyle + +### 第七步总结 +- CSS规则根据specificity和后来优先规则覆盖 +- specificity是个四元组,越左边权重越高 +- 一个CSS规则的specificity根据包含的简单选择器相加而成 \ No newline at end of file diff --git a/week03/clint.js b/week03/clint.js new file mode 100644 index 000000000..862a81c6f --- /dev/null +++ b/week03/clint.js @@ -0,0 +1,221 @@ + +const net = require('net') +const parser = require('./parser') + +class Request{ + constructor(options){ + this.method = options.method || "GET" + this.host = options.host + this.port = options.port || "8080" + this.path = options.path || "/" + this.headers = options.headers || {} + this.body = options.body || {} + if(!this.headers["content-type"]){ + this.headers["content-type"]="application/x-www-form-urlenconded" + } + if(this.headers["content-type"]==="application/json"){ + this.bodyText=JSON.stringify(this.body) + }else if(this.headers["content-type"]="application/x-www-form-urlenconded"){ + this.bodyText=Object.keys(this.body).map(key=>`${key}=${encodeURIComponent(this.body[key])}`).join('&') + } + this.headers["content-length"]=this.bodyText.length + } + send(connection){ + return new Promise((resolve,reject)=>{ + const parser = new ResponseParser() + if(connection){ + connection.write(this.toString()) + }else{ + connection = net.createConnection({ + host:this.host, + port:this.port + },()=>{ + connection.write(this.toString()) + }) + } + //监听 data + connection.on('data', (data) => { + console.log('connection.on',data.toString(), parser, connection.on('data')) + console.log('connection.on', data.toString()); + parser.receive(data.toString()) + if(parser.isFinshed){ + resolve(parser.response) + connection.end() + } + }) + connection.on('error',(err)=>{ + reject(err) + connection.end + }) + }) + } + toString(){ + return `${this.method} ${this.path} HTTP1.1\r +${Object.keys(this.headers).map(key =>`${key}: ${this.headers[key]}`).join('\r\n')}\r +\r +${this.bodyText}` + } +} + +class ResponseParser { + constructor(){ + this.WAITING_STATUS_LINE = 0 + this.WAITING_STATUS_LINE_END = 1 + this.WAITING_HEADER_NAME = 2 + this.WAITING_HEADER_SPACE = 3 + this.WAITING_HEADER_VALUE = 4 + this.WAITING_HEADER_LINE_END = 5 + this.WAITING_HEADER_BLOCK_END = 6 + this.WAITING_BODY = 7 + + this.current = this.WAITING_STATUS_LINE + this.statusLine="" + this.headers= {} + this.headerName = "" + this.headerValue = "" + this.bodyParser = null + } + get isFinshed(){ + return this.bodyParser && this.bodyParser.isFinshed + } + get response(){ + this.statusLine.match(/HTTP\/1.1 ([0-9]+)([\s\S]+)/) + return { + statusCode: RegExp.$1, + statusText: RegExp.$2, + headers: this.headers, + body: this.bodyParser.content.join(''), + } + } + receive(string){ + for(let i = 0;i { + let body =[] + request.on('error',(err)=>{ + console.error(err); + }).on('data',(chunk)=>{ + body.push(chunk.toString()) + }).on('end',()=>{ + body.Buffer.contact(body).toString() + console.log('body',body); + response.writeHead(200,{'content-type':'text/html'}) + response.end('hello server \n') + }) +}).listen(8088) + +console.log('serve started'); diff --git a/week03/test1.js b/week03/test1.js new file mode 100644 index 000000000..23b95eb9c --- /dev/null +++ b/week03/test1.js @@ -0,0 +1,38 @@ + +class StrStr{ + constructor(haystack,needle){ + this.haystack = haystack + this.needle = needle + } + match() { + if(this.needle.length===0) return false + let state = this.start + for(let c of this.haystack){ + state = this.state(c) + } + return state === this.end + } + start(c){return c==='a'?true:false} + end(c){ return this.end } + foundA(c){return this.end} + +} + +let o = new StrStr('ababab','a') +console.log(o.match()); + + +class Point { + constructor(x, y) { + this.x = x; + this.y = y; + } + + toString() { + return '(' + this.x + ', ' + this.y + ')'; + } + } + +let o2 = new Point('x','y') +console.log(o2.toString()); + diff --git a/week04/NOTE.md b/week04/NOTE.md index 50de30414..7fcef7062 100644 --- a/week04/NOTE.md +++ b/week04/NOTE.md @@ -1 +1,42 @@ -学习笔记 \ No newline at end of file +学习笔记 +浏览器架构 +#### 浏览器架构图 +```mermaid +graph TD +A[URL] -->|HTTP| B(HTML) +B -->|parse| C(DOM) +C -->|css computing| D(DOM with CSS) +D -->|layout| E(DOM with position) +E -->|render| F(Bitmap) +``` + +### 第一步 排版-根据浏览器属性进行排版(FLEX) +> 三代排版技术 +> 1.古典 2.flex 3.grid 4.CSS Houdini + + +- 采用flex布局 +- +### 第二步 排版-收集元素 + +- 设计一个HTTP请求的类 +- content type 是一个毕业的字段,要有默认值 +- body是KV格式 +- 不同的content-type影响body的格式 + +### 第三步 排版-计算主轴 + +### 第四步 排版-计算交叉轴 + +### 第五步 渲染-绘制单个元素 + +- 绘制需要依赖一个图形环境 +- 采用了npm包的images +- 绘制在一个viewport上进行 +- 与绘制相关的属性 background-color、border、background-image等 +### 第六步 渲染-绘制DOM树 +![450e948cab5f46333a972e4791fad910.png](evernotecid://2393A90F-1FE0-42B1-A655-82D09E31A7AF/appyinxiangcom/307379/ENResource/p4502) +- 递归调用子元素方法完成DOM树的绘制 +- 忽略一些不需要绘制的节点 +- 实际浏览器中,文字绘制是难点,需要依赖字体库 +- 实际浏览器中,还会对一些土城做compositing \ No newline at end of file diff --git a/week04/toyBrowser/clint.js b/week04/toyBrowser/clint.js new file mode 100644 index 000000000..e15f21fd6 --- /dev/null +++ b/week04/toyBrowser/clint.js @@ -0,0 +1,227 @@ + +const net = require('net'); +const parser = require('./parser'); +const images = require('images'); +const render = require('./render.js'); + +class Request{ + constructor(options){ + this.method = options.method || "GET" + this.host = options.host + this.port = options.port || "8080" + this.path = options.path || "/" + this.headers = options.headers || {} + this.body = options.body || {} + if(!this.headers["content-type"]){ + this.headers["content-type"]="application/x-www-form-urlenconded" + } + if(this.headers["content-type"]==="application/json"){ + this.bodyText=JSON.stringify(this.body) + }else if(this.headers["content-type"]="application/x-www-form-urlenconded"){ + this.bodyText=Object.keys(this.body).map(key=>`${key}=${encodeURIComponent(this.body[key])}`).join('&') + } + this.headers["content-length"]=this.bodyText.length + } + send(connection){ + return new Promise((resolve,reject)=>{ + const parser = new ResponseParser() + if(connection){ + connection.write(this.toString()) + }else{ + connection = net.createConnection({ + host:this.host, + port:this.port + },()=>{ + connection.write(this.toString()) + }) + } + //监听 data + connection.on('data', (data) => { + console.log('connection.on',data.toString(), parser, connection.on('data')) + console.log('connection.on', data.toString()); + parser.receive(data.toString()) + if(parser.isFinshed){ + resolve(parser.response) + connection.end() + } + }) + connection.on('error',(err)=>{ + reject(err) + connection.end + }) + }) + } + toString(){ + return `${this.method} ${this.path} HTTP1.1\r +${Object.keys(this.headers).map(key =>`${key}: ${this.headers[key]}`).join('\r\n')}\r +\r +${this.bodyText}` + } +} + +class ResponseParser { + constructor(){ + this.WAITING_STATUS_LINE = 0 + this.WAITING_STATUS_LINE_END = 1 + this.WAITING_HEADER_NAME = 2 + this.WAITING_HEADER_SPACE = 3 + this.WAITING_HEADER_VALUE = 4 + this.WAITING_HEADER_LINE_END = 5 + this.WAITING_HEADER_BLOCK_END = 6 + this.WAITING_BODY = 7 + + this.current = this.WAITING_STATUS_LINE + this.statusLine="" + this.headers= {} + this.headerName = "" + this.headerValue = "" + this.bodyParser = null + } + get isFinshed(){ + return this.bodyParser && this.bodyParser.isFinshed + } + get response(){ + this.statusLine.match(/HTTP\/1.1 ([0-9]+)([\s\S]+)/) + return { + statusCode: RegExp.$1, + statusText: RegExp.$2, + headers: this.headers, + body: this.bodyParser.content.join(''), + } + } + receive(string){ + for(let i = 0;i e.type === "element"); + items.sort((a, b) => { + return (a.order || 0) - (b.order || 0); + }); + + var style = elementStyle; + + ["width", "height"].forEach(size => { + if (style[size] === 'auto' || style[size] === '') { + style[size] = null; + } + }); + + if (!style.flexDirection || style.flexDirection === "auto") { + style.flexDirection = 'row'; + } + if (!style.alignItems || style.alignItems === "auto") { + style.alignItems = 'stretch'; + } + if (!style.justifyContent || style.justifyContent === "auto") { + style.justifyContent = 'flex-start'; + } + if (!style.flexWrap || style.flexWrap === "auto") { + style.flexWrap = 'nowrap'; + } + if (!style.alignContent || style.alignContent === "auto") { + style.alignContent = 'stretch'; + } + + var mainSize, mainStart, mainEnd, mainSign, mainBase, + crossSize, crossStart, crossEnd, crossSign, crossBase; + if (style.flexDirection === "row") { + mainSize = "width"; + mainStart = "left"; + mainEnd = "right"; + + //属性相减时作用 + mainSign = +1; + //start from right or left + mainBase = 0; + + crossSize = "height"; + crossStart = "top"; + crossEnd = "bottom"; + } + else if (style.flexDirection === "row-reverse") { + mainSize = "width"; + mainStart = "right"; + mainEnd = "left"; + + //属性相减时作用 + mainSign = -1; + //start from right or left + mainBase = style.width; + + crossSize = "height"; + crossStart = "top"; + crossEnd = "bottom"; + } + else if (style.flexDirection === "column") { + mainSize = "height"; + mainStart = "top"; + mainEnd = "bottom"; + + mainSign = +1; + mainBase = 0; + + crossSize = "width"; + crossStart = "left"; + crossEnd = "right"; + } + else if (style.flexDirection === "column-reverse") { + mainSize = "height"; + mainStart = "bottom"; + mainEnd = "top"; + + mainSign = -1; + mainBase = style.height; + + crossSize = "width"; + crossStart = "left"; + crossEnd = "right"; + } + + if (style.flexWrap === "wrap-reverse") { + let tmp = crossStart; + crossStart = crossEnd; + crossEnd = tmp; + crossSign = -1; + } + else { + crossBase = 0; + crossSign = 1; + } + + //parent element does not set the width/height of the main axis + var isAutoMainSize = false; + if (!style[mainSize]) { //auto sizing + elementStyle[mainSize] = 0; + for (let i = 0; i < items.length; ++i) { + var item = items[i]; + var itemStyle = getStyle(item); + if (itemStyle[mainSize] !== null || itemStyle[mainSize] !== (void 0)) { + elementStyle[mainSize] = elementStyle[mainSize] + itemStyle[mainSize]; + } + } + } + isAutoMainSize = true; + + // 元素分行 + var flexLine = []; + var flexLines = [flexLine]; + + //剩余空间 + var mainSpace = elementStyle[mainSize]; + var crossSpace = 0; + + for (let i = 0; i < items.length; ++i) { + var item = items[i]; + var itemStyle = getStyle(item); + + if (itemStyle[mainSize] === null) { + itemStyle[mainSize] = 0; + } + + //有flex属性,可伸缩 + if (itemStyle.flex) { + flexLine.push(item); + } + else if (itemStyle.flexWrap === "nowrap" && isAutoMainSize) { + mainSpace -= itemStyle[mainSize] ; + if (itemStyle[crossSize] !== null && itemStyle[crossSize] !== (void 0)) { + //the highest element in the line + crossSpace = Math.max(crossSpace, itemStyle[crossSize]); + } + flexLine.push(item); + } + else { + // child element main size > parent ... + if (itemStyle[mainSize] > style[mainSize]) { + itemStyle[mainSize] = style[mainSize]; + } + // cannot be inserted + if (mainSpace < itemStyle[mainSize]) { + flexLine.mainSpace = mainSpace; + flexLine.crossSpace = crossSpace; + flexLine = [item]; + flexLines.push(flexLine); + mainSpace = style[mainSize]; + crossSpace = 0; + } + else { + flexLine.push(item); + } + mainSpace -= itemStyle[mainSize]; + if (itemStyle[crossSize] !== null && itemStyle[crossSize] !== (void 0)) { + //the highest element in the line + crossSpace = Math.max(crossSpace, itemStyle[crossSize]); + } + } + } + + //calculation of main axis + flexLine.mainSpace = mainSpace; + if (style.flexWrap === 'nowrap' || isAutoMainSize) { + flexLine.crossSpace = (style[crossSize] !== (void 0)) ? style[crossSize] : crossSpace; + } + else { + flexLine.crossSpace = crossSpace; + } + // mainspace the margin left + if (mainSpace < 0) { + // overflow (happens only if container is single line), scale down every item + // compression by scale + var scale = style[mainSize] / (style[mainSize] - mainSpace); + var currentMain = mainBase; + for (var i = 0; i < items.length; ++i) { + var item = items[i]; + var itemStyle = getStyle(item); + + // set flex to 0 + if (itemStyle.flex) { + itemStyle[mainSize] = 0; + } + + itemStyle[mainSize] *= scale; + itemStyle[mainStart] = currentMain; + itemStyle[mainEnd] = itemStyle[mainStart] + mainSign * itemStyle[mainSize]; + currentMain = itemStyle[mainEnd]; + } + } + else { + flexLines.forEach(function (items) { + var mainSpace = items.mainSpace; + var flexTotal = 0; + + //find all elements with flex + for (var i = 0; i < items.length; ++i) { + var item = items[i]; + var itemStyle = getStyle(item); + + if (itemStyle.flex !== null && (itemStyle.flex !== (void 0))) { + flexTotal += itemStyle.flex; + continue; + } + } + + if (flexTotal > 0) { + var currentMain = mainBase; + for (var i = 0; i < items.length; ++i) { + var item = items[i]; + var itemStyle = getStyle(item); + if (itemStyle.flex) { + itemStyle[mainSize] = (mainSpace / flexTotal) * itemStyle.flex; + } + + itemStyle[mainStart] = currentMain; + itemStyle[mainEnd] = itemStyle[mainStart] + mainSign * itemStyle[mainSize]; + currentMain = itemStyle[mainEnd]; + } + } + // justify content + // since there is no flex items, justify content should work + else { + if (style.justifyContent === "flex-start") { + var currentMain = mainBase; + var step = 0; + } + if (style.justifyContent === "flex-end") { + var currentMain = mainSpace * mainSign + mainBase; + var step = 0; + } + if (style.justifyContent === "center") { + var currentMain = mainSpace / 2 * mainSign + mainBase; + var step = 0; + } + if (style.justifyContent === "space-between") { + var step = mainSpace / (items.length - 1) * mainSign; + var currentMain = mainBase; + } + if (style.justifyContent === "space-around") { + var step = mainSpace / items.length * mainSign; + var currentMain = step / 2 + mainBase; + } + + + for (let i = 0; i < items.length; ++i) { + var item = items[i]; + itemStyle[mainStart] = currentMain; + itemStyle[mainEnd] = itemStyle[mainStart] + mainSign * itemStyle[mainSize]; + currentMain = itemStyle[mainEnd] + step; + } + } + }); + } + + // calculation of cross axis + // align-items, align-self + var crossSpace; + //check if cross space of parent element has been filled + if (!style[crossSize]) { + crossSpace = 0; + elementStyle[crossSize] = 0; + for (let i = 0; i < flexLines.length; ++i) { + elementStyle[crossSize] += flexLines[i].crossSpace; + } + } + else { + crossSpace = style[crossSize]; + for (let i = 0; i < flexLines.length; ++i) { + crossSpace -= flexLines[i].crossSpace; + } + } + + if (style.flexWrap === "wrap-reverse") { + crossBase = sytle[crossSize]; + } + else { + crossBase = 0; + } + + + var lineSize = style[crossSize] / flexLines.length; + var step; + if (style.alignContent === "flex-start") { + crossBase += 0; + step = 0; + } + if (style.alignContent === "flex-end") { + crossBase += crossSpace * crossSign; + step = 0; + } + if (style.alignContent === "center") { + crossBase += crossSpace / 2 * crossSign; + step = 0; + } + if (style.alignContent === "space-between") { + step = crossSpace / (flexLines.length - 1); + crossBase += 0; + } + if (style.alignContent === "space-around") { + step = crossSpace / (flexLines.length); + crossSpace += crossSign * step / 2; + } + if (style.alignContent === "stretch") { + step = 0; + crossSpace += 0; + } + + flexLines.forEach(function (items) { + var lineCrossSize = style.alignContent === "stretch" ? + items.crossSpace + crossSpace / flexLines.length : + items.crossSpace; + + for (var i = 0; i < items.length; ++i) { + var item = items[i]; + var itemStyle = getStyle(item); + + // the priority of alignSelf is greater than alignItems from parent elements + var align = itemStyle.alignSelf || style.alignItems; + + if (itemStyle[crossSize] === null || itemStyle[crossSize] === 0) { + itemStyle[crossSize] = (align === "stretch") ? lineCrossSize : 0; + } + if (align === "flex-start") { + itemStyle[crossStart] = crossBase; + itemStyle[crossEnd] = itemStyle[crossStart] + crossSign * itemStyle[crossSize]; + } + if (align === "flex-end") { + itemStyle[crossEnd] = crossBase + lineCrossSize * crossSign; + itemStyle[crossStart] = itemStyle[crossEnd] - crossSign * itemStyle[crossSize]; + } + if (align === "center") { + itemStyle[crossStart] = crossBase + crossSign * (lineCrossSize - itemStyle[crossSize]) / 2; + itemStyle[crossEnd] = itemStyle[crossStart] + crossSign * itemStyle[crossSize]; + } + if (align === "stretch") { + itemStyle[crossStart] = crossBase; + itemStyle[crossEnd] = crossBase + crossSign * (itemStyle[crossSize] !== "null" && itemStyle[crossSize]); + itemStyle[crossSize] = crossSign * (itemStyle[crossEnd] - itemStyle[crossStart]); + } + } + crossBase += crossSign * (lineCrossSize + step); + }); +} + +function getStyle(element) { + if (!element.style) { + element.style = {}; + } + for (let prop in element.computedStyle) { + var p = element.computedStyle.value; + element.style[prop] = element.computedStyle[prop].value; + + if (element.style[prop].toString().match(/px$/)) { + element.style[prop] = parseInt(element.style[prop]); + } + if (element.style[prop].toString().match(/^[0-9\.]$/)) { + element.style[prop] = parseInt(element.style[prop]); + } + } + + return element.style; +} + +module.exports = layout; diff --git a/week04/toyBrowser/parser.js b/week04/toyBrowser/parser.js new file mode 100644 index 000000000..8959636b6 --- /dev/null +++ b/week04/toyBrowser/parser.js @@ -0,0 +1,446 @@ + +/** + * parsing using state machine in html standard + * https://html.spec.whatwg.org/#tokenization +**/ +const css = require('css'); +const EOF = Symbol("EOF"); +const layout = require('./layout.js'); +let currentToken = null; +let stack = [{ type: "document", children: [] }]; +let currentTextNode = null; + +let rules = []; +function addCSSRules(text) { + var ast = css.parse(text); + rules.push(...ast.stylesheet.rules); +} + +function computeCSS(element) { + // use slice to duplicate stack array + var elements = stack.slice().reverse(); + + if (!element.computedStyle) { + element.computedStyle = {}; + } + + for (let rule of rules) { + var selectorParts = rule.selectors[0].split(" ").reverse(); + if (!match(element, selectorParts[0])) + continue; + + // check all the parent elements + let matched = false; + var j = 1; + for (var i = 0; i < elements.length; ++i) { + if (match(elements[i], selectorParts[j])) { + j++; + } + } + + if (j >= selectorParts.length) { + matched = true; + } + if (matched) { + var sp = specificity(rule.selectors[0]); + var computedStyle = element.computedStyle; + for (var declaration of rule.declarations) { + if (!computedStyle[declaration.property]) { + computedStyle[declaration.property] = {}; + } + + if (!computedStyle[declaration.property].specificity){ + computedStyle[declaration.property].value = declaration.value; + computedStyle[declaration.property].specificity = sp; + } + else if (compare(computedStyle[declaration.property].specificity, sp) < 0){ + computedStyle[declaration.property].value = declaration.value; + computedStyle[declaration.property].specificity = sp; + } + + } + + } + } +} + +//assume simple css selector only +// one class +// .a +// #a +// div +function match(element, selector) { + // skip text element + if (!selector || !element.attributes) return false; + + // only has one attribute + if (selector.charAt(0) == '#') { + var attr = element.attributes.filter(attr => attr.name === 'id'); + if (attr[0] && attr[0].value === selector.replace("#", "")) { + return true; + } + } + else if (selector.charAt(0) == '.') { + var attr = element.attributes.filter(attr => attr.name === 'class'); + if (attr[0] && attr[0].value === selector.replace(".", "")) { + return true; + } + } + else { + if (element.tagName === selector) { + return true; + } + } + return false; +} + +function specificity(selector){ + var p = [0,0,0,0]; + var selectorParts = selector.split(" "); + for (var part of selectorParts) { + if (part.charAt(0) === '#'){ + p[1] += 1; + } + else if (part.charAt(0) === '.'){ + p[2] += 1; + } + else { + p[3] += 1; + } + } + return p; +} + +function compare(sp1, sp2){ + if (sp1[0] - sp2[0]){ + return sp1[0] - sp2[0]; + } + if (sp1[1] - sp2[1]){ + return sp1[1] - sp2[1]; + } + if (sp1[2] - sp2[2]){ + return sp1[2] - sp2[2]; + } + return sp1[3] - sp2[3] +} +function emit(token) { + let top = stack[stack.length - 1]; + + if (token.type === "startTag") { + let element = { + type: "element", + children: [], + attributes: [] + }; + element.tagName = token.tagName; + + for (let p in token) { + if (p !== "type" && p != "tagName") { + element.attributes.push({ + name: p, + value: token[p] + }); + } + } + // CSS information has been gathered + // ignore css in the body for recalculation + computeCSS(element); + + top.children.push(element); + //element.parent = top; + + if (!token.isSelfClosing) + stack.push(element); + currentTextNode = null; + } + else if (token.type === "EndTag") { + if (top.tagName != token.tagName) { + throw Error("Tag start and end does not match") + } + else { + //add css rule + if (top.tagName === "style") { + addCSSRules(top.children[0].content); + } + layout(top); + stack.pop(); + } + currentTextNode = null; + } + else if (token.type === "text") { + if (currentTextNode == null) { + currentTextNode = { + type: "text", + content: "" + }; + top.children.push(currentTextNode); + } + currentTextNode.content += token.content; + } +}; + +function data(c) { + if (c === '<') { + return tagOpen; + } + else if (c === EOF) { + emit({ + type: "EOF" + }); + return; + } + else { + emit({ + type: "text", + content: c + }); + return data; + } +} + +function tagOpen(c) { + // ') { + } + else if (c === EOF) { + + } +} + +function tagName(c) { + // + if (c.match(/^[\n\t\f ]$/)) { + return beforeAttributeName; + } + else if (c === '/') { + return selfClosingTag; + } + else if (c.match(/^[a-zA-Z]$/)) { + currentToken.tagName += c.toLowerCase(); + return tagName; + } + else if (c === '>') { + emit(currentToken); + return data; + } + else { + return tagName; + } +} + +//' || c === '/' || c === EOF) { + return afterAttributeName(c); + } + else if (c === '=') { + // error + } + else { + currentAttribute = { + name: "", + value: "" + } + return attributeName(c); + } +} + +function attributeName(c) { + //
+ if (c.match(/^[\n\t\f ]$/) || c === '/' || c === '>' || c === EOF) { + return afterAttributeName(c); + } + else if (c === '=') { + return beforeAttributeValue; + } + else if (c === '\u0000') { + + } + else if (c === "\"" || c === "'" || c === "<") { + + } + else { + currentAttribute.name += c; + return attributeName; + } +} + +function afterAttributeName(c) { + if (c.match(/^[\n\t\f ]$/)) { + return afterAttributeName; + } + else if (c === '/') { + return selfClosingTag; + } + else if (c === '=') { + return beforeAttributeValue; + } + else if (c === '>') { + emit(currentToken); + return data; + } + else if (c === EOF) { + + } + else { + currentAttribute = { + name: "", + value: "" + } + return attributeName(c); + } +} + +function beforeAttributeValue(c) { + if (c.match(/^[\n\t\f ]$/) || c === '/' || c === '>' || c === EOF) { + return beforeAttributeValue; + } + else if (c === "\"") + return doubleQuotedAttributeValue; + else if (c === "\'") + return singleQuotedAttributeValue; + else if (c === '>') { + //return data + } + else { + return unquotedAttributeValue(c); + } +} + +function doubleQuotedAttributeValue(c) { + if (c === "\"") { + currentToken[currentAttribute.name] = currentAttribute.value; + return afterQuotedAttributeValue; + } + else if (c === '\u0000') { + + } + else if (c === EOF) { + + } + else { + currentAttribute.value += c; + return doubleQuotedAttributeValue; + } +} + +function singleQuotedAttributeValue(c) { + if (c === "\'") { + currentToken[currentAttribute.name] = currentAttribute.value; + return afterQuotedAttributeValue; + } + else if (c === '\u0000') { + + } + else if (c === EOF) { + + } + else { + currentAttribute.value += c; + return singleQuotedAttributeValue; + } +} + +function unquotedAttributeValue(c) { + if (c.match(/^[\n\t\f ]$/) || c === '/' || c === EOF) { + currentToken[currentAttribute.name] = currentAttribute.value; + return beforeAttributeValue; + } + else if (c === "/") { + currentToken[currentAttribute.name] = currentAttribute.value; + return selfClosingTag; + } + else if (c === '>') { + currentToken[currentAttribute.name] = currentAttribute.value; + emit(currentToken); + return data; + } + else if (c === '\u0000') { + + } + else if (c === '\"' || c === "'" || c === "<" || c === "=" || c === "`") { + + } + else if (c === EOF) { + + } + else { + currentAttribute.value += c; + return unquotedAttributeValue; + } +} + + +function afterQuotedAttributeValue(c) { + if (c.match(/^[\n\t\f ]$/)) { + return beforeAttributeValue; + } + else if (c === '/') { + return selfClosingTag; + } + else if (c === '>') { + emit(currentToken); + return data; + } + else if (c === EOF) { + + } + else { + return beforeAttributeName(c); + } +} +function selfClosingTag(c) { + if (c === '>') { + currentToken.isSelfClosing = true; + emit(currentToken); + return data; + } + else if (c === "EOF") { + + } + else { + + } +} + + + +module.exports.parseHTML = function parseHTML(html) { + let state = data; + let deg = ""; + for (let c of html) { + deg += c; + state = state(c); + + } + //force to terminate + state = state(EOF); + return stack[0]; +} \ No newline at end of file diff --git a/week04/toyBrowser/render.js b/week04/toyBrowser/render.js new file mode 100644 index 000000000..e87689b65 --- /dev/null +++ b/week04/toyBrowser/render.js @@ -0,0 +1,20 @@ +const images = require('images'); + +function render(viewPort, element){ + if (element.style){ + var img = images(element.style.width, element.style.height); + if (element.style["background-color"]){ + let color = element.style["background-color"] || "rgb(255,255,255)"; + color.match(/rgb\((\d+),(\d+),(\d+)\)/); + img.fill(Number(RegExp.$1), Number(RegExp.$2), Number(RegExp.$3),0); + viewPort.draw(img, element.style.left||0, element.style.top||0); + } + } + if (element.children){ + for (var child of element.children){ + render(viewPort, child); + } + } +} + +module.exports = render; \ No newline at end of file diff --git a/week04/toyBrowser/server.js b/week04/toyBrowser/server.js new file mode 100644 index 000000000..664a01f10 --- /dev/null +++ b/week04/toyBrowser/server.js @@ -0,0 +1,51 @@ +const http = require('http') +http.createServer((request,response) => { + let body =[] + request.on('error',(err)=>{ + console.error(err); + }).on('data',(chunk)=>{ + body.push(chunk.toString()) + }).on('end',()=>{ + tmp = []; + for (var i of body){ + tmp.push(Buffer.from(i)); + } + body = Buffer.concat(tmp).toString(); + console.log("body:",body); + response.writeHead(200,{'content-type':'text/html'}) + + const html = ` + + + + + +
+
+
+
+ + `; + response.end(html); + }) +}).listen(8088) + +console.log("server started!"); \ No newline at end of file diff --git "a/week05/13 \346\236\201\345\256\242\345\244\247\345\255\246-\345\211\215\347\253\257\350\277\233\351\230\266\350\256\255\347\273\203\350\220\245-\351\207\215\345\255\246CSS\346\200\273\350\256\272.pdf" "b/week05/13 \346\236\201\345\256\242\345\244\247\345\255\246-\345\211\215\347\253\257\350\277\233\351\230\266\350\256\255\347\273\203\350\220\245-\351\207\215\345\255\246CSS\346\200\273\350\256\272.pdf" new file mode 100644 index 000000000..3c9f16fdc Binary files /dev/null and "b/week05/13 \346\236\201\345\256\242\345\244\247\345\255\246-\345\211\215\347\253\257\350\277\233\351\230\266\350\256\255\347\273\203\350\220\245-\351\207\215\345\255\246CSS\346\200\273\350\256\272.pdf" differ diff --git "a/week05/14 \346\236\201\345\256\242\345\244\247\345\255\246-\345\211\215\347\253\257\350\277\233\351\230\266\350\256\255\347\273\203\350\220\245-\351\207\215\345\255\246CSS\351\200\211\346\213\251\345\231\250.pdf" "b/week05/14 \346\236\201\345\256\242\345\244\247\345\255\246-\345\211\215\347\253\257\350\277\233\351\230\266\350\256\255\347\273\203\350\220\245-\351\207\215\345\255\246CSS\351\200\211\346\213\251\345\231\250.pdf" new file mode 100644 index 000000000..127ec2551 Binary files /dev/null and "b/week05/14 \346\236\201\345\256\242\345\244\247\345\255\246-\345\211\215\347\253\257\350\277\233\351\230\266\350\256\255\347\273\203\350\220\245-\351\207\215\345\255\246CSS\351\200\211\346\213\251\345\231\250.pdf" differ diff --git a/week05/CSS.xmind b/week05/CSS.xmind new file mode 100644 index 000000000..cbbf7c50d Binary files /dev/null and b/week05/CSS.xmind differ diff --git "a/week05/CSS\344\274\252\345\205\203\347\264\240.png" "b/week05/CSS\344\274\252\345\205\203\347\264\240.png" new file mode 100644 index 000000000..67d2fcb86 Binary files /dev/null and "b/week05/CSS\344\274\252\345\205\203\347\264\240.png" differ diff --git a/week05/NOTE.md b/week05/NOTE.md index 50de30414..ef780fcff 100644 --- a/week05/NOTE.md +++ b/week05/NOTE.md @@ -1 +1,91 @@ -学习笔记 \ No newline at end of file +学习笔记 +### 1. CSS总论 | CSS语法的研究 +> ![c26208dc094ab997c8ecf023e1de26db.png](evernotecid://2393A90F-1FE0-42B1-A655-82D09E31A7AF/appyinxiangcom/307379/ENResource/p4506) + +#### CSS 总体结构 +- @charset +- @import +- rules + - @media + - @page + - rule +### 2. CSS总论 | CSS @规则的研究 + +At-rules +- @charset : https://www.w3.org/TR/css-syntax-3/ +- @import :https://www.w3.org/TR/css-cascade-4/ +- @media :https://www.w3.org/TR/css3-conditional/ +- @page : https://www.w3.org/TR/css-page-3/ +- @counter-style :https://www.w3.org/TR/css-counter-styles - @keyframes :https://www.w3.org/TR/css-animations-1/ +- @fontface :https://www.w3.org/TR/css-fonts-3/ +- @supports :https://www.w3.org/TR/css3-conditional/ +- @namespace :https://www.w3.org/TR/css-namespaces-3/ + + + +### 3. CSS总论 | CSS规则的结构 +- 选择器 +- 声明 + - key + - value + +### 4. CSS总论 | 收集标准 +#### 地址:https://www.w3.org/TR/?tag=css +#### 过滤CSS标准的代码 code 如下 + +### 5. CSS总论 | CSS总论总结 + +### 6. CSS选择器 | 选择器语法 +• 简单选择器 + • * • div svg|a + • .cls + • #id + • [attr=value] + • :hover + • ::before + +• 复合选择器 + • <简单选择器><简单选择器><简单选择器> • * 或者 div 必须写在最前面 +• 复杂选择器 + • <复合选择器><复合选择器> + • <复合选择器>">"<复合选择器> + • <复合选择器>"~"<复合选择器> + • <复合选择器>"+"<复合选择器> + • <复合选择器>"||"<复合选择器> + +### 7. CSS选择器 | 选择器的优先级 + +### 8. 伪类 +伪类 +• 链接/行为 + • :any-link + • :link :visited + • :hover + • :active + • :focus + • :target +• 树结构 + • :empty + • :nth-child() + • :nth-last-child() + • :first-child :last-child :only-child +• 逻辑型 + • :not伪类 + • :where :has + +### 9. 伪元素 +• ::before +• ::after +• ::first-line +• ::first-letter + +#### 为什么first-letter可以设置float之类的,而first-line不行呢? +答:一行可以有多个::first-letter伪元素,只能有一个::first-line伪元素。所以first-letter可以设置float之类的,而first-line不行 + +#### 作业:编写一个match函数 +```js +function match(selector, element) { +return true; +} +match("div #id.class", document.getElementById("id")); +``` \ No newline at end of file diff --git a/week05/match.js b/week05/match.js new file mode 100644 index 000000000..e69de29bb diff --git a/week05/toy-browser.zip b/week05/toy-browser.zip new file mode 100644 index 000000000..d5a5e732d Binary files /dev/null and b/week05/toy-browser.zip differ diff --git a/week05/toy-browser/css-computing/.vscode/launch.json b/week05/toy-browser/css-computing/.vscode/launch.json new file mode 100755 index 000000000..a9edaba58 --- /dev/null +++ b/week05/toy-browser/css-computing/.vscode/launch.json @@ -0,0 +1,19 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Launch Program", + "program": "${workspaceFolder}/7/Client.js", + "skipFiles": [ + "/**" + ] + } + + + ] +} \ No newline at end of file diff --git a/week05/toy-browser/css-computing/1/clientjs.png b/week05/toy-browser/css-computing/1/clientjs.png new file mode 100755 index 000000000..ac9f147e3 Binary files /dev/null and b/week05/toy-browser/css-computing/1/clientjs.png differ diff --git a/week05/toy-browser/css-computing/1/parserjs.png b/week05/toy-browser/css-computing/1/parserjs.png new file mode 100755 index 000000000..897ae388c Binary files /dev/null and b/week05/toy-browser/css-computing/1/parserjs.png differ diff --git a/week05/toy-browser/css-computing/2/clientjs.png b/week05/toy-browser/css-computing/2/clientjs.png new file mode 100755 index 000000000..31bdd1346 Binary files /dev/null and b/week05/toy-browser/css-computing/2/clientjs.png differ diff --git a/week05/toy-browser/css-computing/2/parserjs.png b/week05/toy-browser/css-computing/2/parserjs.png new file mode 100755 index 000000000..2eb607ca7 Binary files /dev/null and b/week05/toy-browser/css-computing/2/parserjs.png differ diff --git a/week05/toy-browser/css-computing/3/clientjs.png b/week05/toy-browser/css-computing/3/clientjs.png new file mode 100755 index 000000000..aa01feaed Binary files /dev/null and b/week05/toy-browser/css-computing/3/clientjs.png differ diff --git a/week05/toy-browser/css-computing/3/parserjs.png b/week05/toy-browser/css-computing/3/parserjs.png new file mode 100755 index 000000000..6f699b321 Binary files /dev/null and b/week05/toy-browser/css-computing/3/parserjs.png differ diff --git a/week05/toy-browser/css-computing/4/clientjs.png b/week05/toy-browser/css-computing/4/clientjs.png new file mode 100755 index 000000000..6bfc9bad4 Binary files /dev/null and b/week05/toy-browser/css-computing/4/clientjs.png differ diff --git a/week05/toy-browser/css-computing/4/parserjs.png b/week05/toy-browser/css-computing/4/parserjs.png new file mode 100755 index 000000000..05fe2210b Binary files /dev/null and b/week05/toy-browser/css-computing/4/parserjs.png differ diff --git a/week05/toy-browser/css-computing/5/clientjs.png b/week05/toy-browser/css-computing/5/clientjs.png new file mode 100755 index 000000000..58dd67c7e Binary files /dev/null and b/week05/toy-browser/css-computing/5/clientjs.png differ diff --git a/week05/toy-browser/css-computing/5/parserjs.png b/week05/toy-browser/css-computing/5/parserjs.png new file mode 100755 index 000000000..dae3db076 Binary files /dev/null and b/week05/toy-browser/css-computing/5/parserjs.png differ diff --git a/week05/toy-browser/css-computing/6/clientjs.png b/week05/toy-browser/css-computing/6/clientjs.png new file mode 100755 index 000000000..4a9e7a794 Binary files /dev/null and b/week05/toy-browser/css-computing/6/clientjs.png differ diff --git a/week05/toy-browser/css-computing/6/parserjs.png b/week05/toy-browser/css-computing/6/parserjs.png new file mode 100755 index 000000000..0f0c1085c Binary files /dev/null and b/week05/toy-browser/css-computing/6/parserjs.png differ diff --git a/week05/toy-browser/css-computing/7/clientjs.png b/week05/toy-browser/css-computing/7/clientjs.png new file mode 100755 index 000000000..d55f4ffda Binary files /dev/null and b/week05/toy-browser/css-computing/7/clientjs.png differ diff --git a/week05/toy-browser/css-computing/7/parserjs.png b/week05/toy-browser/css-computing/7/parserjs.png new file mode 100755 index 000000000..45afeb79a Binary files /dev/null and b/week05/toy-browser/css-computing/7/parserjs.png differ diff --git a/week05/toy-browser/css-computing/serverjs.png b/week05/toy-browser/css-computing/serverjs.png new file mode 100755 index 000000000..404366030 Binary files /dev/null and b/week05/toy-browser/css-computing/serverjs.png differ diff --git a/week05/toy-browser/finite-state-machine/1/matchjs.png b/week05/toy-browser/finite-state-machine/1/matchjs.png new file mode 100755 index 000000000..1b9040666 Binary files /dev/null and b/week05/toy-browser/finite-state-machine/1/matchjs.png differ diff --git a/week05/toy-browser/finite-state-machine/2/matchjs.png b/week05/toy-browser/finite-state-machine/2/matchjs.png new file mode 100755 index 000000000..d31123706 Binary files /dev/null and b/week05/toy-browser/finite-state-machine/2/matchjs.png differ diff --git a/week05/toy-browser/finite-state-machine/3/matchjs.png b/week05/toy-browser/finite-state-machine/3/matchjs.png new file mode 100755 index 000000000..1d19d5277 Binary files /dev/null and b/week05/toy-browser/finite-state-machine/3/matchjs.png differ diff --git a/week05/toy-browser/finite-state-machine/4/matchjs.png b/week05/toy-browser/finite-state-machine/4/matchjs.png new file mode 100755 index 000000000..2a07734c8 Binary files /dev/null and b/week05/toy-browser/finite-state-machine/4/matchjs.png differ diff --git a/week05/toy-browser/finite-state-machine/5/matchjs.png b/week05/toy-browser/finite-state-machine/5/matchjs.png new file mode 100755 index 000000000..ff638c313 Binary files /dev/null and b/week05/toy-browser/finite-state-machine/5/matchjs.png differ diff --git a/week05/toy-browser/finite-state-machine/5/wrongjs.png b/week05/toy-browser/finite-state-machine/5/wrongjs.png new file mode 100755 index 000000000..9025c9a88 Binary files /dev/null and b/week05/toy-browser/finite-state-machine/5/wrongjs.png differ diff --git a/week05/toy-browser/html-parse/.vscode/launch.json b/week05/toy-browser/html-parse/.vscode/launch.json new file mode 100755 index 000000000..c5fe7082e --- /dev/null +++ b/week05/toy-browser/html-parse/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Launch Program", + "skipFiles": [ + "/**" + ], + "program": "${workspaceFolder}/7-combineText/client.js" + } + ] +} \ No newline at end of file diff --git a/week05/toy-browser/html-parse/1-spiltFile/clientjs.png b/week05/toy-browser/html-parse/1-spiltFile/clientjs.png new file mode 100755 index 000000000..6c9210b5f Binary files /dev/null and b/week05/toy-browser/html-parse/1-spiltFile/clientjs.png differ diff --git a/week05/toy-browser/html-parse/1-spiltFile/parserjs.png b/week05/toy-browser/html-parse/1-spiltFile/parserjs.png new file mode 100755 index 000000000..b5608fdd6 Binary files /dev/null and b/week05/toy-browser/html-parse/1-spiltFile/parserjs.png differ diff --git a/week05/toy-browser/html-parse/2-initFSM/clientjs.png b/week05/toy-browser/html-parse/2-initFSM/clientjs.png new file mode 100755 index 000000000..ccf7bcdcc Binary files /dev/null and b/week05/toy-browser/html-parse/2-initFSM/clientjs.png differ diff --git a/week05/toy-browser/html-parse/2-initFSM/parserjs.png b/week05/toy-browser/html-parse/2-initFSM/parserjs.png new file mode 100755 index 000000000..f95bd294e Binary files /dev/null and b/week05/toy-browser/html-parse/2-initFSM/parserjs.png differ diff --git a/week05/toy-browser/html-parse/3-ParseTag/clientjs.png b/week05/toy-browser/html-parse/3-ParseTag/clientjs.png new file mode 100755 index 000000000..73c4bb2f3 Binary files /dev/null and b/week05/toy-browser/html-parse/3-ParseTag/clientjs.png differ diff --git a/week05/toy-browser/html-parse/3-ParseTag/parserjs.png b/week05/toy-browser/html-parse/3-ParseTag/parserjs.png new file mode 100755 index 000000000..e795fb0de Binary files /dev/null and b/week05/toy-browser/html-parse/3-ParseTag/parserjs.png differ diff --git a/week05/toy-browser/html-parse/4-emitToken/clientjs.png b/week05/toy-browser/html-parse/4-emitToken/clientjs.png new file mode 100755 index 000000000..e61f3a9a7 Binary files /dev/null and b/week05/toy-browser/html-parse/4-emitToken/clientjs.png differ diff --git a/week05/toy-browser/html-parse/4-emitToken/parserjs.png b/week05/toy-browser/html-parse/4-emitToken/parserjs.png new file mode 100755 index 000000000..3c33ed7f6 Binary files /dev/null and b/week05/toy-browser/html-parse/4-emitToken/parserjs.png differ diff --git a/week05/toy-browser/html-parse/5-attribute/clientjs.png b/week05/toy-browser/html-parse/5-attribute/clientjs.png new file mode 100755 index 000000000..321c236aa Binary files /dev/null and b/week05/toy-browser/html-parse/5-attribute/clientjs.png differ diff --git a/week05/toy-browser/html-parse/5-attribute/parserjs.png b/week05/toy-browser/html-parse/5-attribute/parserjs.png new file mode 100755 index 000000000..6234ead55 Binary files /dev/null and b/week05/toy-browser/html-parse/5-attribute/parserjs.png differ diff --git a/week05/toy-browser/html-parse/6-constructTree/clientjs.png b/week05/toy-browser/html-parse/6-constructTree/clientjs.png new file mode 100755 index 000000000..a5537686d Binary files /dev/null and b/week05/toy-browser/html-parse/6-constructTree/clientjs.png differ diff --git a/week05/toy-browser/html-parse/6-constructTree/parserjs.png b/week05/toy-browser/html-parse/6-constructTree/parserjs.png new file mode 100755 index 000000000..b264ff0b3 Binary files /dev/null and b/week05/toy-browser/html-parse/6-constructTree/parserjs.png differ diff --git a/week05/toy-browser/html-parse/7-combineText/clientjs.png b/week05/toy-browser/html-parse/7-combineText/clientjs.png new file mode 100755 index 000000000..9b1d227d6 Binary files /dev/null and b/week05/toy-browser/html-parse/7-combineText/clientjs.png differ diff --git a/week05/toy-browser/html-parse/7-combineText/parserjs.png b/week05/toy-browser/html-parse/7-combineText/parserjs.png new file mode 100755 index 000000000..ca9d11e24 Binary files /dev/null and b/week05/toy-browser/html-parse/7-combineText/parserjs.png differ diff --git a/week05/toy-browser/html-parse/serverjs.png b/week05/toy-browser/html-parse/serverjs.png new file mode 100755 index 000000000..351faf5fa Binary files /dev/null and b/week05/toy-browser/html-parse/serverjs.png differ diff --git a/week05/toy-browser/layout/1/client.js.png b/week05/toy-browser/layout/1/client.js.png new file mode 100755 index 000000000..451f3d924 Binary files /dev/null and b/week05/toy-browser/layout/1/client.js.png differ diff --git a/week05/toy-browser/layout/1/layout.js.png b/week05/toy-browser/layout/1/layout.js.png new file mode 100755 index 000000000..7dea7a537 Binary files /dev/null and b/week05/toy-browser/layout/1/layout.js.png differ diff --git a/week05/toy-browser/layout/1/parser.js.png b/week05/toy-browser/layout/1/parser.js.png new file mode 100755 index 000000000..53cf7e11b Binary files /dev/null and b/week05/toy-browser/layout/1/parser.js.png differ diff --git a/week05/toy-browser/layout/2/client.js.png b/week05/toy-browser/layout/2/client.js.png new file mode 100755 index 000000000..9cbf1eaa6 Binary files /dev/null and b/week05/toy-browser/layout/2/client.js.png differ diff --git a/week05/toy-browser/layout/2/demo.html b/week05/toy-browser/layout/2/demo.html new file mode 100755 index 000000000..c3ac6de32 --- /dev/null +++ b/week05/toy-browser/layout/2/demo.html @@ -0,0 +1,10 @@ + +
+
+
+
+
\ No newline at end of file diff --git a/week05/toy-browser/layout/2/layout.js.png b/week05/toy-browser/layout/2/layout.js.png new file mode 100755 index 000000000..2cd34c668 Binary files /dev/null and b/week05/toy-browser/layout/2/layout.js.png differ diff --git a/week05/toy-browser/layout/2/parser.js.png b/week05/toy-browser/layout/2/parser.js.png new file mode 100755 index 000000000..b6a5e9d84 Binary files /dev/null and b/week05/toy-browser/layout/2/parser.js.png differ diff --git a/week05/toy-browser/layout/3/client.js.png b/week05/toy-browser/layout/3/client.js.png new file mode 100755 index 000000000..aff087a04 Binary files /dev/null and b/week05/toy-browser/layout/3/client.js.png differ diff --git a/week05/toy-browser/layout/3/layout.js.png b/week05/toy-browser/layout/3/layout.js.png new file mode 100755 index 000000000..41ddbbb0a Binary files /dev/null and b/week05/toy-browser/layout/3/layout.js.png differ diff --git a/week05/toy-browser/layout/3/parser.js.png b/week05/toy-browser/layout/3/parser.js.png new file mode 100755 index 000000000..ff222a557 Binary files /dev/null and b/week05/toy-browser/layout/3/parser.js.png differ diff --git a/week05/toy-browser/layout/4/client.js.png b/week05/toy-browser/layout/4/client.js.png new file mode 100755 index 000000000..66b0bae12 Binary files /dev/null and b/week05/toy-browser/layout/4/client.js.png differ diff --git a/week05/toy-browser/layout/4/layout.js.png b/week05/toy-browser/layout/4/layout.js.png new file mode 100755 index 000000000..4cf2723b3 Binary files /dev/null and b/week05/toy-browser/layout/4/layout.js.png differ diff --git a/week05/toy-browser/layout/4/parser.js.png b/week05/toy-browser/layout/4/parser.js.png new file mode 100755 index 000000000..108abb0cb Binary files /dev/null and b/week05/toy-browser/layout/4/parser.js.png differ diff --git a/week05/toy-browser/render/1/client.js.png b/week05/toy-browser/render/1/client.js.png new file mode 100755 index 000000000..e9e2c2652 Binary files /dev/null and b/week05/toy-browser/render/1/client.js.png differ diff --git a/week05/toy-browser/render/1/layout.js.png b/week05/toy-browser/render/1/layout.js.png new file mode 100755 index 000000000..bc469c4e1 Binary files /dev/null and b/week05/toy-browser/render/1/layout.js.png differ diff --git a/week05/toy-browser/render/1/parser.js.png b/week05/toy-browser/render/1/parser.js.png new file mode 100755 index 000000000..7f551d15b Binary files /dev/null and b/week05/toy-browser/render/1/parser.js.png differ diff --git a/week05/toy-browser/render/1/render.js.png b/week05/toy-browser/render/1/render.js.png new file mode 100755 index 000000000..29f88a7a7 Binary files /dev/null and b/week05/toy-browser/render/1/render.js.png differ diff --git a/week05/toy-browser/render/2/client.js.png b/week05/toy-browser/render/2/client.js.png new file mode 100755 index 000000000..42f58b108 Binary files /dev/null and b/week05/toy-browser/render/2/client.js.png differ diff --git a/week05/toy-browser/render/2/demo.html b/week05/toy-browser/render/2/demo.html new file mode 100755 index 000000000..9a14017ae --- /dev/null +++ b/week05/toy-browser/render/2/demo.html @@ -0,0 +1,5 @@ + +
+
\ No newline at end of file diff --git a/week05/toy-browser/render/2/layout.js.png b/week05/toy-browser/render/2/layout.js.png new file mode 100755 index 000000000..6aca1b67f Binary files /dev/null and b/week05/toy-browser/render/2/layout.js.png differ diff --git a/week05/toy-browser/render/2/parser.js.png b/week05/toy-browser/render/2/parser.js.png new file mode 100755 index 000000000..4ceafca03 Binary files /dev/null and b/week05/toy-browser/render/2/parser.js.png differ diff --git a/week05/toy-browser/render/2/render.js.png b/week05/toy-browser/render/2/render.js.png new file mode 100755 index 000000000..045bf971d Binary files /dev/null and b/week05/toy-browser/render/2/render.js.png differ diff --git a/week06/CSS.xmind b/week06/CSS.xmind new file mode 100644 index 000000000..b729a5940 Binary files /dev/null and b/week06/CSS.xmind differ diff --git a/week06/NOTE.md b/week06/NOTE.md index 50de30414..a13148be3 100644 --- a/week06/NOTE.md +++ b/week06/NOTE.md @@ -1 +1,85 @@ -学习笔记 \ No newline at end of file +### 1. CSS排版 | 盒 +>HTML代码中可以书写开始**标签**,结束**标签**,和自封闭**标签**。 +一对起止**标签**,表示一个**元素**。 +DOM树中存储的是**元素**和其它类型的节点(Node)。 +CSS选择器选中的是**元素**。 +CSS选择器选中的**元素**,在排版时可能产生多个**盒**。 +排版和渲染的基本单位是**盒**。 +- 盒模型 +### 2. CSS排版 | 正常流 +- 正常流排版 + • 收集盒进行 + • 计算盒在行中的排布 + • 计算行的排布 +### 3. CSS排版 | 正常流的行级排布 +### 4. CSS排版 | 正常流的块级排布 + - float与clear + - margin折叠 +### 5. CSS排版 | BFC合并 +-Block +• Block Container:里面有BFC的 +• 能容纳正常流的盒,里面就有BFC,想想有哪些? +• Block-level Box:外面有BFC的 +• Block Box = Block Container + Block-level Box: +里外都有BFC的 + +Block Container +• block +• inline-block +• table-cell +• flex item +• grid cell +• table-caption + + +### 6. CSS排版 | Flex排版 +Flex排版 +• 收集盒进行 +• 计算盒在主轴方向的排布 +• 计算盒在交叉轴方向的排布 + +Animation +• animation-name 时间曲线 +• animation-duration 动画的时长; +• animation-timing-function 动画的时间曲线; +• animation-delay 动画开始前的延迟; +• animation-iteration-count 动画的播放次数; +• animation-direction 动画的方向。 + + + +### 7. CSS动画与绘制 | 动画 +#### Animation +• @keyframes定义 +• animation: 使用 + +#### Transition +• transition-property 要变换的属性; +• transition-duration 变换的时长; +• transition-timing-function 时间曲线; +• transition-delay 延迟。 + +#### cubic-bezier + +### 8. CSS动画与绘制 | 颜色 +CMYK与RGB +HSL与HSV +### 9. CSS动画与绘制 | 绘制 + +#### 几何图形 +• border +• box-shadow +• border-radius + +#### 文字 +• font +• text-decoration +#### 位图 +• background-image + +##### 应用技巧 +• data uri + svg +• data:image/svg+xml, \ No newline at end of file diff --git a/week06/code/css-crawler.js b/week06/code/css-crawler.js new file mode 100644 index 000000000..b06aac04b --- /dev/null +++ b/week06/code/css-crawler.js @@ -0,0 +1,31 @@ + + + +let iframe = document.createElement("iframe"); +document.body.innerHTML = ""; +document.body.appendChild(iframe); +const happen = (ele,e)=>{ + return new Promise(function(resolve){ + let handler = () => { + resolve(); + ele.removeEventListener(e,handler); + } + ele.addEventListener(e,handler); + }) +} +const sleep = (delay) => { + const start = (new Date()).getTime(); + while ((new Date()).getTime() - start < delay) { + continue + } +} + +void async function(){ + for(let standard of standards){ + iframe.src = standard.url; + console.log(standard.name); + await sleep(1000) + await happen(iframe,"load"); + console.log(iframe.contentDocument.querySelectorAll(".dfn-paneled")); + } +} \ No newline at end of file diff --git a/week06/code/filter.js b/week06/code/filter.js new file mode 100644 index 000000000..4c5f48820 --- /dev/null +++ b/week06/code/filter.js @@ -0,0 +1 @@ +JSON.stringify(Array.prototype.slice.call(document.querySelector("#container").children).filter(e =>e.getAttribute("data-tag").match(/css/)).map(e=>({name:e.children[1].innerText,url:e.children[1].children[0].href}))) diff --git a/week06/code/standards.json b/week06/code/standards.json new file mode 100644 index 000000000..36a0f4219 --- /dev/null +++ b/week06/code/standards.json @@ -0,0 +1,562 @@ +[ + { + "name":"CSS Grid Layout Module Level 2", + "url":"https://www.w3.org/TR/2020/CR-css-grid-2-20200818/" + }, + { + "name":"CSS Cascading and Inheritance Level 4", + "url":"https://www.w3.org/TR/2020/WD-css-cascade-4-20200818/" + }, + { + "name":"CSS Grid Layout Module Level 1", + "url":"https://www.w3.org/TR/2020/CR-css-grid-1-20200818/" + }, + { + "name":"CSS Cascading and Inheritance Level 3", + "url":"https://www.w3.org/TR/2020/CR-css-cascade-3-20200817/" + }, + { + "name":"Requirements for Japanese Text Layout 日本語組版処理の要件(日本語版)", + "url":"https://www.w3.org/TR/2020/NOTE-jlreq-20200811/" + }, + { + "name":"Requirements for Chinese Text Layout中文排版需求", + "url":"https://www.w3.org/TR/2020/WD-clreq-20200801/" + }, + { + "name":"Media Queries Level 5", + "url":"https://www.w3.org/TR/2020/WD-mediaqueries-5-20200731/" + }, + { + "name":"Media Queries Level 4", + "url":"https://www.w3.org/TR/2020/CR-mediaqueries-4-20200721/" + }, + { + "name":"CSS Lists Module Level 3", + "url":"https://www.w3.org/TR/2020/WD-css-lists-3-20200709/" + }, + { + "name":"CSS Inline Layout Module Level 3", + "url":"https://www.w3.org/TR/2020/WD-css-inline-3-20200618/" + }, + { + "name":"CSS Overflow Module Level 3", + "url":"https://www.w3.org/TR/2020/WD-css-overflow-3-20200603/" + }, + { + "name":"CSS Containment Module Level 2", + "url":"https://www.w3.org/TR/2020/WD-css-contain-2-20200603/" + }, + { + "name":"Encoding", + "url":"https://www.w3.org/TR/2020/NOTE-encoding-20200602/" + }, + { + "name":"Requirements for Hangul Text Layout and Typography : 한국어 텍스트 레이아웃 및 타이포그래피를 위한 요구사항", + "url":"https://www.w3.org/TR/2020/NOTE-klreq-20200527/" + }, + { + "name":"CSS Box Sizing Module Level 4", + "url":"https://www.w3.org/TR/2020/WD-css-sizing-4-20200526/" + }, + { + "name":"Ethiopic Layout Requirements", + "url":"https://www.w3.org/TR/2020/WD-elreq-20200526/" + }, + { + "name":"CSS Positioned Layout Module Level 3", + "url":"https://www.w3.org/TR/2020/WD-css-position-3-20200519/" + }, + { + "name":"CSS Display Module Level 3", + "url":"https://www.w3.org/TR/2020/CR-css-display-3-20200519/" + }, + { + "name":"CSS Text Decoration Module Level 4", + "url":"https://www.w3.org/TR/2020/WD-css-text-decor-4-20200506/" + }, + { + "name":"CSS Ruby Layout Module Level 1", + "url":"https://www.w3.org/TR/2020/WD-css-ruby-1-20200429/" + }, + { + "name":"CSS Text Module Level 3", + "url":"https://www.w3.org/TR/2020/WD-css-text-3-20200429/" + }, + { + "name":"CSS Box Alignment Module Level 3", + "url":"https://www.w3.org/TR/2020/WD-css-align-3-20200421/" + }, + { + "name":"CSS Box Model Module Level 4", + "url":"https://www.w3.org/TR/2020/WD-css-box-4-20200421/" + }, + { + "name":"CSS Box Model Module Level 3", + "url":"https://www.w3.org/TR/2020/WD-css-box-3-20200421/" + }, + { + "name":"CSS Color Adjustment Module Level 1", + "url":"https://www.w3.org/TR/2020/WD-css-color-adjust-1-20200402/" + }, + { + "name":"CSS Speech Module", + "url":"https://www.w3.org/TR/2020/CR-css-speech-1-20200310/" + }, + { + "name":"CSS Transforms Module Level 2", + "url":"https://www.w3.org/TR/2020/WD-css-transforms-2-20200303/" + }, + { + "name":"CSS Color Module Level 5", + "url":"https://www.w3.org/TR/2020/WD-css-color-5-20200303/" + }, + { + "name":"CSS Conditional Rules Module Level 4", + "url":"https://www.w3.org/TR/2020/WD-css-conditional-4-20200303/" + }, + { + "name":"Resize Observer", + "url":"https://www.w3.org/TR/2020/WD-resize-observer-1-20200211/" + }, + { + "name":"CSS Scroll Anchoring Module Level 1", + "url":"https://www.w3.org/TR/2020/WD-css-scroll-anchoring-1-20200211/" + }, + { + "name":"Timed Text Markup Language 2 (TTML2) (2nd Edition)", + "url":"https://www.w3.org/TR/2020/CR-ttml2-20200128/" + }, + { + "name":"CSS Basic User Interface Module Level 4", + "url":"https://www.w3.org/TR/2020/WD-css-ui-4-20200124/" + }, + { + "name":"CSS Writing Modes Level 3", + "url":"https://www.w3.org/TR/2019/REC-css-writing-modes-3-20191210/" + }, + { + "name":"CSS Spatial Navigation Level 1", + "url":"https://www.w3.org/TR/2019/WD-css-nav-1-20191126/" + }, + { + "name":"CSS Containment Module Level 1", + "url":"https://www.w3.org/TR/2019/REC-css-contain-1-20191121/" + }, + { + "name":"CSS Text Module Level 4", + "url":"https://www.w3.org/TR/2019/WD-css-text-4-20191113/" + }, + { + "name":"CSS Fonts Module Level 4", + "url":"https://www.w3.org/TR/2019/WD-css-fonts-4-20191113/" + }, + { + "name":"CSS Color Module Level 4", + "url":"https://www.w3.org/TR/2019/WD-css-color-4-20191105/" + }, + { + "name":"CSS Properties and Values API Level 1", + "url":"https://www.w3.org/TR/2019/WD-css-properties-values-api-1-20191025/" + }, + { + "name":"CSS Multi-column Layout Module Level 1", + "url":"https://www.w3.org/TR/2019/WD-css-multicol-1-20191015/" + }, + { + "name":"CSS Images Module Level 3", + "url":"https://www.w3.org/TR/2019/CR-css-images-3-20191010/" + }, + { + "name":"CSS Text Decoration Module Level 3", + "url":"https://www.w3.org/TR/2019/CR-css-text-decor-3-20190813/" + }, + { + "name":"CSS Generated Content Module Level 3", + "url":"https://www.w3.org/TR/2019/WD-css-content-3-20190802/" + }, + { + "name":"CSS Writing Modes Level 4", + "url":"https://www.w3.org/TR/2019/CR-css-writing-modes-4-20190730/" + }, + { + "name":"CSS Table Module Level 3", + "url":"https://www.w3.org/TR/2019/WD-css-tables-3-20190727/" + }, + { + "name":"CSS Syntax Module Level 3", + "url":"https://www.w3.org/TR/2019/CR-css-syntax-3-20190716/" + }, + { + "name":"CSS Animation Worklet API", + "url":"https://www.w3.org/TR/2019/WD-css-animation-worklet-1-20190625/" + }, + { + "name":"CSS Values and Units Module Level 3", + "url":"https://www.w3.org/TR/2019/CR-css-values-3-20190606/" + }, + { + "name":"CSS Overscroll Behavior Module Level 1", + "url":"https://www.w3.org/TR/2019/WD-css-overscroll-1-20190606/" + }, + { + "name":"CSS Intrinsic & Extrinsic Sizing Module Level 3", + "url":"https://www.w3.org/TR/2019/WD-css-sizing-3-20190522/" + }, + { + "name":"CSS Easing Functions Level 1", + "url":"https://www.w3.org/TR/2019/CR-css-easing-1-20190430/" + }, + { + "name":"TTML Media Type Definition and Profile Registry", + "url":"https://www.w3.org/TR/2019/NOTE-ttml-profile-registry-20190411/" + }, + { + "name":"WebVTT: The Web Video Text Tracks Format", + "url":"https://www.w3.org/TR/2019/CR-webvtt1-20190404/" + }, + { + "name":"Non-element Selectors Module Level 1", + "url":"https://www.w3.org/TR/2019/NOTE-selectors-nonelement-1-20190402/" + }, + { + "name":"CSS Scroll Snap Module Level 1", + "url":"https://www.w3.org/TR/2019/CR-css-scroll-snap-1-20190319/" + }, + { + "name":"CSS Pseudo-Elements Module Level 4", + "url":"https://www.w3.org/TR/2019/WD-css-pseudo-4-20190225/" + }, + { + "name":"CSS Transforms Module Level 1", + "url":"https://www.w3.org/TR/2019/CR-css-transforms-1-20190214/" + }, + { + "name":"CSS Values and Units Module Level 4", + "url":"https://www.w3.org/TR/2019/WD-css-values-4-20190131/" + }, + { + "name":"CSS Snapshot 2018", + "url":"https://www.w3.org/TR/2019/NOTE-css-2018-20190122/" + }, + { + "name":"Motion Path Module Level 1", + "url":"https://www.w3.org/TR/2018/WD-motion-1-20181218/" + }, + { + "name":"CSS Fragmentation Module Level 4", + "url":"https://www.w3.org/TR/2018/WD-css-break-4-20181218/" + }, + { + "name":"Filter Effects Module Level 1", + "url":"https://www.w3.org/TR/2018/WD-filter-effects-1-20181218/" + }, + { + "name":"CSS Fragmentation Module Level 3", + "url":"https://www.w3.org/TR/2018/CR-css-break-3-20181204/" + }, + { + "name":"Geometry Interfaces Module Level 1", + "url":"https://www.w3.org/TR/2018/CR-geometry-1-20181204/" + }, + { + "name":"Selectors Level 4", + "url":"https://www.w3.org/TR/2018/WD-selectors-4-20181121/" + }, + { + "name":"CSS Flexible Box Layout Module Level 1", + "url":"https://www.w3.org/TR/2018/CR-css-flexbox-1-20181119/" + }, + { + "name":"CSS Shadow Parts", + "url":"https://www.w3.org/TR/2018/WD-css-shadow-parts-1-20181115/" + }, + { + "name":"Timed Text Markup Language 2 (TTML2)", + "url":"https://www.w3.org/TR/2018/REC-ttml2-20181108/" + }, + { + "name":"Selectors Level 3", + "url":"https://www.w3.org/TR/2018/REC-selectors-3-20181106/" + }, + { + "name":"CSS Paged Media Module Level 3", + "url":"https://www.w3.org/TR/2018/WD-css-page-3-20181018/" + }, + { + "name":"Web Animations", + "url":"https://www.w3.org/TR/2018/WD-web-animations-1-20181011/" + }, + { + "name":"CSS Transitions", + "url":"https://www.w3.org/TR/2018/WD-css-transitions-1-20181011/" + }, + { + "name":"CSS Animations Level 1", + "url":"https://www.w3.org/TR/2018/WD-css-animations-1-20181011/" + }, + { + "name":"CSS Scrollbars Module Level 1", + "url":"https://www.w3.org/TR/2018/WD-css-scrollbars-1-20180925/" + }, + { + "name":"CSS Fonts Module Level 3", + "url":"https://www.w3.org/TR/2018/REC-css-fonts-3-20180920/" + }, + { + "name":"Cascading Style Sheets, level 1", + "url":"https://www.w3.org/TR/2018/SPSD-CSS1-20180913/" + }, + { + "name":"CSS Logical Properties and Values Level 1", + "url":"https://www.w3.org/TR/2018/WD-css-logical-1-20180827/" + }, + { + "name":"CSS Painting API Level 1", + "url":"https://www.w3.org/TR/2018/CR-css-paint-api-1-20180809/" + }, + { + "name":"CSS Basic User Interface Module Level 3 (CSS3 UI)", + "url":"https://www.w3.org/TR/2018/REC-css-ui-3-20180621/" + }, + { + "name":"CSS Color Module Level 3", + "url":"https://www.w3.org/TR/2018/REC-css-color-3-20180619/" + }, + { + "name":"DOMMatrix interface", + "url":"https://www.w3.org/TR/2018/NOTE-matrix-20180412/" + }, + { + "name":"CSS Layout API Level 1", + "url":"https://www.w3.org/TR/2018/WD-css-layout-api-1-20180412/" + }, + { + "name":"CSS Typed OM Level 1", + "url":"https://www.w3.org/TR/2018/WD-css-typed-om-1-20180410/" + }, + { + "name":"CSS Counter Styles Level 3", + "url":"https://www.w3.org/TR/2017/CR-css-counter-styles-3-20171214/" + }, + { + "name":"CSS Backgrounds and Borders Module Level 3", + "url":"https://www.w3.org/TR/2017/CR-css-backgrounds-3-20171017/" + }, + { + "name":"CSS Overflow Module Level 4", + "url":"https://www.w3.org/TR/2017/WD-css-overflow-4-20170613/" + }, + { + "name":"CSS Fill and Stroke Module Level 3", + "url":"https://www.w3.org/TR/2017/WD-fill-stroke-3-20170413/" + }, + { + "name":"CSS Image Values and Replaced Content Module Level 4", + "url":"https://www.w3.org/TR/2017/WD-css-images-4-20170413/" + }, + { + "name":"CSS Rhythmic Sizing", + "url":"https://www.w3.org/TR/2017/WD-css-rhythm-1-20170302/" + }, + { + "name":"Ready-made Counter Styles", + "url":"https://www.w3.org/TR/2017/NOTE-predefined-counter-styles-20170216/" + }, + { + "name":"CSS Snapshot 2017", + "url":"https://www.w3.org/TR/2017/NOTE-css-2017-20170131/" + }, + { + "name":"CSS Round Display Level 1", + "url":"https://www.w3.org/TR/2016/WD-css-round-display-1-20161222/" + }, + { + "name":"Worklets Level 1", + "url":"https://www.w3.org/TR/2016/WD-worklets-1-20160607/" + }, + { + "name":"Cascading Style Sheets Level 2 Revision 2 (CSS 2.2) Specification", + "url":"https://www.w3.org/TR/2016/WD-CSS22-20160412/" + }, + { + "name":"CSS Device Adaptation Module Level 1", + "url":"https://www.w3.org/TR/2016/WD-css-device-adapt-1-20160329/" + }, + { + "name":"CSSOM View Module", + "url":"https://www.w3.org/TR/2016/WD-cssom-view-1-20160317/" + }, + { + "name":"CSS Object Model (CSSOM)", + "url":"https://www.w3.org/TR/2016/WD-cssom-1-20160317/" + }, + { + "name":"CSS Custom Properties for Cascading Variables Module Level 1", + "url":"https://www.w3.org/TR/2015/CR-css-variables-1-20151203/" + }, + { + "name":"CSS Will Change Module Level 1", + "url":"https://www.w3.org/TR/2015/CR-css-will-change-1-20151203/" + }, + { + "name":"CSS Snapshot 2015", + "url":"https://www.w3.org/TR/2015/NOTE-css-2015-20151013/" + }, + { + "name":"CSS Page Floats", + "url":"https://www.w3.org/TR/2015/WD-css-page-floats-3-20150915/" + }, + { + "name":"Priorities for CSS from the Digital Publishing Interest Group", + "url":"https://www.w3.org/TR/2015/WD-dpub-css-priorities-20150820/" + }, + { + "name":"CSS Template Layout Module", + "url":"https://www.w3.org/TR/2015/NOTE-css-template-3-20150326/" + }, + { + "name":"CSS Exclusions Module Level 1", + "url":"https://www.w3.org/TR/2015/WD-css3-exclusions-20150115/" + }, + { + "name":"Compositing and Blending Level 1", + "url":"https://www.w3.org/TR/2015/CR-compositing-1-20150113/" + }, + { + "name":"Fullscreen", + "url":"https://www.w3.org/TR/2014/NOTE-fullscreen-20141118/" + }, + { + "name":"CSS3 Hyperlink Presentation Module", + "url":"https://www.w3.org/TR/2014/NOTE-css3-hyperlinks-20141014/" + }, + { + "name":"Behavioral Extensions to CSS", + "url":"https://www.w3.org/TR/2014/NOTE-becss-20141014/" + }, + { + "name":"CSS TV Profile 1.0", + "url":"https://www.w3.org/TR/2014/NOTE-css-tv-20141014/" + }, + { + "name":"CSS Marquee Module Level 3", + "url":"https://www.w3.org/TR/2014/NOTE-css3-marquee-20141014/" + }, + { + "name":"The CSS ‘Reader’ Media Type", + "url":"https://www.w3.org/TR/2014/NOTE-css3-reader-20141014/" + }, + { + "name":"CSS Presentation Levels Module", + "url":"https://www.w3.org/TR/2014/NOTE-css3-preslev-20141014/" + }, + { + "name":"CSS Mobile Profile 2.0", + "url":"https://www.w3.org/TR/2014/NOTE-css-mobile-20141014/" + }, + { + "name":"CSS Regions Module Level 1", + "url":"https://www.w3.org/TR/2014/WD-css-regions-1-20141009/" + }, + { + "name":"CSS Line Grid Module Level 1", + "url":"https://www.w3.org/TR/2014/WD-css-line-grid-1-20140916/" + }, + { + "name":"CSS Masking Module Level 1", + "url":"https://www.w3.org/TR/2014/CR-css-masking-1-20140826/" + }, + { + "name":"CSS Font Loading Module Level 3", + "url":"https://www.w3.org/TR/2014/WD-css-font-loading-3-20140522/" + }, + { + "name":"CSS Generated Content for Paged Media Module", + "url":"https://www.w3.org/TR/2014/WD-css-gcpm-3-20140513/" + }, + { + "name":"SVG Integration", + "url":"https://www.w3.org/TR/2014/WD-svg-integration-20140417/" + }, + { + "name":"CSS Scoping Module Level 1", + "url":"https://www.w3.org/TR/2014/WD-css-scoping-1-20140403/" + }, + { + "name":"CSS Shapes Module Level 1", + "url":"https://www.w3.org/TR/2014/CR-css-shapes-1-20140320/" + }, + { + "name":"CSS Namespaces Module Level 3", + "url":"https://www.w3.org/TR/2014/REC-css-namespaces-3-20140320/" + }, + { + "name":"CSS Style Attributes", + "url":"https://www.w3.org/TR/2013/REC-css-style-attr-20131107/" + }, + { + "name":"Selectors API Level 2", + "url":"https://www.w3.org/TR/2013/NOTE-selectors-api2-20131017/" + }, + { + "name":"CSS Conditional Rules Module Level 3", + "url":"https://www.w3.org/TR/2013/CR-css3-conditional-20130404/" + }, + { + "name":"CSS Print Profile", + "url":"https://www.w3.org/TR/2013/NOTE-css-print-20130314/" + }, + { + "name":"Selectors API Level 1", + "url":"https://www.w3.org/TR/2013/REC-selectors-api-20130221/" + }, + { + "name":"Media Queries", + "url":"https://www.w3.org/TR/2012/REC-css3-mediaqueries-20120619/" + }, + { + "name":"A MathML for CSS Profile", + "url":"https://www.w3.org/TR/2011/REC-mathml-for-css-20110607/" + }, + { + "name":"Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification", + "url":"https://www.w3.org/TR/2011/REC-CSS2-20110607/" + }, + { + "name":"Cascading Style Sheets (CSS) Snapshot 2010", + "url":"https://www.w3.org/TR/2011/NOTE-css-2010-20110512/" + }, + { + "name":"Cascading Style Sheets (CSS) Snapshot 2007", + "url":"https://www.w3.org/TR/2011/NOTE-css-beijing-20110512/" + }, + { + "name":"Associating Style Sheets with XML documents 1.0 (Second Edition)", + "url":"https://www.w3.org/TR/2010/REC-xml-stylesheet-20101028/" + }, + { + "name":"Document Object Model (DOM) Level 2 Style Specification", + "url":"https://www.w3.org/TR/2000/REC-DOM-Level-2-Style-20001113/" + }, + { + "name":"CSS Techniques for Web Content Accessibility Guidelines 1.0", + "url":"https://www.w3.org/TR/2000/NOTE-WCAG10-CSS-TECHS-20001106/" + }, + { + "name":"Positioning HTML Elements with Cascading Style Sheets", + "url":"https://www.w3.org/TR/1999/WD-positioning-19990902" + }, + { + "name":"CSS Printing Extensions", + "url":"https://www.w3.org/TR/1999/WD-print-19990902" + }, + { + "name":"Aural Cascading Style Sheets (ACSS) Specification", + "url":"https://www.w3.org/TR/1999/WD-acss-19990902" + }, + { + "name":"List of suggested extensions to CSS", + "url":"https://www.w3.org/TR/1998/NOTE-CSS-potential-19981210" + } +] \ No newline at end of file diff --git a/week06/code/test.html b/week06/code/test.html new file mode 100644 index 000000000..7e7f5718a --- /dev/null +++ b/week06/code/test.html @@ -0,0 +1,18 @@ + + + + + + + + + HTML5 + + + +
+ + + + diff --git a/week06/code/test.js b/week06/code/test.js new file mode 100644 index 000000000..737d1157a --- /dev/null +++ b/week06/code/test.js @@ -0,0 +1,609 @@ +const standards = [ + { + "name":"CSS Grid Layout Module Level 2", + "url":"https://www.w3.org/TR/2020/CR-css-grid-2-20200818/" + }, + { + "name":"CSS Cascading and Inheritance Level 4", + "url":"https://www.w3.org/TR/2020/WD-css-cascade-4-20200818/" + }, + { + "name":"CSS Grid Layout Module Level 1", + "url":"https://www.w3.org/TR/2020/CR-css-grid-1-20200818/" + }, + { + "name":"CSS Cascading and Inheritance Level 3", + "url":"https://www.w3.org/TR/2020/CR-css-cascade-3-20200817/" + }, + { + "name":"Requirements for Japanese Text Layout 日本語組版処理の要件(日本語版)", + "url":"https://www.w3.org/TR/2020/NOTE-jlreq-20200811/" + }, + { + "name":"Requirements for Chinese Text Layout中文排版需求", + "url":"https://www.w3.org/TR/2020/WD-clreq-20200801/" + }, + { + "name":"Media Queries Level 5", + "url":"https://www.w3.org/TR/2020/WD-mediaqueries-5-20200731/" + }, + { + "name":"Media Queries Level 4", + "url":"https://www.w3.org/TR/2020/CR-mediaqueries-4-20200721/" + }, + { + "name":"CSS Lists Module Level 3", + "url":"https://www.w3.org/TR/2020/WD-css-lists-3-20200709/" + }, + { + "name":"CSS Inline Layout Module Level 3", + "url":"https://www.w3.org/TR/2020/WD-css-inline-3-20200618/" + }, + { + "name":"CSS Overflow Module Level 3", + "url":"https://www.w3.org/TR/2020/WD-css-overflow-3-20200603/" + }, + { + "name":"CSS Containment Module Level 2", + "url":"https://www.w3.org/TR/2020/WD-css-contain-2-20200603/" + }, + { + "name":"Encoding", + "url":"https://www.w3.org/TR/2020/NOTE-encoding-20200602/" + }, + { + "name":"Requirements for Hangul Text Layout and Typography : 한국어 텍스트 레이아웃 및 타이포그래피를 위한 요구사항", + "url":"https://www.w3.org/TR/2020/NOTE-klreq-20200527/" + }, + { + "name":"CSS Box Sizing Module Level 4", + "url":"https://www.w3.org/TR/2020/WD-css-sizing-4-20200526/" + }, + { + "name":"Ethiopic Layout Requirements", + "url":"https://www.w3.org/TR/2020/WD-elreq-20200526/" + }, + { + "name":"CSS Positioned Layout Module Level 3", + "url":"https://www.w3.org/TR/2020/WD-css-position-3-20200519/" + }, + { + "name":"CSS Display Module Level 3", + "url":"https://www.w3.org/TR/2020/CR-css-display-3-20200519/" + }, + { + "name":"CSS Text Decoration Module Level 4", + "url":"https://www.w3.org/TR/2020/WD-css-text-decor-4-20200506/" + }, + { + "name":"CSS Ruby Layout Module Level 1", + "url":"https://www.w3.org/TR/2020/WD-css-ruby-1-20200429/" + }, + { + "name":"CSS Text Module Level 3", + "url":"https://www.w3.org/TR/2020/WD-css-text-3-20200429/" + }, + { + "name":"CSS Box Alignment Module Level 3", + "url":"https://www.w3.org/TR/2020/WD-css-align-3-20200421/" + }, + { + "name":"CSS Box Model Module Level 4", + "url":"https://www.w3.org/TR/2020/WD-css-box-4-20200421/" + }, + { + "name":"CSS Box Model Module Level 3", + "url":"https://www.w3.org/TR/2020/WD-css-box-3-20200421/" + }, + { + "name":"CSS Color Adjustment Module Level 1", + "url":"https://www.w3.org/TR/2020/WD-css-color-adjust-1-20200402/" + }, + { + "name":"CSS Speech Module", + "url":"https://www.w3.org/TR/2020/CR-css-speech-1-20200310/" + }, + { + "name":"CSS Transforms Module Level 2", + "url":"https://www.w3.org/TR/2020/WD-css-transforms-2-20200303/" + }, + { + "name":"CSS Color Module Level 5", + "url":"https://www.w3.org/TR/2020/WD-css-color-5-20200303/" + }, + { + "name":"CSS Conditional Rules Module Level 4", + "url":"https://www.w3.org/TR/2020/WD-css-conditional-4-20200303/" + }, + { + "name":"Resize Observer", + "url":"https://www.w3.org/TR/2020/WD-resize-observer-1-20200211/" + }, + { + "name":"CSS Scroll Anchoring Module Level 1", + "url":"https://www.w3.org/TR/2020/WD-css-scroll-anchoring-1-20200211/" + }, + { + "name":"Timed Text Markup Language 2 (TTML2) (2nd Edition)", + "url":"https://www.w3.org/TR/2020/CR-ttml2-20200128/" + }, + { + "name":"CSS Basic User Interface Module Level 4", + "url":"https://www.w3.org/TR/2020/WD-css-ui-4-20200124/" + }, + { + "name":"CSS Writing Modes Level 3", + "url":"https://www.w3.org/TR/2019/REC-css-writing-modes-3-20191210/" + }, + { + "name":"CSS Spatial Navigation Level 1", + "url":"https://www.w3.org/TR/2019/WD-css-nav-1-20191126/" + }, + { + "name":"CSS Containment Module Level 1", + "url":"https://www.w3.org/TR/2019/REC-css-contain-1-20191121/" + }, + { + "name":"CSS Text Module Level 4", + "url":"https://www.w3.org/TR/2019/WD-css-text-4-20191113/" + }, + { + "name":"CSS Fonts Module Level 4", + "url":"https://www.w3.org/TR/2019/WD-css-fonts-4-20191113/" + }, + { + "name":"CSS Color Module Level 4", + "url":"https://www.w3.org/TR/2019/WD-css-color-4-20191105/" + }, + { + "name":"CSS Properties and Values API Level 1", + "url":"https://www.w3.org/TR/2019/WD-css-properties-values-api-1-20191025/" + }, + { + "name":"CSS Multi-column Layout Module Level 1", + "url":"https://www.w3.org/TR/2019/WD-css-multicol-1-20191015/" + }, + { + "name":"CSS Images Module Level 3", + "url":"https://www.w3.org/TR/2019/CR-css-images-3-20191010/" + }, + { + "name":"CSS Text Decoration Module Level 3", + "url":"https://www.w3.org/TR/2019/CR-css-text-decor-3-20190813/" + }, + { + "name":"CSS Generated Content Module Level 3", + "url":"https://www.w3.org/TR/2019/WD-css-content-3-20190802/" + }, + { + "name":"CSS Writing Modes Level 4", + "url":"https://www.w3.org/TR/2019/CR-css-writing-modes-4-20190730/" + }, + { + "name":"CSS Table Module Level 3", + "url":"https://www.w3.org/TR/2019/WD-css-tables-3-20190727/" + }, + { + "name":"CSS Syntax Module Level 3", + "url":"https://www.w3.org/TR/2019/CR-css-syntax-3-20190716/" + }, + { + "name":"CSS Animation Worklet API", + "url":"https://www.w3.org/TR/2019/WD-css-animation-worklet-1-20190625/" + }, + { + "name":"CSS Values and Units Module Level 3", + "url":"https://www.w3.org/TR/2019/CR-css-values-3-20190606/" + }, + { + "name":"CSS Overscroll Behavior Module Level 1", + "url":"https://www.w3.org/TR/2019/WD-css-overscroll-1-20190606/" + }, + { + "name":"CSS Intrinsic & Extrinsic Sizing Module Level 3", + "url":"https://www.w3.org/TR/2019/WD-css-sizing-3-20190522/" + }, + { + "name":"CSS Easing Functions Level 1", + "url":"https://www.w3.org/TR/2019/CR-css-easing-1-20190430/" + }, + { + "name":"TTML Media Type Definition and Profile Registry", + "url":"https://www.w3.org/TR/2019/NOTE-ttml-profile-registry-20190411/" + }, + { + "name":"WebVTT: The Web Video Text Tracks Format", + "url":"https://www.w3.org/TR/2019/CR-webvtt1-20190404/" + }, + { + "name":"Non-element Selectors Module Level 1", + "url":"https://www.w3.org/TR/2019/NOTE-selectors-nonelement-1-20190402/" + }, + { + "name":"CSS Scroll Snap Module Level 1", + "url":"https://www.w3.org/TR/2019/CR-css-scroll-snap-1-20190319/" + }, + { + "name":"CSS Pseudo-Elements Module Level 4", + "url":"https://www.w3.org/TR/2019/WD-css-pseudo-4-20190225/" + }, + { + "name":"CSS Transforms Module Level 1", + "url":"https://www.w3.org/TR/2019/CR-css-transforms-1-20190214/" + }, + { + "name":"CSS Values and Units Module Level 4", + "url":"https://www.w3.org/TR/2019/WD-css-values-4-20190131/" + }, + { + "name":"CSS Snapshot 2018", + "url":"https://www.w3.org/TR/2019/NOTE-css-2018-20190122/" + }, + { + "name":"Motion Path Module Level 1", + "url":"https://www.w3.org/TR/2018/WD-motion-1-20181218/" + }, + { + "name":"CSS Fragmentation Module Level 4", + "url":"https://www.w3.org/TR/2018/WD-css-break-4-20181218/" + }, + { + "name":"Filter Effects Module Level 1", + "url":"https://www.w3.org/TR/2018/WD-filter-effects-1-20181218/" + }, + { + "name":"CSS Fragmentation Module Level 3", + "url":"https://www.w3.org/TR/2018/CR-css-break-3-20181204/" + }, + { + "name":"Geometry Interfaces Module Level 1", + "url":"https://www.w3.org/TR/2018/CR-geometry-1-20181204/" + }, + { + "name":"Selectors Level 4", + "url":"https://www.w3.org/TR/2018/WD-selectors-4-20181121/" + }, + { + "name":"CSS Flexible Box Layout Module Level 1", + "url":"https://www.w3.org/TR/2018/CR-css-flexbox-1-20181119/" + }, + { + "name":"CSS Shadow Parts", + "url":"https://www.w3.org/TR/2018/WD-css-shadow-parts-1-20181115/" + }, + { + "name":"Timed Text Markup Language 2 (TTML2)", + "url":"https://www.w3.org/TR/2018/REC-ttml2-20181108/" + }, + { + "name":"Selectors Level 3", + "url":"https://www.w3.org/TR/2018/REC-selectors-3-20181106/" + }, + { + "name":"CSS Paged Media Module Level 3", + "url":"https://www.w3.org/TR/2018/WD-css-page-3-20181018/" + }, + { + "name":"Web Animations", + "url":"https://www.w3.org/TR/2018/WD-web-animations-1-20181011/" + }, + { + "name":"CSS Transitions", + "url":"https://www.w3.org/TR/2018/WD-css-transitions-1-20181011/" + }, + { + "name":"CSS Animations Level 1", + "url":"https://www.w3.org/TR/2018/WD-css-animations-1-20181011/" + }, + { + "name":"CSS Scrollbars Module Level 1", + "url":"https://www.w3.org/TR/2018/WD-css-scrollbars-1-20180925/" + }, + { + "name":"CSS Fonts Module Level 3", + "url":"https://www.w3.org/TR/2018/REC-css-fonts-3-20180920/" + }, + { + "name":"Cascading Style Sheets, level 1", + "url":"https://www.w3.org/TR/2018/SPSD-CSS1-20180913/" + }, + { + "name":"CSS Logical Properties and Values Level 1", + "url":"https://www.w3.org/TR/2018/WD-css-logical-1-20180827/" + }, + { + "name":"CSS Painting API Level 1", + "url":"https://www.w3.org/TR/2018/CR-css-paint-api-1-20180809/" + }, + { + "name":"CSS Basic User Interface Module Level 3 (CSS3 UI)", + "url":"https://www.w3.org/TR/2018/REC-css-ui-3-20180621/" + }, + { + "name":"CSS Color Module Level 3", + "url":"https://www.w3.org/TR/2018/REC-css-color-3-20180619/" + }, + { + "name":"DOMMatrix interface", + "url":"https://www.w3.org/TR/2018/NOTE-matrix-20180412/" + }, + { + "name":"CSS Layout API Level 1", + "url":"https://www.w3.org/TR/2018/WD-css-layout-api-1-20180412/" + }, + { + "name":"CSS Typed OM Level 1", + "url":"https://www.w3.org/TR/2018/WD-css-typed-om-1-20180410/" + }, + { + "name":"CSS Counter Styles Level 3", + "url":"https://www.w3.org/TR/2017/CR-css-counter-styles-3-20171214/" + }, + { + "name":"CSS Backgrounds and Borders Module Level 3", + "url":"https://www.w3.org/TR/2017/CR-css-backgrounds-3-20171017/" + }, + { + "name":"CSS Overflow Module Level 4", + "url":"https://www.w3.org/TR/2017/WD-css-overflow-4-20170613/" + }, + { + "name":"CSS Fill and Stroke Module Level 3", + "url":"https://www.w3.org/TR/2017/WD-fill-stroke-3-20170413/" + }, + { + "name":"CSS Image Values and Replaced Content Module Level 4", + "url":"https://www.w3.org/TR/2017/WD-css-images-4-20170413/" + }, + { + "name":"CSS Rhythmic Sizing", + "url":"https://www.w3.org/TR/2017/WD-css-rhythm-1-20170302/" + }, + { + "name":"Ready-made Counter Styles", + "url":"https://www.w3.org/TR/2017/NOTE-predefined-counter-styles-20170216/" + }, + { + "name":"CSS Snapshot 2017", + "url":"https://www.w3.org/TR/2017/NOTE-css-2017-20170131/" + }, + { + "name":"CSS Round Display Level 1", + "url":"https://www.w3.org/TR/2016/WD-css-round-display-1-20161222/" + }, + { + "name":"Worklets Level 1", + "url":"https://www.w3.org/TR/2016/WD-worklets-1-20160607/" + }, + { + "name":"Cascading Style Sheets Level 2 Revision 2 (CSS 2.2) Specification", + "url":"https://www.w3.org/TR/2016/WD-CSS22-20160412/" + }, + { + "name":"CSS Device Adaptation Module Level 1", + "url":"https://www.w3.org/TR/2016/WD-css-device-adapt-1-20160329/" + }, + { + "name":"CSSOM View Module", + "url":"https://www.w3.org/TR/2016/WD-cssom-view-1-20160317/" + }, + { + "name":"CSS Object Model (CSSOM)", + "url":"https://www.w3.org/TR/2016/WD-cssom-1-20160317/" + }, + { + "name":"CSS Custom Properties for Cascading Variables Module Level 1", + "url":"https://www.w3.org/TR/2015/CR-css-variables-1-20151203/" + }, + { + "name":"CSS Will Change Module Level 1", + "url":"https://www.w3.org/TR/2015/CR-css-will-change-1-20151203/" + }, + { + "name":"CSS Snapshot 2015", + "url":"https://www.w3.org/TR/2015/NOTE-css-2015-20151013/" + }, + { + "name":"CSS Page Floats", + "url":"https://www.w3.org/TR/2015/WD-css-page-floats-3-20150915/" + }, + { + "name":"Priorities for CSS from the Digital Publishing Interest Group", + "url":"https://www.w3.org/TR/2015/WD-dpub-css-priorities-20150820/" + }, + { + "name":"CSS Template Layout Module", + "url":"https://www.w3.org/TR/2015/NOTE-css-template-3-20150326/" + }, + { + "name":"CSS Exclusions Module Level 1", + "url":"https://www.w3.org/TR/2015/WD-css3-exclusions-20150115/" + }, + { + "name":"Compositing and Blending Level 1", + "url":"https://www.w3.org/TR/2015/CR-compositing-1-20150113/" + }, + { + "name":"Fullscreen", + "url":"https://www.w3.org/TR/2014/NOTE-fullscreen-20141118/" + }, + { + "name":"CSS3 Hyperlink Presentation Module", + "url":"https://www.w3.org/TR/2014/NOTE-css3-hyperlinks-20141014/" + }, + { + "name":"Behavioral Extensions to CSS", + "url":"https://www.w3.org/TR/2014/NOTE-becss-20141014/" + }, + { + "name":"CSS TV Profile 1.0", + "url":"https://www.w3.org/TR/2014/NOTE-css-tv-20141014/" + }, + { + "name":"CSS Marquee Module Level 3", + "url":"https://www.w3.org/TR/2014/NOTE-css3-marquee-20141014/" + }, + { + "name":"The CSS ‘Reader’ Media Type", + "url":"https://www.w3.org/TR/2014/NOTE-css3-reader-20141014/" + }, + { + "name":"CSS Presentation Levels Module", + "url":"https://www.w3.org/TR/2014/NOTE-css3-preslev-20141014/" + }, + { + "name":"CSS Mobile Profile 2.0", + "url":"https://www.w3.org/TR/2014/NOTE-css-mobile-20141014/" + }, + { + "name":"CSS Regions Module Level 1", + "url":"https://www.w3.org/TR/2014/WD-css-regions-1-20141009/" + }, + { + "name":"CSS Line Grid Module Level 1", + "url":"https://www.w3.org/TR/2014/WD-css-line-grid-1-20140916/" + }, + { + "name":"CSS Masking Module Level 1", + "url":"https://www.w3.org/TR/2014/CR-css-masking-1-20140826/" + }, + { + "name":"CSS Font Loading Module Level 3", + "url":"https://www.w3.org/TR/2014/WD-css-font-loading-3-20140522/" + }, + { + "name":"CSS Generated Content for Paged Media Module", + "url":"https://www.w3.org/TR/2014/WD-css-gcpm-3-20140513/" + }, + { + "name":"SVG Integration", + "url":"https://www.w3.org/TR/2014/WD-svg-integration-20140417/" + }, + { + "name":"CSS Scoping Module Level 1", + "url":"https://www.w3.org/TR/2014/WD-css-scoping-1-20140403/" + }, + { + "name":"CSS Shapes Module Level 1", + "url":"https://www.w3.org/TR/2014/CR-css-shapes-1-20140320/" + }, + { + "name":"CSS Namespaces Module Level 3", + "url":"https://www.w3.org/TR/2014/REC-css-namespaces-3-20140320/" + }, + { + "name":"CSS Style Attributes", + "url":"https://www.w3.org/TR/2013/REC-css-style-attr-20131107/" + }, + { + "name":"Selectors API Level 2", + "url":"https://www.w3.org/TR/2013/NOTE-selectors-api2-20131017/" + }, + { + "name":"CSS Conditional Rules Module Level 3", + "url":"https://www.w3.org/TR/2013/CR-css3-conditional-20130404/" + }, + { + "name":"CSS Print Profile", + "url":"https://www.w3.org/TR/2013/NOTE-css-print-20130314/" + }, + { + "name":"Selectors API Level 1", + "url":"https://www.w3.org/TR/2013/REC-selectors-api-20130221/" + }, + { + "name":"Media Queries", + "url":"https://www.w3.org/TR/2012/REC-css3-mediaqueries-20120619/" + }, + { + "name":"A MathML for CSS Profile", + "url":"https://www.w3.org/TR/2011/REC-mathml-for-css-20110607/" + }, + { + "name":"Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification", + "url":"https://www.w3.org/TR/2011/REC-CSS2-20110607/" + }, + { + "name":"Cascading Style Sheets (CSS) Snapshot 2010", + "url":"https://www.w3.org/TR/2011/NOTE-css-2010-20110512/" + }, + { + "name":"Cascading Style Sheets (CSS) Snapshot 2007", + "url":"https://www.w3.org/TR/2011/NOTE-css-beijing-20110512/" + }, + { + "name":"Associating Style Sheets with XML documents 1.0 (Second Edition)", + "url":"https://www.w3.org/TR/2010/REC-xml-stylesheet-20101028/" + }, + { + "name":"Document Object Model (DOM) Level 2 Style Specification", + "url":"https://www.w3.org/TR/2000/REC-DOM-Level-2-Style-20001113/" + }, + { + "name":"CSS Techniques for Web Content Accessibility Guidelines 1.0", + "url":"https://www.w3.org/TR/2000/NOTE-WCAG10-CSS-TECHS-20001106/" + }, + { + "name":"Positioning HTML Elements with Cascading Style Sheets", + "url":"https://www.w3.org/TR/1999/WD-positioning-19990902" + }, + { + "name":"CSS Printing Extensions", + "url":"https://www.w3.org/TR/1999/WD-print-19990902" + }, + { + "name":"Aural Cascading Style Sheets (ACSS) Specification", + "url":"https://www.w3.org/TR/1999/WD-acss-19990902" + }, + { + "name":"List of suggested extensions to CSS", + "url":"https://www.w3.org/TR/1998/NOTE-CSS-potential-19981210" + } +] + +const standards = [ + { + "name":"CSS Display Module Level 3", + "url":"https://www.w3.org/TR/2020/CR-css-display-3-20200519/" + } +] + +const iframe = document.createElement("iframe"); +document.body.innerHTML = ""; +document.body.appendChild(iframe); +const happen = (ele,e)=>{ + return new Promise(function(resolve){ + let handler = () => { + resolve(); + ele.removeEventListener(e,handler); + } + ele.addEventListener(e,handler); + }) +} +const sleep = (delay) => { + const start = (new Date()).getTime(); + while ((new Date()).getTime() - start < delay) { + continue + } +} + +const run = async() => { + for(let standard of standards){ + iframe.src = standard.url; + console.log(standard.name); + await sleep(1000) + await happen(iframe,"load"); + let str = iframe.contentDocument.querySelectorAll(".dfn-paneled.css") + + + for(let s of str){ + console.log(s); + // console.log(s.getAttribute('data-dfn-type')==='property'); + // // if(s.getAttribute('data-dfn-type')==='property'){ + // // console.log(s); + // // } + } + console.log(str.length); + } +} +run() diff --git a/week06/code/tt.js b/week06/code/tt.js new file mode 100644 index 000000000..26e6068b7 --- /dev/null +++ b/week06/code/tt.js @@ -0,0 +1,4 @@ + + + +// Object.getPrototypeOf(a) diff --git a/week06/code/w.html b/week06/code/w.html new file mode 100644 index 000000000..dcc939dd4 --- /dev/null +++ b/week06/code/w.html @@ -0,0 +1,19 @@ + + + + + + + + + HTML5 + + + +
+ + + + \ No newline at end of file diff --git a/week06/code/ww.html b/week06/code/ww.html new file mode 100644 index 000000000..8b95e0bc2 --- /dev/null +++ b/week06/code/ww.html @@ -0,0 +1,28 @@ + + + + + + + + + + + + test + + + +
+ + + \ No newline at end of file diff --git a/week06/css-crawler.js.png b/week06/css-crawler.js.png new file mode 100755 index 000000000..933bfe358 Binary files /dev/null and b/week06/css-crawler.js.png differ diff --git a/week07/NOTE.md b/week07/NOTE.md index 50de30414..c192f0496 100644 --- a/week07/NOTE.md +++ b/week07/NOTE.md @@ -1 +1,398 @@ -学习笔记 \ No newline at end of file + + +#### 1. 重学HTML | HTML的定义:XML与SGML +##### SGML:(Standard Generalized Markup Language,标准通用标记语言),在web为发明之前就已经存在了,SGML是国际上定义电子文件结构和内容描述的标准。SGML具有非常复杂的文档结构,主要用于大量高度结构化数据的访问和其他各种工业领域,在分类和索引数据中非常有用。但是它不适用于Web数据描述。 + +##### XML:随着Web应用的不断发展,HTML的局限性也越来越明显地显现了出来,如HTML无法描述数据、可读性差、搜索时间长等。人们又把目光转向SGML,再次改造SGML使之适应现在的网络需求。随着先辈的努力,1998年2月10日,W3C(World WideⅥiebConsortium,万维网联盟)公布XML 1.0标准,XML诞生了。可以说xml是在html和sgml的基础上诞生的。 + +##### XML使用一个简单而又灵活的标准格式,为基于Web的应用提供了一个描述数据和交换数据的有效手段。但是,XML并非是用来取代HTML的。HTML着重如何描述将文件显示在浏览器中,而XML与SGML相近,它着重描述如何将数据以结构化方式表示。 + + +#### HTML 中有用的字符实体 +注释:实体名称对大小写敏感! + +|显示结果 |描述 |实体名称 |实体编号| +|-|-|-|-| +| | 空格| ` `| ` `| +|`< |小于号 |`<`; |`<`;| +|> `|大于号 |`>`| `>`| +|& |和号 |`&` |`&`| +|" |引号 |`"` |`"`| +|' |撇号 | `'`| (IE不支持)`'`| +|¢ |分(cent)| `¢`|` ¢`| +|£ 镑(pound) |`£`|` £`| +|¥ 元(yen) |`¥ `|`¥`| +|€ 欧元(euro) |`€`|` €`| +|§ 小节 |`§`|` §`| +|© 版权(copyright) |`© `|`©`| +|® 注册商标 |`® `|`®`| +|™ 商标 |`™ `|`™`| +|× 乘号 |`× `|`×`| +|÷ 除号 |`÷ `|`÷`| + +#### 2. 重学HTML | HTML标签语义 +HTML5 中的新语义元素 +这些链接指向完整的 HTML 参考手册。 + +|标签 |描述| +|-|-| +|`
`| 定义文章。 +|`