UNPKG

cirsim

Version:

Cirsim Circuit Simulator

1,746 lines (1,386 loc) 3.37 MB
/******/ (() => { // webpackBootstrap /******/ var __webpack_modules__ = ({ /***/ "./index.js": /*!******************!*\ !*** ./index.js ***! \******************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "Cirsim": () => (/* reexport safe */ _src_Cirsim_Cirsim__WEBPACK_IMPORTED_MODULE_2__.Cirsim), /* harmony export */ "default": () => (/* reexport safe */ _src_Cirsim_Cirsim__WEBPACK_IMPORTED_MODULE_2__.Cirsim) /* harmony export */ }); /* harmony import */ var _src_public_path__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./src/public-path */ "./src/public-path.js"); /* harmony import */ var _src_public_path__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_src_public_path__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _src_polyfills_all__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./src/polyfills/all */ "./src/polyfills/all.js"); /* harmony import */ var _src_Cirsim_Cirsim__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./src/Cirsim/Cirsim */ "./src/Cirsim/Cirsim.js"); /* harmony import */ var _src_cirsim_scss__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./src/_cirsim.scss */ "./src/_cirsim.scss"); /* harmony import */ var _src_Cirsim_Utility_Ready__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./src/Cirsim/Utility/Ready */ "./src/Cirsim/Utility/Ready.js"); // The public-path module must be imported first! // This allows Cirsim to be used as Cirsim or Cirsim.Cirsim // since the version in cl/cirsim is Cirsim.Cirsim. _src_Cirsim_Cirsim__WEBPACK_IMPORTED_MODULE_2__.Cirsim.Cirsim = _src_Cirsim_Cirsim__WEBPACK_IMPORTED_MODULE_2__.Cirsim; // Automatically install into div.cirsim-install, where the text // contents of the tag are JSON to configure Cirsim _src_Cirsim_Utility_Ready__WEBPACK_IMPORTED_MODULE_4__.Ready.go(function () { var elements = document.querySelectorAll('div.cirsim-install'); for (var i = 0; i < elements.length; i++) { var element = elements[i]; element.classList.remove('cirsim-install'); var json = JSON.parse(element.textContent); element.innerHTML = ''; var cirsim = new _src_Cirsim_Cirsim__WEBPACK_IMPORTED_MODULE_2__.Cirsim(element, json); cirsim.startNow(); element.style.display = 'block'; } }); __webpack_require__.g.Cirsim = _src_Cirsim_Cirsim__WEBPACK_IMPORTED_MODULE_2__.Cirsim; /***/ }), /***/ "./src/Cirsim/Bend.js": /*!****************************!*\ !*** ./src/Cirsim/Bend.js ***! \****************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "Bend": () => (/* binding */ Bend) /* harmony export */ }); /* harmony import */ var _Selectable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Selectable */ "./src/Cirsim/Selectable.js"); /** * Object that represents a bend in a connection line. * @constructor */ var Bend = function Bend(x, y) { _Selectable__WEBPACK_IMPORTED_MODULE_0__.Selectable.call(this); this.connection = null; // Connection this bend is associated with if (x !== undefined) { this.x = x; this.moveX = x; } if (y !== undefined) { this.y = y; this.moveY = y; } }; Bend.prototype = Object.create(_Selectable__WEBPACK_IMPORTED_MODULE_0__.Selectable.prototype); Bend.prototype.constructor = Bend; Bend.prototype.touchRange = 12; Bend.prototype.size = 4; Bend.prototype.clone = function () { var copy = new Bend(); copy.copyFrom(this); return copy; }; Bend.prototype.draw = function (context, view) { if (view.selection.isSelected(this)) { this.selectStyle(context, view); context.beginPath(); context.arc(this.x, this.y, this.size, 0, 2 * Math.PI); context.fill(); } }; /** * Determine if we have touched this bend * @param x * @param y * @returns {boolean} */ Bend.prototype.touch = function (x, y) { return Math.abs(x - this.x) + Math.abs(y - this.y) <= this.touchRange; }; /** * Delete this bend, removing it from the connection. * @param caller Calling object. * that object. */ Bend.prototype["delete"] = function (caller) { this.connection.removeBend(this); }; /** * Save this bend as an object suitable for conversion to JSON * @returns {{x: *, y: *}} */ Bend.prototype.save = function () { return { "x": this.x, "y": this.y }; }; /***/ }), /***/ "./src/Cirsim/Circuit.js": /*!*******************************!*\ !*** ./src/Cirsim/Circuit.js ***! \*******************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "Circuit": () => (/* binding */ Circuit) /* harmony export */ }); /* harmony import */ var _Component_CircuitRef__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Component/CircuitRef */ "./src/Cirsim/Component/CircuitRef.js"); /* harmony import */ var _Connection__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./Connection */ "./src/Cirsim/Connection.js"); /* harmony import */ var _Utility_Sanitize__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./Utility/Sanitize */ "./src/Cirsim/Utility/Sanitize.js"); /* harmony import */ var _Utility_Rect__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./Utility/Rect */ "./src/Cirsim/Utility/Rect.js"); /* harmony import */ var _Circuits__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./Circuits */ "./src/Cirsim/Circuits.js"); function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } /** * Construct a circuit * @param name Name of the circuit * @constructor */ var Circuit = function Circuit(name) { this.circuits = null; this.components = []; this.name = name; this.width = this.defWidth; this.height = this.defHeight; // Previous copy in the copy stack this.prev = null; /** * See if some object has been touched by the mouse. * @param x Mouse X * @param y Mouse Y * @return Touched element or null if none */ this.touch = function (x, y) { // // First we try to grab a component. // We do this in reverse order so we are selecting // from top down. // for (var i = this.components.length - 1; i >= 0; i--) { var component = this.components[i]; var grabbed = component.touch(x, y); if (grabbed !== null) { return grabbed; } } return null; }; /** * Advance the animation by delta time... * @param delta */ this.advance = function (delta) { var any = false; for (var i = 0; i < this.components.length; i++) { var component = this.components[i]; if (component.advance(delta)) { any = true; } } return any; }; }; Circuit.prototype.defWidth = 1920; ///< Default width Circuit.prototype.defHeight = 1080; ///< Default height /** * Create a backup clone of this circuit * @returns {Circuit} */ Circuit.prototype.clone = function () { var copy = new Circuit(this.name); copy.width = this.width; copy.height = this.height; // Add to the copy stack copy.prev = this.prev; this.prev = copy; // Iterate over the components, cloning each of them for (var i = 0; i < this.components.length; i++) { var component = this.components[i]; var componentCopy = component.clone(); copy.add(componentCopy); } // Again we iterate over the components, this time // cloning the output connections. for (var _i = 0; _i < this.components.length; _i++) { var component = this.components[_i]; for (var j = 0; j < component.outs.length; j++) { var out = component.outs[j]; for (var k = 0; k < out.to.length; k++) { out.to[k].clone(); } } } return copy; }; /** * Create a backup clone of this circuit * @returns {Circuit} */ Circuit.prototype.copy_clone = function () { var copy = new Circuit(this.name); copy.width = this.width; copy.height = this.height; // Iterate over the components, cloning each of them for (var i = 0; i < this.components.length; i++) { var component = this.components[i]; var componentCopy = component.clone(); copy.add(componentCopy); } // Again we iterate over the components, this time // cloning the output connections. for (var i = 0; i < this.components.length; i++) { var component = this.components[i]; for (var j = 0; j < component.outs.length; j++) { var out = component.outs[j]; for (var k = 0; k < out.to.length; k++) { out.to[k].clone(); } } } return copy; }; /** * Update circuit after a circuit change. * This is used by CircuitRef components to ensure * references are always correct. */ Circuit.prototype.update = function () { var _iterator = _createForOfIteratorHelper(this.components), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var component = _step.value; component.update(); } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } }; Circuit.prototype.draw = function (context, view) { this.components.forEach(function (component, index, array) { component.draw(context, view); }); }; Circuit.prototype.newTab = function () { // There was code here to iterate over the components // in reverse order. I don't recall why that was. I think // it may be a holdover from the circuits being in reverse // order. I'm removed it and will see if it breaks anything. // for(let i=this.components.length-1; i>= 0; i--) { for (var i = 0; i < this.components.length; i++) { var component = this.components[i]; // Tell any components that need to know that // we have selected a new tab. This is // important for the reference component. component.newTab(); } }; Circuit.prototype.recompute = function () { for (var i = 0; i < this.components.length; i++) { // Ensure everything get recomputed this.components[i].pending(); } }; /** * Test if components or bends are contained in a given rectangle. * @param rect Rect object * @returns {Array} Array of all contained components */ Circuit.prototype.inRect = function (rect) { var ret = []; for (var i = this.components.length - 1; i >= 0; i--) { this.components[i].inRect(rect, ret); } return ret; }; Circuit.prototype.snapIt = function (item) { if (this.circuits.snap) { item.x = this.circuits.grid * Math.round(item.x / this.circuits.grid); item.y = this.circuits.grid * Math.round(item.y / this.circuits.grid); } }; Circuit.prototype.add = function (component) { this.components.push(component); component.added(this); return component; }; /** * Delete a specific item from the list of components * @param toDelete Item to delete */ Circuit.prototype["delete"] = function (toDelete) { for (var i = 0; i < this.components.length; i++) { if (this.components[i] === toDelete) { this.components.splice(i, 1); break; } } }; /** * Determine if x,y touches a component In * @param x * @param y */ Circuit.prototype.touchIn = function (x, y) { for (var i = this.components.length - 1; i >= 0; i--) { var component = this.components[i]; var touched = component.touchIn(x, y); if (touched !== null) { return touched; } } return null; }; /** * Determine if x,y touches a component Out * @param x * @param y */ Circuit.prototype.touchOut = function (x, y) { for (var i = this.components.length - 1; i >= 0; i--) { var component = this.components[i]; var touched = component.touchOut(x, y); if (touched !== null) { return touched; } } return null; }; /** * Save this object into an object suitable for conversion to * a JSON object for storage. * @returns Object */ Circuit.prototype.save = function () { // Iterate over the components, saving each of them var comps = []; for (var i = 0; i < this.components.length; i++) { var component = this.components[i]; // Set an ID on each component // component.id = "c" + (i + 1001); comps.push(component.save()); } // Then iterate over the connections, saving each of them var connections = []; for (var _i2 = 0; _i2 < this.components.length; _i2++) { var _component = this.components[_i2]; connections = connections.concat(_component.saveConnections()); } return { "name": this.name, "width": this.width, "height": this.height, "components": comps, "connections": connections }; }; /** * Load this object from an object that was converted from a * JSON object for storage. * @param obj */ Circuit.prototype.load = function (obj) { this.name = _Utility_Sanitize__WEBPACK_IMPORTED_MODULE_2__.Sanitize.sanitize(obj.name); this.width = +obj.width; this.height = +obj.height; // Load the components var compsMap = {}; // Map from component ID to component object for (var i = 0; i < obj.components.length; i++) { var componentObj = obj.components[i]; var componentProto = void 0; if (componentObj.type === "CircuitRef") { componentProto = _Component_CircuitRef__WEBPACK_IMPORTED_MODULE_0__.CircuitRef; } else { componentProto = this.circuits.model.main.components.get(componentObj.type); } if (componentProto !== null) { var component = new componentProto(); component.circuit = this; component.load(componentObj); compsMap[component.id] = component; this.add(component); } else { console.log(componentObj); } } // Load the connections for (var _i3 = 0; _i3 < obj.connections.length; _i3++) { var connectionObj = obj.connections[_i3]; var fmComp = compsMap[connectionObj["from"]]; if (fmComp === undefined) { console.log("From object undefined"); console.log(this); console.log(connectionObj); continue; } var toComp = compsMap[connectionObj["to"]]; if (toComp === undefined) { console.log("To object undefined"); console.log(this); console.log(connectionObj); continue; } var outNdx = connectionObj["out"]; var inNdx = connectionObj["in"]; var connection = this.connect(fmComp, outNdx, toComp, inNdx); if (connection !== null) { connection.load(connectionObj); } } }; /** * Get a component by it's naming * @param naming Naming to search for * @returns {*} */ Circuit.prototype.getComponentByNaming = function (naming) { for (var i = 0; i < this.components.length; i++) { var component = this.components[i]; if (component.naming === naming) { return component; } } return null; }; /** * Get all components by type * @param type Naming to search for * @returns Array with collection of components of that type */ Circuit.prototype.getComponentsByType = function (type) { var components = []; for (var i = 0; i < this.components.length; i++) { var component = this.components[i]; if (component.constructor.type === type) { components.push(component); } } return components; }; Circuit.prototype.mouseUp = function () { for (var i = 0; i < this.components.length; i++) { var component = this.components[i]; component.mouseUp(); } }; Circuit.prototype.connect = function (outObj, outNdx, inObj, inNdx) { if (outObj.outs.length <= outNdx || inObj.ins.length <= inNdx) { return null; } return new _Connection__WEBPACK_IMPORTED_MODULE_1__.Connection(outObj.outs[outNdx], inObj.ins[inNdx]); }; Circuit.prototype.getComponentsByType = function (type) { var ret = []; for (var i = 0; i < this.components.length; i++) { var component = this.components[i]; if (component.constructor.type === type) { ret.push(component); } } return ret; }; /** * Determine the maximum size in each dimension for this circuit. * Does include an extra 16 pixel bias in each dimension to account for * inputs and outputs. * @returns {{x: number, y: number}} */ Circuit.prototype.maxXY = function () { var maxX = 1; var maxY = 1; for (var i = 0; i < this.components.length; i++) { var bounds = this.components[i].bounds(); if (bounds.right > maxX) { maxX = bounds.right; } if (bounds.bottom > maxY) { maxY = bounds.bottom; } } return { x: maxX + 16, y: maxY + 16 }; }; /** * Compute a bounding box that encloses all of this circuit. * @returns {*} */ Circuit.prototype.bounds = function () { if (this.components.length === 0) { return new _Utility_Rect__WEBPACK_IMPORTED_MODULE_3__.Rect(); } var bounds = this.components[0].bounds(); for (var i = 0; i < this.components.length; i++) { var b = this.components[i].bounds(); bounds.expand(b); } return bounds; }; Circuit.prototype.pending = function () { for (var i = 0; i < this.components.length; i++) { var component = this.components[i]; component.pending(); } }; Circuit.prototype.getName = function () { return this.name; }; Circuit.prototype.setName = function (name) { this.name = name; }; /** * Obtain basic statistics about this circuit * @returns {{name: *, numComponents: Number, numConnections: number, width: *, height: *}} */ Circuit.prototype.stats = function () { var numConnections = 0; this.components.forEach(function (component) { component.outs.forEach(function (out) { numConnections += out.to.length; }); }); return { name: this.name, numComponents: this.components.length, numConnections: numConnections, width: this.width, height: this.height }; }; Circuit.prototype.moveToFront = function (component) { for (var i = 0; i < this.components.length; i++) { if (this.components[i] === component) { this.components.splice(i, 1); this.components.push(component); break; } } }; /** * Return all CircuitRef components that refer to a circuit * @param circuit Circuit we are testing. If omitted, all CircuitRef components are returned. * @return array of CircuitRef components. */ Circuit.prototype.references = function (circuit) { var references = []; var _iterator2 = _createForOfIteratorHelper(this.components), _step2; try { for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { var component = _step2.value; if (component instanceof _Component_CircuitRef__WEBPACK_IMPORTED_MODULE_0__.CircuitRef) { if (circuit !== undefined) { if (component.circuitName === circuit.name) { references.push(component); } } else { references.push(component); } } } } catch (err) { _iterator2.e(err); } finally { _iterator2.f(); } return references; }; /***/ }), /***/ "./src/Cirsim/Circuits.js": /*!********************************!*\ !*** ./src/Cirsim/Circuits.js ***! \********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "Circuits": () => (/* binding */ Circuits) /* harmony export */ }); /* harmony import */ var _Simulation__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Simulation */ "./src/Cirsim/Simulation.js"); /* harmony import */ var _Circuit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./Circuit */ "./src/Cirsim/Circuit.js"); /* harmony import */ var _Utility_Sanitize__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./Utility/Sanitize */ "./src/Cirsim/Utility/Sanitize.js"); function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } /** * A collection of circuit objects * @param model The model we are a member of * @param simulation The simulation object that simulates operation of the circuits * @constructor */ var Circuits = function Circuits(model, simulation) { this.model = model; this.circuits = []; this.grid = 8; this.snap = true; this.id = model !== null ? model.id : undefined; // If none is supplied, create a simulation object this.simulation = simulation ? simulation : new _Simulation__WEBPACK_IMPORTED_MODULE_0__.Simulation(); // Previous copy in the copy stack this.prev = null; }; /** * Add a circuit to this collection of circuits * @param circuit */ Circuits.prototype.add = function (circuit) { this.circuits.push(circuit); circuit.circuits = this; return circuit; }; Circuits.prototype.insert = function (circuit) { this.circuits.unshift(circuit); circuit.circuits = this; return circuit; }; /** * Get the collection of circuits. * @returns Array of Circuit objects (copy) */ Circuits.prototype.getCircuits = function () { return this.circuits.slice(); }; /** * Get a circuit by name * @param name Name of the circuit * @returns Circuit object or null */ Circuits.prototype.getCircuit = function (name) { for (var i = 0; i < this.circuits.length; i++) { var circuit = this.circuits[i]; if (circuit.name === name) { return circuit; } } return null; }; Circuits.prototype.advance = function (delta) { var ret = false; for (var i = 0; i < this.circuits.length; i++) { var circuit = this.circuits[i]; if (circuit.advance(delta)) { ret = true; } } return ret; }; /** * Determine if a circuit can be deleted. * @param ndx Index into the circuits. */ Circuits.prototype.canDelete = function (ndx) { if (ndx === 0) { // The main circuit (first) cannot be deleted return false; } // Do any circuits to the left refer to this one? var circuit = this.circuits[ndx]; for (var i = 0; i < ndx; i++) { var references = this.circuits[i].references(circuit); if (references.length > 0) { return false; } } return true; }; /** * Determine if a circuit can be moved left as a tab. * @param ndx Index into the circuits. * @returns {boolean} True if can be moved left */ Circuits.prototype.canMoveLeft = function (ndx) { // First two tabs cannot be moved left at all if (ndx < 2) { return false; } // Does the circuit to the left refer to this one? var circuit = this.circuits[ndx]; var references = this.circuits[ndx - 1].references(circuit); return references.length === 0; }; /** * Determine if a circuit can be moved right as a tab * @param ndx Index into the circuits. * @returns {boolean} True if can be move right */ Circuits.prototype.canMoveRight = function (ndx) { // First tab cannot be moved at all. Last tab can't // move to the right. if (ndx === 0 || ndx === this.circuits.length - 1) { return false; } // What does this circuit refer to? var right = this.circuits[ndx + 1].name; var references = this.circuits[ndx].references(); var _iterator = _createForOfIteratorHelper(references), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var reference = _step.value; if (reference.circuitName === right) { return false; } } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } return true; }; Circuits.prototype.moveLeft = function (ndx) { if (this.canMoveLeft(ndx)) { this.model.backup(); var t = this.circuits[ndx - 1]; this.circuits[ndx - 1] = this.circuits[ndx]; this.circuits[ndx] = t; return true; } return false; }; Circuits.prototype.moveRight = function (ndx) { if (this.canMoveRight(ndx)) { this.model.backup(); var t = this.circuits[ndx + 1]; this.circuits[ndx + 1] = this.circuits[ndx]; this.circuits[ndx] = t; return true; } return false; }; Circuits.prototype.rename = function (ndx, name) { this.model.backup(); var circuit = this.circuits[ndx]; // Rename any references to this circuit for (var i = 0; i < ndx; i++) { var references = this.circuits[i].references(circuit); var _iterator2 = _createForOfIteratorHelper(references), _step2; try { for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { var reference = _step2.value; reference.circuitName = name; } } catch (err) { _iterator2.e(err); } finally { _iterator2.f(); } } circuit.setName(name); }; Circuits.prototype.newTab = function () { // for(let i=0; i<this.circuits.length; i++) { // this.circuits[i].newTab(); // } for (var i = this.circuits.length - 1; i >= 0; i--) { this.circuits[i].newTab(); } }; Circuits.prototype.recompute = function () { //for(let i=0; i<this.circuits.length; i++) { for (var i = this.circuits.length - 1; i >= 0; i--) { this.circuits[i].recompute(); } }; /** * Create a backup clone of this circuit * @returns {Circuits} */ Circuits.prototype.clone = function () { var copy = new Circuits(this.model, this.simulation); copy.grid = this.grid; copy.snap = this.snap; // Add to the copy stack copy.prev = this.prev; this.prev = copy; // Copy the circuit objects for (var i = 0; i < this.circuits.length; i++) { var circuit = this.circuits[i]; copy.add(circuit.clone()); } return copy; }; /** * Update circuits after a circuit change. * This is used by CircuitRef components to ensure * references are always correct. * @param circuit Update up until this circuit */ Circuits.prototype.update = function (circuit) { var _iterator3 = _createForOfIteratorHelper(this.circuits), _step3; try { for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) { var c = _step3.value; if (c === circuit) { break; } c.update(); } } catch (err) { _iterator3.e(err); } finally { _iterator3.f(); } }; Circuits.prototype.toJSON = function () { return JSON.stringify(this.save()); }; /** * Load the circuits from a JSON-encoded object * @param json */ Circuits.prototype.fmJSON = function (json) { var obj = JSON.parse(json); this.load(obj); }; /** * Save this object into an object suitable for conversion to * a JSON object for storage. * @returns Object */ Circuits.prototype.save = function () { var cirs = []; for (var i = 0; i < this.circuits.length; i++) { var circuit = this.circuits[i]; cirs.push(circuit.save()); } var obj = { "grid": this.grid, "circuits": cirs, "id": this.id }; if (this.snap) { obj.snap = true; } return obj; }; /** * Load this object from an object converted from a JSON * object used for storage. * @param obj */ Circuits.prototype.load = function (obj) { this.grid = +obj["grid"]; this.snap = _Utility_Sanitize__WEBPACK_IMPORTED_MODULE_2__.Sanitize.boolean(obj["snap"]); this.prev = null; this.circuits = []; if (obj["id"] !== undefined) { this.id = _Utility_Sanitize__WEBPACK_IMPORTED_MODULE_2__.Sanitize.sanitize(obj["id"]); } // // Load circuits in reverse order // for (var i = obj.circuits.length - 1; i >= 0; i--) { var circuitObj = obj.circuits[i]; var circuit = new _Circuit__WEBPACK_IMPORTED_MODULE_1__.Circuit(circuitObj.name); this.insert(circuit); circuit.load(circuitObj); } // In reverse order, ensure all circuits have // had compute called on all components for (var _i = this.circuits.length - 1; _i >= 0; _i--) { this.circuits[_i].pending(); } }; Circuits.prototype.addCircuit = function (name) { var circuit = new _Circuit__WEBPACK_IMPORTED_MODULE_1__.Circuit(name); this.add(circuit); }; /** * Delete a circuit by the index to the circuit * @param index Index into the circuits array */ Circuits.prototype.deleteCircuitByIndex = function (index) { this.circuits.splice(index, 1); }; /** * Get a component by it's naming * @param naming Naming to search for * @returns {*} */ Circuits.prototype.getComponentByNaming = function (naming) { for (var i = 0; i < this.circuits.length; i++) { var circuit = this.circuits[i]; var pin = circuit.getComponentByNaming(naming); if (pin !== null) { return pin; } } return null; }; /** * Get all components by type * @param type Naming to search for * @returns Array with collection of components of that type */ Circuits.prototype.getComponentsByType = function (type) { var components = []; for (var i = 0; i < this.circuits.length; i++) { var circuit = this.circuits[i]; var c = circuit.getComponentsByType(type); components = components.concat(c); } return components; }; /** * Replace a circuit that currently exists with a new version. */ Circuits.prototype.replaceCircuit = function (circuit) { circuit.circuits = this; for (var i = 0; i < this.circuits.length; i++) { if (this.circuits[i].name === circuit.name) { this.circuits[i] = circuit; // Ensure all components in the new circuit are pending, so they // all get updated. circuit.components.forEach(function (component) { component.pending(); }); // Force this to appear to be a new tab this.model.newTab(); break; } } }; /***/ }), /***/ "./src/Cirsim/Cirsim.js": /*!******************************!*\ !*** ./src/Cirsim/Cirsim.js ***! \******************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "Cirsim": () => (/* binding */ Cirsim) /* harmony export */ }); /* harmony import */ var _Main__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Main */ "./src/Cirsim/Main.js"); /* harmony import */ var _Options__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./Options */ "./src/Cirsim/Options.js"); /* harmony import */ var _Components__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./Components */ "./src/Cirsim/Components.js"); /* harmony import */ var _Component_All__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./Component/All */ "./src/Cirsim/Component/All.js"); /* harmony import */ var _Utility_Ready__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./Utility/Ready */ "./src/Cirsim/Utility/Ready.js"); /** * Create an instance of Cirsim * * This creates a single Instance that manages the * components and starts actual Cirsim windows. * * Construct and start running like this: * * Given an HTML div: * <div id="cirsim"></div> * * The following script starts Cirsim in that div: * * var cirsim = new Cirsim('#cirsim'); * cirsim.start(); * * @param sel Selector to create Cirsim in (can be many) * @param options An object containing Cirsim options. * @constructor */ var Cirsim = function Cirsim(sel, options) { var _this = this; // // Master set of the version // var PACKAGE = __webpack_require__(/*! ../../package.json */ "./package.json"); this.version = PACKAGE.version; // // Determine the root directory for Cirsim // This is the directory containing cirsim.js or // cirsim.min.js // this.root = __webpack_require__.p; // Record the selector this.sel = sel; // The Options object that manages user options this.options = new _Options__WEBPACK_IMPORTED_MODULE_1__.Options(options); // // Install all components and configure standard // Cirsim palettes. // this.components = new _Components__WEBPACK_IMPORTED_MODULE_2__.Components(); (0,_Component_All__WEBPACK_IMPORTED_MODULE_3__.All)(this.components); // A collection of Main objects. var mains = []; // A collection of tests. // We collect those in Cirsim because the actual // Main may not be created, yet. var tests = []; /** * Start Cirsim running, creating the user interface. * This does wait for document ready before calling * this.startNow() unless we are running in no-window * mode. In that case it returns a started instance. */ this.start = function () { if (sel === null) { return _this.startNow(); } _Utility_Ready__WEBPACK_IMPORTED_MODULE_4__.Ready.go(function () { _this.startNow(); }); }; /** * Start Cirsim running now. Does not wait for document ready. */ this.startNow = function () { if (sel !== null) { if (sel instanceof Element) { var main = new _Main__WEBPACK_IMPORTED_MODULE_0__.Main(_this, sel, tests); mains.push(main); } else { var elements = document.querySelectorAll(sel); for (var i = 0; i < elements.length; i++) { var element = elements[i]; var _main = new _Main__WEBPACK_IMPORTED_MODULE_0__.Main(_this, element, tests); mains.push(_main); } } if (mains.length === 1) { if (_this.options.global !== null) { __webpack_require__.g[_this.options.global] = mains[0]; } return mains[0]; } } else { _this.options.display = 'none'; var _main2 = new _Main__WEBPACK_IMPORTED_MODULE_0__.Main(_this, null, tests); mains.push(_main2); return _main2; } return null; }; /** * Get all active instances of Cirsim that are running. * @returns {Array} Array of objects of type Main. * @deprecated This is going away */ this.getInstances = function () { return mains; }; /** * Add a test that is available to run * * The underlying test is a JavaScript object with these tags: * * tag: A tag to identify the test * name: Name of the test, what will appear in menus * input: Array of input labels * output: Array of output labels * test: Array of tests, each an array of input/expected * staff: true if this is staff testing (no saving) * * @param test Test to add. Can be Javascript object, JSON or base64 * encoded JSON. */ this.addTest = function (test) { tests.push(test); }; /** * Run a test by name * @param test */ this.runTest = function (test) { mains.forEach(function (main) { main.runTest(test); }); }; }; /***/ }), /***/ "./src/Cirsim/Component.js": /*!*********************************!*\ !*** ./src/Cirsim/Component.js ***! \*********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "Component": () => (/* binding */ Component) /* harmony export */ }); /* harmony import */ var _Selectable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Selectable */ "./src/Cirsim/Selectable.js"); /* harmony import */ var _In__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./In */ "./src/Cirsim/In.js"); /* harmony import */ var _Out__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./Out */ "./src/Cirsim/Out.js"); /* harmony import */ var _OutInv__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./OutInv */ "./src/Cirsim/OutInv.js"); /* harmony import */ var _Connection__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./Connection */ "./src/Cirsim/Connection.js"); /* harmony import */ var _Dlg_ComponentPropertiesDlg__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./Dlg/ComponentPropertiesDlg */ "./src/Cirsim/Dlg/ComponentPropertiesDlg.js"); /* harmony import */ var dompurify__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! dompurify */ "../../.yarn/cache/dompurify-npm-2.2.9-1a93a7440c-8673be49ae.zip/node_modules/dompurify/dist/purify.js"); /* harmony import */ var dompurify__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(dompurify__WEBPACK_IMPORTED_MODULE_6__); /* harmony import */ var _Utility_Rect__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./Utility/Rect */ "./src/Cirsim/Utility/Rect.js"); function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } /** * Base object for a component in a circuit * @constructor */ var Component = function Component() { _Selectable__WEBPACK_IMPORTED_MODULE_0__.Selectable.call(this); var circuit = null; Object.defineProperty(this, 'circuit', { get: function get() { return circuit; }, set: function set(value) { circuit = value; } }); this.height = 10; this.width = 10; this.prev = null; this.id = ''; // Will be set to a unique id for this component this.circuit = null; this.naming = null; // Naming, as in U1 or I1 this.ins = []; this.outs = []; }; Component.prototype = Object.create(_Selectable__WEBPACK_IMPORTED_MODULE_0__.Selectable.prototype); Component.prototype.constructor = Component; /** * Prefix for component naming */ Component.prototype.prefix = "U"; Component.prototype.nameRequired = false; Component.prototype.delay = 11; ///< Propagation delay in nanoseconds /** * Assign this component a unique ID. This is done when a * component is created by the view. */ Component.prototype.brand = function () { // Every component get a unique ID when it is created this.id = 'c' + ++Component.maxId; }; /// Maximum ID integer value for any component Component.maxId = 1000; Component.prototype.copyFrom = function (component) { this.height = component.height; this.width = component.width; this.prev = component.prev; this.naming = component.naming; this.id = component.id; component.prev = this; _Selectable__WEBPACK_IMPORTED_MODULE_0__.Selectable.prototype.copyFrom.call(this, component); // // Copy input and output states // for (var i = 0; i < this.ins.length; i++) { this.ins[i].copyFrom(component.ins[i]); } for (var _i = 0; _i < this.outs.length; _i++) { this.outs[_i].copyFrom(component.outs[_i]); } }; Component.prototype.drop = function () { if (this.x < this.width / 2) { this.x = this.width / 2; } if (this.y < this.height / 2) { this.y = this.height / 2; } }; Component.prototype.grab = function () { _Selectable__WEBPACK_IMPORTED_MODULE_0__.Selectable.prototype.grab.call(this); this.circuit.moveToFront(this); }; Component.prototype.mouseUp = function () {}; /** * Called when a component is added to a circuit * @param circuit */ Component.prototype.added = function (circuit) { this.circuit = circuit; if (this.naming === null && this.nameRequired) { // Create a new name for (var i = 1;; i++) { var naming = void 0; if (this.prefix.charAt(0) === "*") { if (i <= 26) { naming = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.charAt(i - 1); } else { naming = this.prefix.charAt(1) + (i - 26); } } else { naming = this.prefix + i; } var existing = this.circuit.getComponentByNaming(naming); if (existing === null) { this.naming = naming; break; } } } }; /** * Add an input to this component * @param x Relative X location * @param y Relative Y location * @param len Length of the line to draw for the input * @return {In} */ Component.prototype.addIn = function (x, y, len, name) { var inObj = new _In__WEBPACK_IMPORTED_MODULE_1__.In(this, x, y, len, name); inObj.index = this.ins.length; this.ins.push(inObj); return inObj; }; /** * Add an output to this component * @param x Relative X location * @param y Relative Y location * @param len Length of the line to draw for the output * @return Created output object */ Component.prototype.addOut = function (x, y, len, name, inv) { var outObj = new _Out__WEBPACK_IMPORTED_MODULE_2__.Out(this, x, y, len, name, inv); outObj.index = this.outs.length; this.outs.push(outObj); return outObj; }; /** * Add an inverse output to this component * @param x Relative X location * @param y Relative Y location * @param len Length of the line to draw for the output * @return Created output object */ Component.prototype.addOutInv = function (x, y, len, name, inv) { var outObj = new _OutInv__WEBPACK_IMPORTED_MODULE_3__.OutInv(this, x, y, len, name, inv); outObj.index = this.outs.length; this.outs.push(outObj); return outObj; }; /** * Try to touch this component or some part of * the component. * @param x Mouse X * @param y Mouse Y */ Component.prototype.touch = function (x, y) { // First, try to touch the inputs and outputs var touched = this.touchOut(x, y); if (touched !== null) { // We have touched an Out connector. Add a connection // for this output, but with no current "to" return new _Connection__WEBPACK_IMPORTED_MODULE_4__.Connection(touched, null); } touched = this.touchIn(x, y); if (touched !== null) { // We have touched an In connector. Add a connection // for this input, but with no current "from" return new _Connection__WEBPACK_IMPORTED_MODULE_4__.Connection(null, touched); } // Have we touched the component itself? if (x >= this.x - this.width / 2 && x <= this.x + this.width / 2 && y >= this.y - this.height / 2 && y <= this.y + this.height / 2) { return this; } // Test if we have touched an output connection or bend for (var i = 0; i < this.outs.length; i++) { var conn = this.outs[i].touchConnections(x, y); if (conn !== null) { return conn; } } return null; }; /** * Try to touch an Out object for this componenet * @param x * @param y * @return Out object touched or null if none */ Component.prototype.touchOut = function (x, y) { for (var i = 0; i < this.outs.length; i++) { if (this.outs[i].touch(x, y)) { return this.outs[i]; } } return null; }; /** * Try to touch an In object for this componenet * @param x * @param y * @return In object touched or null if none */ Component.prototype.touchIn = function (x, y) { for (var i = 0; i < this.ins.length; i++) { if (this.ins[i].touch(x, y)) { return this.ins[i]; } } return null; }; /** * Collect all of this component and any bends that * are contained in the rectangle. * @param rect Rectangle to test * @param collect Collection (array) to add items to. */ Component.prototype.inRect = function (rect, collect) { if (rect.contains(this.x, this.y)) { collect.push(this); } this.outs.forEach(function (out) { out.selectRect(rect, collect); }); }; Component.prototype["delete"] = function () { // Delete all connection for (var i = 0; i < this.ins.length; i++) { this.ins[i].clear(); } for (var i = 0; i < this.outs.length; i++) { this.outs[i].clear(); } this.circuit["delete"](this); }; /** * Compute a bounding box that completely contains the component * @returns {Rect} */ Component.prototype.bounds = function () { var bounds = new _Utility_Rect__WEBPACK_IMPORTED_MODULE_7__.Rect(this.x - this.width / 2, this.y - this.height / 2, this.x + this.width / 2, this.y + this.height / 2); var _iterator = _createForOfIteratorHelper(this.ins), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var ins = _step.value; bounds.expand(ins.bounds()); } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } var _iterator2 = _createForOfIteratorHelper(this.outs), _step2; try { for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { var out = _step2.value; bounds.expand(out.bounds()); } } catch (err) { _iterator2.e(err); } finally { _iterator2.f(); } return bounds; }; /** * Draw component object. * * Default version for simple box objects * @param context Display context * @param view View object */ Component.prototype.draw = function (context, view) { this.selectStyle(context, view); this.drawBox(context); this.drawName(context, 0, 3); this.drawIO(context, view); }; /** * Draw the input/output pins for this component. * * This also draws the connections. */ Component.prototype.drawIO = function (context, view) { for (var i = 0; i < this.ins.length; i++) { this.selectStyle(context, view); this.ins[i].draw(context, view); } for (var i = 0; i < this.outs.length; i++) { this.selectStyle(context, view); this.outs[i].draw(context, view); } }; /** * Save the component basic properties to an object * * The character ' is replaced with `. This is so the * output JSON won't have any ' characters that would * cause problems in PHP and Javascript * * @returns {{id: *, x: *, y: *, name: string, type: *}} */ Component.prototype.save = function () { var type = this.constructor.type; var naming = this.naming; if (naming !== null) { naming = naming.replace(/'/g, '`'); } return { "id": this.id, "x": this.x, "y": this.y, "name": naming, "type": type }; }; Component.prototype.load = fun