UNPKG

react-qml

Version:
289 lines (210 loc) 8.95 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.diffProps = diffProps; exports.updateProps = updateProps; var _StyleSheet = _interopRequireDefault(require("../common/StyleSheet")); var _Anchor = require("../common/Anchor"); var _util = require("util"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } // QML signal handler convention var qmlSignalRegex = /^on([A-Z][a-zA-Z]+)$/; // Calculate the diff between the two objects. function diffProps(lastProps, nextProps) { var updatePayload = []; // phase 1: look for deleted props for (var propKey in lastProps) { if (lastProps[propKey] == null || !lastProps.hasOwnProperty(propKey) || nextProps.hasOwnProperty(propKey)) { continue; } updatePayload.push(propKey, undefined); } // phase 2: look for actual changes for (var _propKey in nextProps) { var nextPropValue = nextProps[_propKey]; var lastPropValue = lastProps != null ? lastProps[_propKey] : undefined; if (!nextProps.hasOwnProperty(_propKey) || nextPropValue === lastPropValue) { continue; } // event handling var matches = _propKey.match(qmlSignalRegex); var isEventProp = matches && lastPropValue !== nextPropValue; var isAnchorsProp = _propKey === 'anchors'; var isAnchorRefProp = _propKey === 'anchorRef'; var isStyleProp = _propKey === 'style'; // attached property or group props // eg: Layout, Material, layer etc. var isObjectProp = _typeof(nextPropValue) === 'object'; if (isEventProp || isAnchorsProp || isAnchorRefProp || isStyleProp || isObjectProp) { updatePayload.push(_propKey, [lastPropValue, nextPropValue]); continue; } // flat prop updatePayload.push(_propKey, nextPropValue); } return updatePayload.length === 0 ? null : updatePayload; } function listenTo(qmlElement, eventName, nextHandler, lastHandler) { eventName = eventName[0].toLowerCase() + eventName.substring(1); if (!qmlElement[eventName]) { console.warn("Event \"".concat(eventName, "\" not found in ").concat(qmlElement)); return; } if (lastHandler) { qmlElement[eventName].disconnect(lastHandler); } if (nextHandler) { qmlElement[eventName].connect(nextHandler); } } // handle connections function handleAnchors(qmlElement, lastAnchors, nextAnchors) { // last anchors for (var propName in lastAnchors) { if (lastAnchors.hasOwnProperty(propName)) { if ((0, _Anchor.isAnchorProp)(propName)) { var anchorRef = lastAnchors[propName]; if (typeof anchorRef === 'string') { _Anchor.ParentAnchor.removeSubscription(qmlElement, propName); qmlElement.anchors[propName] = undefined; continue; } if (anchorRef) { anchorRef.removeSubscription(qmlElement, propName); } // unset anchor qmlElement.anchors[propName] = undefined; } } } // next anchors for (var _propName in nextAnchors) { if (nextAnchors.hasOwnProperty(_propName)) { if ((0, _Anchor.isAnchorProp)(_propName)) { var _anchorRef = nextAnchors[_propName]; if (typeof _anchorRef === 'string') { _Anchor.ParentAnchor.addSubscription(qmlElement, _propName, _anchorRef); continue; } if (_anchorRef) { // anchor, set value when anchor ready _anchorRef.addSubscription(qmlElement, _propName); } else { // unset anchor qmlElement.anchors[_propName] = undefined; } } else { // primitive, set values right away var propValue = nextAnchors[_propName]; qmlElement.anchors[_propName] = propValue; } } } } // handle anchor ref function handleAnchorRef(qmlElement, lastRef, nextRef) { // TODO: handle last ref if (nextRef) { nextRef.setQmlElement(qmlElement); } } function handleStyle(qmlElement, lastStyle, nextStyle) { // last style var nextFlatStyle = _StyleSheet.default.flattenStyle(nextStyle); var finalStyle = nextFlatStyle; if (lastStyle) { var lastFlatStyle = _StyleSheet.default.flattenStyle(lastStyle); for (var styleName in lastFlatStyle) { if (!nextFlatStyle.hasOwnProperty(styleName)) { // not every element/prop allow setting to undefined try { finalStyle[styleName] = undefined; } catch (ex) { console.warn("Cannot unset property '".concat(styleName, "' of ").concat(qmlElement)); } } } } _StyleSheet.default.setStyle(qmlElement, finalStyle); } function handleGroupProps(qmlElement, group, lastProps, nextProps) { // phase 1: look for deleted props for (var propKey in lastProps) { if (lastProps[propKey] == null || !lastProps.hasOwnProperty(propKey) || nextProps.hasOwnProperty(propKey)) { continue; } // not every element/prop allow setting to undefined try { qmlElement[group][propKey] = undefined; } catch (ex) { console.warn("Cannot unset property '".concat(propKey, "' of ").concat(qmlElement, ".").concat(group)); } } // phase 2: look for actual changes for (var _propKey2 in nextProps) { var nextPropValue = nextProps[_propKey2]; var lastPropValue = lastProps != null ? lastProps[_propKey2] : undefined; if (!nextProps.hasOwnProperty(_propKey2) || nextPropValue === lastPropValue) { continue; } qmlElement[group][_propKey2] = nextPropValue; } } // Apply the diff. function updateProps(container, updatePayload) { var qmlElement = container.element; for (var i = 0; i < updatePayload.length; i += 2) { var propKey = updatePayload[i]; var propValue = updatePayload[i + 1]; // ignore the children if (propKey === 'children') { continue; } // event handling var matches = propKey.match(qmlSignalRegex); if (matches) { var eventName = matches[1]; var _propValue = _slicedToArray(propValue, 2), lastHandler = _propValue[0], nextHandler = _propValue[1]; listenTo(qmlElement, eventName, nextHandler, lastHandler); continue; } // anchor ref if (propKey === 'anchorRef') { var _propValue2 = _slicedToArray(propValue, 2), lastRef = _propValue2[0], nextRef = _propValue2[1]; handleAnchorRef(qmlElement, lastRef, nextRef); continue; } // anchors handling if (propKey === 'anchors') { var _propValue3 = _slicedToArray(propValue, 2), lastAnchors = _propValue3[0], nextAnchors = _propValue3[1]; handleAnchors(qmlElement, lastAnchors, nextAnchors); continue; } // style handling if (propKey === 'style') { var _propValue4 = _slicedToArray(propValue, 2), lastStyle = _propValue4[0], nextStyle = _propValue4[1]; handleStyle(qmlElement, lastStyle, nextStyle); continue; } // attached property or group props // eg: Layout, Material, layer etc. var isObjectProp = _typeof(qmlElement[propKey]) === 'object'; if (Array.isArray(propValue) && isObjectProp) { var _propValue5 = _slicedToArray(propValue, 2), lastPropValue = _propValue5[0], nextPropValue = _propValue5[1]; if (_typeof(nextPropValue) === 'object') { handleGroupProps(qmlElement, propKey, lastPropValue, nextPropValue); continue; } } if (!qmlElement.hasOwnProperty(propKey)) { console.warn("Cannot assign to non-existent property \"".concat(propKey, "\"")); continue; } if (propValue === undefined) { try { qmlElement[propKey] = propValue; } catch (ex) { console.warn("Cannot unset property \"".concat(propKey, "\" of object ").concat(qmlElement)); } } else { qmlElement[propKey] = propValue; } } }