├── src ├── .eslintrc ├── engine │ ├── .eslintrc │ ├── QMLNumber.js │ ├── QMLString.js │ ├── QMLVariant.js │ ├── QMLBoolean.js │ ├── QMLInteger.js │ ├── QMLUrl.js │ ├── QMLOperationState.js │ ├── AutoLoader.js │ ├── jsparser.js │ ├── QMLList.js │ ├── getset.js │ ├── i18n.js │ ├── keyboard.js │ └── helpers.js ├── QmlWeb.js ├── modules │ ├── QmlWeb.Dom │ │ ├── DomDiv.js │ │ ├── DomParagraph.js │ │ └── DomStyle.js │ ├── QtQuick │ │ ├── AnimatedImage.js │ │ ├── FocusScope.js │ │ ├── XAnimator.js │ │ ├── YAnimator.js │ │ ├── ScaleAnimator.js │ │ ├── OpacityAnimator.js │ │ ├── RotationAnimator.js │ │ ├── UniformAnimator.js │ │ ├── ListElement.js │ │ ├── RegExpValidator.js │ │ ├── Translate.js │ │ ├── PropertyChanges.js │ │ ├── GradientStop.js │ │ ├── ShaderEffect.js │ │ ├── IntValidator.js │ │ ├── Animator.js │ │ ├── Column.js │ │ ├── Behavior.js │ │ ├── PauseAnimation.js │ │ ├── Animation.js │ │ ├── ShaderEffectSource.js │ │ ├── Positioner.js │ │ ├── Scale.js │ │ ├── State.js │ │ ├── Gradient.js │ │ ├── Rotation.js │ │ ├── Row.js │ │ ├── ListView.js │ │ ├── Canvas.js │ │ └── DoubleValidator.js │ ├── QtQml.Models │ │ ├── ListElement.js │ │ └── ListModel.js │ ├── QtQuick.Particles │ │ ├── Direction.js │ │ ├── ParticlePainter.js │ │ ├── CustomParticle.js │ │ ├── AngleDirection.js │ │ ├── ParticleSystem.js │ │ └── Emitter.js │ ├── QtQuick.Controls.2 │ │ ├── TabButton.js │ │ ├── Label.js │ │ ├── TabBar.js │ │ ├── Page.js │ │ ├── ApplicationWindow.js │ │ ├── SwipeView.js │ │ ├── Control.js │ │ ├── AbstractButton.js │ │ └── Container.js │ ├── QtWebEngine │ │ └── WebEngineView.js │ ├── QtQml │ │ ├── QValidator.js │ │ ├── Binding.js │ │ └── Connections.js │ ├── QtQuick.Layouts │ │ ├── DirectionalLayout.js │ │ ├── Positioner.js │ │ ├── StackLayout.js │ │ └── Layout.js │ ├── QtQuick.Controls │ │ ├── TextArea.js │ │ ├── ApplicationWindow.js │ │ └── Button.js │ ├── QtNfc │ │ └── NearField.js │ ├── QtTest │ │ └── SignalSpy.js │ ├── QtMultimedia │ │ ├── VideoOutput.js │ │ ├── Camera.js │ │ └── MediaPlayer.js │ ├── QtQuick.Window │ │ └── Window.js │ ├── QtBluetooth │ │ └── BluetoothDiscoveryModel.js │ ├── QtWebKit │ │ └── WebView.js │ ├── QtMobility │ │ └── GeoLocation.js │ ├── Qt.labs.settings │ │ └── Settings.js │ ├── QtGraphicalEffects │ │ └── FastBlur.js │ └── QtWebView │ │ └── WebView.js └── qtbase │ ├── JSItemModel.js │ ├── QPointF.js │ ├── QSizeF.js │ ├── QQuaternion.js │ └── QRectF.js ├── tests ├── QMLEngine │ ├── qml │ │ ├── ImportReuse │ │ │ ├── foo │ │ │ │ └── bar │ │ │ │ │ ├── qmldir │ │ │ │ │ └── ItemS.qml │ │ │ ├── qmldir │ │ │ ├── ItemA.qml │ │ │ └── main.qml │ │ ├── importTestIncluded.js │ │ ├── singleton │ │ │ ├── qmldir │ │ │ └── Style.qml │ │ ├── importTestInclude.js │ │ ├── ScopeComponentIdSomeComponent.qml │ │ ├── ScopeUpflowWithFoo.qml │ │ ├── ImportFromDir.qml │ │ ├── ImportLocalToFile │ │ │ ├── DirectoryFailSomeComponent.qml │ │ │ ├── ModuleSucceedSomeComponent.qml │ │ │ ├── ModuleFailSomeComponent.qml │ │ │ ├── DirectoryFail.qml │ │ │ ├── ModuleFail2.qml │ │ │ ├── ModuleFail1.qml │ │ │ └── ModuleSucceed.qml │ │ ├── ItemWithValue.qml │ │ ├── somelib │ │ │ ├── qmldir │ │ │ ├── SimpleButton.qml │ │ │ └── RectangleColor.qml │ │ ├── ImportFrom │ │ │ ├── ImportMe.qml │ │ │ ├── ParentDir.qml │ │ │ ├── LocalComponentProperty.qml │ │ │ └── SiblingDir.qml │ │ ├── ImportNoQmldir.qml │ │ ├── ScopeUpflowWithRealFoo.qml │ │ ├── ItemWithPropertyNamedSignal.qml │ │ ├── ImportQmldir.qml │ │ ├── ParseFunctionVar.qml │ │ ├── ImportQualifiedModule.qml │ │ ├── ImportQualifiedNoQmldir.qml │ │ ├── ParseError.qml │ │ ├── PropertiesNamedSignalValues.qml │ │ ├── importTestSimple.js │ │ ├── JavascriptRegexp.qml │ │ ├── PropertiesDefault.qml │ │ ├── PropertiesNamedSignal.qml │ │ ├── ScopeIdOverProperty.qml │ │ ├── ParseSignal.qml │ │ ├── ScopeIdOverPropertyImpl.qml │ │ ├── PropertiesDefaultLabel.qml │ │ ├── BindingsNoSrc.qml │ │ ├── ImportQmldirSingleton.qml │ │ ├── ImportJavascriptInclude.qml │ │ ├── ScopeOverrideBase.qml │ │ ├── PropertiesAlias.qml │ │ ├── PropertiesUndefined.qml │ │ ├── ScopeRoot.qml │ │ ├── ScopeComponentId.qml │ │ ├── ScopeUpflow.qml │ │ ├── BindingsThis.qml │ │ ├── ScopeSibling.qml │ │ ├── ScopeLeaf.qml │ │ ├── ScopeOverride.qml │ │ ├── PropertiesAliasToId.qml │ │ ├── PropertiesChangedExpressionSignal.qml │ │ ├── BasicCreateObject.qml │ │ ├── PropertiesAliasToIdSameName.qml │ │ ├── BasicCreateObjectSomeComponent.qml │ │ ├── ScopeMid.qml │ │ ├── PropertiesStringConversion.qml │ │ ├── BindingsArray.qml │ │ ├── BindingsUpdate.qml │ │ ├── BasicSignalParameters.qml │ │ ├── BasicCompletedOfDynamicObjects.qml │ │ ├── ImportJavascript.qml │ │ ├── StateSimple.qml │ │ ├── BindingsRecursiveInit3.qml │ │ ├── BindingsRecursiveInit4.qml │ │ ├── PropertiesBasic.qml │ │ ├── BindingsRecursiveInit.qml │ │ ├── BasicCreateQmlObject.qml │ │ ├── BasicSignalDisconnectOnDelete.qml │ │ ├── ScopeSafeFromLocals.qml │ │ ├── PropertiesAliasChanged.qml │ │ ├── BasicResolvedUrl.qml │ │ ├── PropertiesAliasChangedBack.qml │ │ ├── PropertiesChangedSignal.qml │ │ ├── StateWhen.qml │ │ ├── BindingsRecursiveInit2.qml │ │ ├── StateBinding.qml │ │ ├── ImportJavascriptScope.qml │ │ ├── PropertiesUrlDir │ │ │ ├── PropertiesUrlImport.qml │ │ │ └── PropertiesUrlImportWithExceptions.qml │ │ ├── ImportLocalComponentAsPropertyInAnotherDir.qml │ │ ├── JavascriptBasicSyntax.qml │ │ ├── PropertiesUrl.qml │ │ ├── ScopeRepeater.qml │ │ ├── BasicSignalDisconnect.qml │ │ └── PropertiesUrlExceptionSafe.qml │ ├── basepath │ │ ├── B.qml │ │ ├── test.qml │ │ ├── import │ │ │ └── A.qml │ │ └── test.js │ ├── javascript.js │ └── parse.js ├── QtQuick │ ├── qml │ │ ├── ItemEmpty.qml │ │ ├── TextWrapMode.qml │ │ ├── RectangleColor.qml │ │ ├── ItemSize.qml │ │ ├── RectangleTransparent.qml │ │ ├── RectangleWhite.qml │ │ ├── ShortcutSequence.qml │ │ ├── LoaderSourceImmediate.qml │ │ ├── LoaderDirectory │ │ │ └── LoaderDirectoryComponent.qml │ │ ├── PropertyAnimationFailsToLoad.qml │ │ ├── PropertyAnimationLoads.qml │ │ ├── TimerSingleshot.qml │ │ ├── LoaderEmptySource.qml │ │ ├── LoaderSourceComponentImmediate.qml │ │ ├── RepeaterNumberModel.qml │ │ ├── TextImplicitSize.qml │ │ ├── TimerParentProperty.qml │ │ ├── LoaderSourceComponentFromComponent.qml │ │ ├── LoaderComponent.qml │ │ ├── LoaderSourceDelayed.qml │ │ ├── RepeaterListModel.qml │ │ ├── MouseAreaGeneric.qml │ │ ├── LoaderSourceComponentDelayed.qml │ │ ├── FontWeights.qml │ │ ├── RepeaterPropertyRoleNameConflict.qml │ │ ├── BehaviorBasic.qml │ │ ├── TimerRunning.qml │ │ ├── ParallelAnimationRunning.qml │ │ ├── SequentialAnimationRunning.qml │ │ ├── ListModel.qml │ │ ├── SequentialAnimationPaused.qml │ │ ├── RepeaterCompletedDestruction.qml │ │ └── RepeaterModelRole.qml │ ├── Behavior.js │ ├── Text.js │ ├── Font.js │ ├── PropertyAnimation.js │ ├── Item.js │ ├── Rectangle.js │ ├── Shortcut.js │ ├── Loader.js │ └── Timer.js ├── Render │ ├── Async │ │ ├── bg.png │ │ ├── Image.png │ │ ├── ImageFill.png │ │ ├── BorderImage.png │ │ ├── ImageMirror.png │ │ ├── ColorAnimation.png │ │ ├── NumberAnimation.png │ │ ├── NumberAnimationAutorun.png │ │ ├── Image.qml │ │ ├── ColorAnimation.qml │ │ ├── NumberAnimationAutorun.qml │ │ ├── NumberAnimation.qml │ │ ├── BorderImage.qml │ │ ├── ImageFill.qml │ │ └── ImageMirror.qml │ ├── Simple │ │ ├── res │ │ │ ├── PropertyGridComponent.qml │ │ │ └── LoaderScopeChild.qml │ │ ├── ElementLoading.qml │ │ ├── FlowTop.png │ │ ├── Translate.png │ │ ├── AnchorChains.png │ │ ├── AnchorsFill.png │ │ ├── AnchorsSides.png │ │ ├── FlowRepeater.png │ │ ├── LoaderScope.png │ │ ├── PropertyGrid.png │ │ ├── TextEditEmpty.png │ │ ├── ElementLoading.png │ │ ├── FlowReflowWidth.png │ │ ├── RectangleBorder.png │ │ ├── RectangleColor.png │ │ ├── RectanglesGrid.png │ │ ├── RepeaterNumber.png │ │ ├── ScaleRectangle.png │ │ ├── FlowReflowHeight.png │ │ ├── PropertyRectangle.png │ │ ├── RepeaterListModel.png │ │ ├── ZeroOpacityLayout.png │ │ ├── AnchorsCenterAndFill.png │ │ ├── RectangleOnCompleted.png │ │ ├── ScaleRectangleOrigin.png │ │ ├── AnchorsCenterAndFill2.png │ │ ├── FlowImplicitWidthHeight.png │ │ ├── RectangleBorderChildren.png │ │ ├── RectangleColor.qml │ │ ├── RectangleImplicitSize.png │ │ ├── AnchorUpdateHVGeometryRecursion.png │ │ ├── RectangleOnCompleted.qml │ │ ├── TextEditEmpty.qml │ │ ├── LoaderScope.qml │ │ ├── FlowRepeater.qml │ │ ├── FlowTop.qml │ │ ├── AnchorsFill.qml │ │ ├── ScaleRectangle.qml │ │ ├── RepeaterNumber.qml │ │ ├── PropertyRectangle.qml │ │ ├── FlowReflowWidth.qml │ │ ├── Translate.qml │ │ ├── FlowReflowHeight.qml │ │ ├── PropertyGrid.qml │ │ ├── RectanglesGrid.qml │ │ ├── AnchorsCenterAndFill2.qml │ │ ├── ScaleRectangleOrigin.qml │ │ ├── AnchorsCenterAndFill.qml │ │ ├── ZeroOpacityLayout.qml │ │ ├── RectangleBorderChildren.qml │ │ ├── RepeaterListModel.qml │ │ ├── AnchorsSides.qml │ │ ├── AnchorChains.qml │ │ ├── RectangleBorder.qml │ │ └── RectangleImplicitSize.qml │ └── Fuzzy │ │ ├── RectanglesAlpha.png │ │ ├── RectanglesOpacity.png │ │ ├── RectanglesOpacity.qml │ │ └── RectanglesAlpha.qml ├── QtQuick.Controls │ └── ComboBox │ │ ├── test.qml │ │ └── test_populated.qml ├── QtTest │ ├── qml │ │ ├── TestCaseEmpty.qml │ │ ├── TestCaseSimple.qml │ │ └── TestCaseDatadriven.qml │ └── TestCase.js ├── Qt.labs.settings │ ├── qml │ │ ├── SettingsPlain.qml │ │ └── SettingsAlias.qml │ └── Settings.js ├── QmlWeb.Dom │ ├── qml │ │ └── DomElementStyle.qml │ └── DomElementStyle.js ├── QtQuick.Layouts │ ├── qml │ │ ├── StackLayout.qml │ │ ├── GridLayoutTopToBottom.qml │ │ ├── GridLayoutLeftToRight.qml │ │ ├── GridLayoutFill.qml │ │ ├── ColumnLayoutImplicitSize.qml │ │ └── RowLayoutImplicitSize.qml │ └── StackLayout.js ├── Auto │ ├── QtTest │ │ └── tst_Math.qml │ ├── Globals │ │ └── tst_i18n.qml │ ├── QtWebKit │ │ └── tst_enums.qml │ ├── QtQuick │ │ ├── tst_point.qml │ │ └── tst_size.qml │ └── runner.js ├── QtQml │ ├── qml │ │ ├── BindingBroken.qml │ │ ├── BindingOneWay.qml │ │ ├── BindingUndefined.qml │ │ ├── ConnectionsConnections.qml │ │ └── BindingTwoWay.qml │ ├── Connections.js │ └── Binding.js ├── phantom.callback.js ├── .eslintrc ├── qmlweb.js └── failingTests.js ├── misc └── logo.png ├── .nycrc ├── .babelrc ├── codecov.yml ├── .gitignore ├── .editorconfig ├── examples ├── fullpage.html ├── qml │ └── main.qml ├── embed.html └── customelement.html ├── .travis.yml ├── bower.json ├── docs ├── JSItemModel.md └── Signal.md ├── AUTHORS ├── LICENSE └── karma.conf.js /src/.eslintrc: -------------------------------------------------------------------------------- 1 | env: 2 | node: false 3 | -------------------------------------------------------------------------------- /src/engine/.eslintrc: -------------------------------------------------------------------------------- 1 | rules: 2 | no-new-func: 0 3 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ImportReuse/foo/bar/qmldir: -------------------------------------------------------------------------------- 1 | ItemS ItemS.qml 2 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/importTestIncluded.js: -------------------------------------------------------------------------------- 1 | var includedTest = 42; 2 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/singleton/qmldir: -------------------------------------------------------------------------------- 1 | singleton Style 1.0 Style.qml -------------------------------------------------------------------------------- /src/QmlWeb.js: -------------------------------------------------------------------------------- 1 | const QmlWeb = {}; 2 | 3 | global.QmlWeb = QmlWeb; 4 | -------------------------------------------------------------------------------- /misc/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/misc/logo.png -------------------------------------------------------------------------------- /tests/QtQuick/qml/ItemEmpty.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | } 5 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ImportReuse/qmldir: -------------------------------------------------------------------------------- 1 | MainUI main.qml 2 | ItemA ItemA.qml 3 | 4 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/importTestInclude.js: -------------------------------------------------------------------------------- 1 | Qt.include("importTestIncluded.js"); 2 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ImportReuse/foo/bar/ItemS.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.3 2 | 3 | Item { 4 | } 5 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ScopeComponentIdSomeComponent.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | } 5 | -------------------------------------------------------------------------------- /tests/QtQuick/qml/TextWrapMode.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Text { 4 | text: "foo" 5 | } 6 | -------------------------------------------------------------------------------- /tests/QMLEngine/basepath/B.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.Controls 1.2 3 | 4 | Item { 5 | } -------------------------------------------------------------------------------- /tests/Render/Async/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Async/bg.png -------------------------------------------------------------------------------- /tests/Render/Simple/res/PropertyGridComponent.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Rectangle { 4 | } 5 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ScopeUpflowWithFoo.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.5 2 | 3 | ScopeUpflowWithRealFoo { 4 | } 5 | -------------------------------------------------------------------------------- /tests/QtQuick/qml/RectangleColor.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Rectangle { 4 | color: 'red' 5 | } 6 | -------------------------------------------------------------------------------- /tests/Render/Async/Image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Async/Image.png -------------------------------------------------------------------------------- /.nycrc: -------------------------------------------------------------------------------- 1 | { 2 | "coverageVariable": "__coverage__", 3 | "require": [ 4 | "babel-register" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ImportFromDir.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | property int value: 5 5 | } 6 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ImportLocalToFile/DirectoryFailSomeComponent.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | ImportMe {} 4 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ImportLocalToFile/ModuleSucceedSomeComponent.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | } 5 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ItemWithValue.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | property int value: 1 5 | } 6 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/somelib/qmldir: -------------------------------------------------------------------------------- 1 | ShinyRectangle 1.0 RectangleColor.qml 2 | ShinyButton 1.0 SimpleButton.qml 3 | -------------------------------------------------------------------------------- /tests/QtQuick/qml/ItemSize.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | width: 200 5 | height: 100 6 | } 7 | -------------------------------------------------------------------------------- /tests/Render/Async/ImageFill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Async/ImageFill.png -------------------------------------------------------------------------------- /tests/Render/Simple/ElementLoading.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | RectangleColor { 4 | width: 50 5 | } 6 | -------------------------------------------------------------------------------- /tests/Render/Simple/FlowTop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Simple/FlowTop.png -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ImportFrom/ImportMe.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | property int value: 67 5 | } 6 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ImportFrom/ParentDir.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import ".." 3 | ImportFromDir { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ImportNoQmldir.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import "ImportFrom" 3 | 4 | ImportMe { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ScopeUpflowWithRealFoo.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.5 2 | 3 | Item { 4 | property int foo: 15 5 | } 6 | -------------------------------------------------------------------------------- /tests/QtQuick.Controls/ComboBox/test.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.Controls 1.2 3 | 4 | ComboBox { 5 | } -------------------------------------------------------------------------------- /tests/Render/Async/BorderImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Async/BorderImage.png -------------------------------------------------------------------------------- /tests/Render/Async/ImageMirror.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Async/ImageMirror.png -------------------------------------------------------------------------------- /tests/Render/Simple/Translate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Simple/Translate.png -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015"], 3 | "plugins": ["transform-class-properties"], 4 | "compact" : false 5 | } 6 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ItemWithPropertyNamedSignal.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.5 2 | Item { 3 | property int signal: 10 4 | } 5 | -------------------------------------------------------------------------------- /tests/QtQuick/qml/RectangleTransparent.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Rectangle { 4 | color: 'transparent' 5 | } 6 | -------------------------------------------------------------------------------- /tests/QtQuick/qml/RectangleWhite.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Rectangle { 4 | width: 200 5 | height: 100 6 | } 7 | -------------------------------------------------------------------------------- /tests/QtQuick/qml/ShortcutSequence.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Shortcut { 4 | sequences: ["Ctrl+Alt+P"] 5 | } 6 | -------------------------------------------------------------------------------- /tests/Render/Async/ColorAnimation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Async/ColorAnimation.png -------------------------------------------------------------------------------- /tests/Render/Simple/AnchorChains.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Simple/AnchorChains.png -------------------------------------------------------------------------------- /tests/Render/Simple/AnchorsFill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Simple/AnchorsFill.png -------------------------------------------------------------------------------- /tests/Render/Simple/AnchorsSides.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Simple/AnchorsSides.png -------------------------------------------------------------------------------- /tests/Render/Simple/FlowRepeater.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Simple/FlowRepeater.png -------------------------------------------------------------------------------- /tests/Render/Simple/LoaderScope.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Simple/LoaderScope.png -------------------------------------------------------------------------------- /tests/Render/Simple/PropertyGrid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Simple/PropertyGrid.png -------------------------------------------------------------------------------- /tests/Render/Simple/TextEditEmpty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Simple/TextEditEmpty.png -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ImportQmldir.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import "somelib" 3 | 4 | ShinyRectangle { 5 | width: 50 6 | } 7 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ParseFunctionVar.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | property var aFunction: function(){} 5 | } 6 | -------------------------------------------------------------------------------- /tests/QtQuick/qml/LoaderSourceImmediate.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Loader { 4 | source: "LoaderComponent.qml" 5 | } 6 | -------------------------------------------------------------------------------- /tests/QtTest/qml/TestCaseEmpty.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtTest 1.0 3 | 4 | TestCase { 5 | name: "Empty" 6 | } 7 | -------------------------------------------------------------------------------- /tests/Render/Async/NumberAnimation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Async/NumberAnimation.png -------------------------------------------------------------------------------- /tests/Render/Fuzzy/RectanglesAlpha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Fuzzy/RectanglesAlpha.png -------------------------------------------------------------------------------- /tests/Render/Simple/ElementLoading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Simple/ElementLoading.png -------------------------------------------------------------------------------- /tests/Render/Simple/FlowReflowWidth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Simple/FlowReflowWidth.png -------------------------------------------------------------------------------- /tests/Render/Simple/RectangleBorder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Simple/RectangleBorder.png -------------------------------------------------------------------------------- /tests/Render/Simple/RectangleColor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Simple/RectangleColor.png -------------------------------------------------------------------------------- /tests/Render/Simple/RectanglesGrid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Simple/RectanglesGrid.png -------------------------------------------------------------------------------- /tests/Render/Simple/RepeaterNumber.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Simple/RepeaterNumber.png -------------------------------------------------------------------------------- /tests/Render/Simple/ScaleRectangle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Simple/ScaleRectangle.png -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ImportReuse/ItemA.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.2 2 | import "foo/bar" 3 | 4 | Item { 5 | ItemS { 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tests/Render/Fuzzy/RectanglesOpacity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Fuzzy/RectanglesOpacity.png -------------------------------------------------------------------------------- /tests/Render/Simple/FlowReflowHeight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Simple/FlowReflowHeight.png -------------------------------------------------------------------------------- /tests/Render/Simple/PropertyRectangle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Simple/PropertyRectangle.png -------------------------------------------------------------------------------- /tests/Render/Simple/RepeaterListModel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Simple/RepeaterListModel.png -------------------------------------------------------------------------------- /tests/Render/Simple/ZeroOpacityLayout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Simple/ZeroOpacityLayout.png -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ImportFrom/LocalComponentProperty.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Repeater { 4 | delegate: ImportMe {} 5 | } 6 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ImportLocalToFile/ModuleFailSomeComponent.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtWebSockets 1.0 3 | 4 | Item { 5 | } 6 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ImportQualifiedModule.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 as Quick 2 | 3 | Quick.Item { 4 | property int value: 67 5 | } 6 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ImportQualifiedNoQmldir.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import "ImportFrom" as ImFr 3 | 4 | ImFr.ImportMe { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ParseError.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.5 2 | Item { 3 | property string correct: "" 4 | properly int error: 11 5 | } 6 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/PropertiesNamedSignalValues.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.5 2 | 3 | ItemWithPropertyNamedSignal { 4 | signal: 20 5 | } 6 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/importTestSimple.js: -------------------------------------------------------------------------------- 1 | function importedTest(x) { 2 | return x + x; 3 | } 4 | 5 | var importedColor = "magenta"; 6 | -------------------------------------------------------------------------------- /tests/QtQuick/qml/LoaderDirectory/LoaderDirectoryComponent.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | property int value: 43 5 | } 6 | -------------------------------------------------------------------------------- /tests/Render/Simple/AnchorsCenterAndFill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Simple/AnchorsCenterAndFill.png -------------------------------------------------------------------------------- /tests/Render/Simple/RectangleOnCompleted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Simple/RectangleOnCompleted.png -------------------------------------------------------------------------------- /tests/Render/Simple/ScaleRectangleOrigin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Simple/ScaleRectangleOrigin.png -------------------------------------------------------------------------------- /src/modules/QmlWeb.Dom/DomDiv.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QmlWeb_Dom_DomDiv extends QmlWeb_Dom_DomElement { 3 | } 4 | -------------------------------------------------------------------------------- /src/modules/QtQuick/AnimatedImage.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_AnimatedImage extends QtQuick_Image { 3 | } 4 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/somelib/SimpleButton.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.Controls 1.2 3 | 4 | Button { 5 | text: "I'm simple" 6 | } -------------------------------------------------------------------------------- /tests/Render/Async/NumberAnimationAutorun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Async/NumberAnimationAutorun.png -------------------------------------------------------------------------------- /tests/Render/Simple/AnchorsCenterAndFill2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Simple/AnchorsCenterAndFill2.png -------------------------------------------------------------------------------- /tests/Render/Simple/FlowImplicitWidthHeight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Simple/FlowImplicitWidthHeight.png -------------------------------------------------------------------------------- /tests/Render/Simple/RectangleBorderChildren.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Simple/RectangleBorderChildren.png -------------------------------------------------------------------------------- /tests/Render/Simple/RectangleColor.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Rectangle { 4 | color: 'red' 5 | width: 100 6 | height: 100 7 | } 8 | -------------------------------------------------------------------------------- /tests/Render/Simple/RectangleImplicitSize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Simple/RectangleImplicitSize.png -------------------------------------------------------------------------------- /src/engine/QMLNumber.js: -------------------------------------------------------------------------------- 1 | function QMLNumber(val) { 2 | return +val; 3 | } 4 | QMLNumber.plainType = true; 5 | QmlWeb.qmlNumber = QMLNumber; 6 | -------------------------------------------------------------------------------- /src/engine/QMLString.js: -------------------------------------------------------------------------------- 1 | function QMLString(val) { 2 | return `${val}`; 3 | } 4 | QMLString.plainType = true; 5 | QmlWeb.qmlString = QMLString; 6 | -------------------------------------------------------------------------------- /src/engine/QMLVariant.js: -------------------------------------------------------------------------------- 1 | function QMLVariant(val) { 2 | return val; 3 | } 4 | QMLVariant.plainType = true; 5 | QmlWeb.qmlVariant = QMLVariant; 6 | -------------------------------------------------------------------------------- /src/modules/QtQuick/FocusScope.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_FocusScope extends QtQuick_Item { 3 | // TODO 4 | } 5 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ImportFrom/SiblingDir.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import "../somelib" 3 | ShinyButton { 4 | property int value: 55 5 | } 6 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ImportLocalToFile/DirectoryFail.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import "../ImportFrom" 3 | 4 | DirectoryFailSomeComponent {} 5 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/JavascriptRegexp.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | property variant reg: /^[0-9]+\/(first|second){1,2}$/ 5 | } 6 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/PropertiesDefault.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.2 2 | 3 | PropertiesDefaultLabel { 4 | Text { 5 | text: "world!" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/PropertiesNamedSignal.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.5 2 | Item { 3 | ItemWithPropertyNamedSignal { 4 | signal: 20 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ScopeIdOverProperty.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | ScopeIdOverPropertyImpl { 4 | Item { 5 | id: foo 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/singleton/Style.qml: -------------------------------------------------------------------------------- 1 | pragma Singleton 2 | import QtQuick 2.0 3 | 4 | QtObject { 5 | property color customColor: "green" 6 | } -------------------------------------------------------------------------------- /src/engine/QMLBoolean.js: -------------------------------------------------------------------------------- 1 | function QMLBoolean(val) { 2 | return !!val; 3 | } 4 | QMLBoolean.plainType = true; 5 | QmlWeb.qmlBoolean = QMLBoolean; 6 | -------------------------------------------------------------------------------- /src/engine/QMLInteger.js: -------------------------------------------------------------------------------- 1 | function QMLInteger(val) { 2 | return val | 0; 3 | } 4 | QMLInteger.plainType = true; 5 | QmlWeb.qmlInteger = QMLInteger; 6 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ParseSignal.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | signal simpleSignal; 5 | signal signalWithParams(string someParam) 6 | } 7 | -------------------------------------------------------------------------------- /src/engine/QMLUrl.js: -------------------------------------------------------------------------------- 1 | function QMLUrl(val) { 2 | return QmlWeb.engine.$resolvePath(`${val}`); 3 | } 4 | QMLUrl.plainType = true; 5 | QmlWeb.qmlUrl = QMLUrl; 6 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ImportLocalToFile/ModuleFail2.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | ModuleFailSomeComponent { 5 | } 6 | WebSocket {} 7 | } 8 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ScopeIdOverPropertyImpl.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | property int foo: 42 5 | property string boo: foo.toString() 6 | } 7 | -------------------------------------------------------------------------------- /tests/Render/Simple/AnchorUpdateHVGeometryRecursion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qmlweb/qmlweb/HEAD/tests/Render/Simple/AnchorUpdateHVGeometryRecursion.png -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ImportLocalToFile/ModuleFail1.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | ModuleFailSomeComponent { 5 | WebSocket {} 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/PropertiesDefaultLabel.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.2 2 | 3 | Text { 4 | default property var someText 5 | text: "Hello, " + someText.text 6 | } 7 | -------------------------------------------------------------------------------- /tests/QtQuick/qml/PropertyAnimationFailsToLoad.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.6 2 | 3 | Item { 4 | transform: Rotation { 5 | NumberAnimation { 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/engine/QMLOperationState.js: -------------------------------------------------------------------------------- 1 | const QMLOperationState = { 2 | Idle: 1, 3 | Init: 2, 4 | Running: 3 5 | }; 6 | 7 | QmlWeb.QMLOperationState = QMLOperationState; 8 | -------------------------------------------------------------------------------- /tests/QtQuick/qml/PropertyAnimationLoads.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.6 2 | 3 | Item { 4 | transform: Rotation { 5 | NumberAnimation on angle { 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/BindingsNoSrc.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | width: 10 5 | height: (typeof bindSrc === 'undefined') ? width + 2 : bindSrc.length 6 | } 7 | -------------------------------------------------------------------------------- /tests/QtQuick/qml/TimerSingleshot.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.5 2 | Timer { 3 | interval: 50 4 | property int counter: 0 5 | onTriggered: { 6 | yield("done") 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/modules/QtQml.Models/ListElement.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQml_Models_ListElement extends QtQuick_ListElement { 3 | static versions = /^2\./; 4 | } 5 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ImportQmldirSingleton.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import "singleton" 3 | 4 | Rectangle { 5 | height: 10 6 | width: 20 7 | color: Style.customColor 8 | } 9 | -------------------------------------------------------------------------------- /tests/QtQuick.Controls/ComboBox/test_populated.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.Controls 1.2 3 | 4 | ComboBox { 5 | currentIndex: 1 6 | model: ["a","b","c"] 7 | } 8 | -------------------------------------------------------------------------------- /tests/QtQuick/qml/LoaderEmptySource.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Loader { 4 | source: "LoaderComponent.qml" 5 | Component.onCompleted: { 6 | source = "" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/modules/QtQuick/XAnimator.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_XAnimator extends QtQuick_Animator { 3 | static versions = /^2\./; 4 | 5 | // TODO 6 | } 7 | -------------------------------------------------------------------------------- /src/modules/QtQuick/YAnimator.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_YAnimator extends QtQuick_Animator { 3 | static versions = /^2\./; 4 | 5 | // TODO 6 | } 7 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ImportJavascriptInclude.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import "importTestInclude.js" as Imported 3 | 4 | Item { 5 | property int value: Imported.includedTest 6 | } 7 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ScopeOverrideBase.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | property var foo: 42 5 | 6 | function getFooVal() { 7 | return foo; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/modules/QtQuick/ScaleAnimator.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_ScaleAnimator extends QtQuick_Animator { 3 | static versions = /^2\./; 4 | 5 | // TODO 6 | } 7 | -------------------------------------------------------------------------------- /tests/QMLEngine/basepath/test.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.Controls 1.2 3 | import "import" 4 | 5 | Item { 6 | A { 7 | a:1 8 | } 9 | B { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/PropertiesAlias.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | property alias childX: child.x 5 | 6 | Item { 7 | id: child 8 | x: 125 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/PropertiesUndefined.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | property var theUndefined 5 | 6 | Text { 7 | text: typeof(theUndefined) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ScopeRoot.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | id: rootItem 5 | 6 | property int value: 1000 7 | ScopeMid { 8 | id: parentItem 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/Render/Simple/RectangleOnCompleted.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Rectangle { 4 | color: 'red' 5 | width: 10 6 | height: 10 7 | Component.onCompleted: color = '#0f0' 8 | } 9 | -------------------------------------------------------------------------------- /src/modules/QtQuick/OpacityAnimator.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_OpacityAnimator extends QtQuick_Animator { 3 | static versions = /^2\./; 4 | 5 | // TODO 6 | } 7 | -------------------------------------------------------------------------------- /src/modules/QtQuick.Particles/Direction.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_Particles_Direction extends QtQml_QtObject { 3 | static versions = /^2\./; 4 | 5 | // TODO 6 | } 7 | -------------------------------------------------------------------------------- /src/modules/QtQuick/RotationAnimator.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_RotationAnimator extends QtQuick_Animator { 3 | static versions = /^2\./; 4 | 5 | // TODO 6 | } 7 | -------------------------------------------------------------------------------- /tests/Qt.labs.settings/qml/SettingsPlain.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import Qt.labs.settings 1.0 3 | 4 | Settings { 5 | category: "QmlWebTestPlain" 6 | property int a: 10 7 | property string b 8 | } 9 | -------------------------------------------------------------------------------- /tests/QtQuick/qml/LoaderSourceComponentImmediate.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Loader { 4 | Component.onCompleted: { 5 | sourceComponent = Qt.createComponent("LoaderComponent.qml"); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ScopeComponentId.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | ScopeComponentIdSomeComponent { 4 | id: some_component 5 | 6 | property int foo: 42 7 | property int bar: some_component.foo 8 | } 9 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ScopeUpflow.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.5 2 | 3 | ScopeUpflowWithFoo { 4 | Item { 5 | id: child 6 | property int thisFoo: typeof foo == "undefined" ? "undefined" : foo 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/QtQuick/qml/RepeaterNumberModel.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | property alias repeater: _repeater 5 | Repeater { 6 | id: _repeater 7 | Item { 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/modules/QtQml.Models/ListModel.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQml_Models_ListModel extends QtQuick_ListModel { 3 | static versions = /^2\./; 4 | static defaultProperty = "$items"; 5 | } 6 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | round: down 3 | range: 50...100 4 | 5 | status: 6 | project: 7 | default: 8 | threshold: 1 9 | changes: off 10 | patch: off 11 | 12 | comment: off 13 | -------------------------------------------------------------------------------- /tests/Render/Simple/TextEditEmpty.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | width: 24 5 | height: 24 6 | 7 | TextEdit { 8 | x: 2 9 | y: 2 10 | width: 20 11 | height: 20 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/modules/QtQuick.Controls.2/TabButton.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_Controls_2_TabButton extends QtQuick_Controls_2_AbstractButton { 3 | static versions = /^2\./; 4 | 5 | // TODO 6 | } 7 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/BindingsThis.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | property int intA: 10 5 | property int intB: this.intA * 2 6 | function foo() { 7 | return this.intB + this.intA; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | lib/ 3 | coverage/ 4 | tmp/ 5 | build/ 6 | .idea/ 7 | *~ 8 | *.bak 9 | *.log 10 | .*.swp 11 | .*.swo 12 | *.qmlc 13 | *.kdev4 14 | *kate-swp 15 | .arcconfig 16 | .eslintcache 17 | .project 18 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ImportLocalToFile/ModuleSucceed.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtWebSockets 1.0 3 | 4 | Item { 5 | ModuleSucceedSomeComponent { 6 | WebSocket {} 7 | } 8 | WebSocket {} 9 | } 10 | -------------------------------------------------------------------------------- /tests/QtQuick/qml/TextImplicitSize.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | property alias text_item: _text_item 5 | Rectangle { 6 | Text { 7 | id: _text_item 8 | text: "_ _ _" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | charset = utf-8 6 | trim_trailing_whitespace = true 7 | indent_style = space 8 | indent_size = 2 9 | 10 | [*.{md,markdown}] 11 | trim_trailing_whitespace = false 12 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ScopeSibling.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.5 2 | 3 | Item { 4 | ItemWithValue { 5 | id: childA 6 | value: 2 7 | } 8 | 9 | ItemWithValue { 10 | id: childB 11 | value: childA.value * 2 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ImportReuse/main.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import "foo/bar" 3 | 4 | Rectangle { 5 | width: 400 6 | height: 400 7 | color: "#000" 8 | 9 | ItemS { 10 | } 11 | 12 | ItemA { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/QtQuick/qml/TimerParentProperty.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | property int value: 42 5 | 6 | property alias timer: _timer 7 | Timer { 8 | id: _timer 9 | property int value: parent.value 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/QmlWeb.Dom/qml/DomElementStyle.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QmlWeb.Dom 1.0 3 | 4 | DomElement { 5 | property int bindSize: 21 6 | style.textAlign: "center" 7 | style.fontSize: bindSize + "px" 8 | text: "Hello HTML" 9 | } 10 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ScopeLeaf.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | property int value: 1 5 | property int rootValue: rootItem.value 6 | property int parentValue: parentItem.value 7 | property int totalValue: (rootValue + parentValue) * value 8 | } 9 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ScopeOverride.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | ScopeOverrideBase { 4 | id: foo 5 | width: 200 6 | 7 | function getFooWidth() { 8 | return foo.width; 9 | } 10 | 11 | Text { 12 | text: getFooWidth() 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/Render/Simple/LoaderScope.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Rectangle { 4 | id: root 5 | width: 30 6 | height: 30 7 | color: 'red' 8 | 9 | Loader { 10 | anchors.fill: parent 11 | source: 'res/LoaderScopeChild.qml' 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/modules/QtQuick/UniformAnimator.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_UniformAnimator extends QtQuick_Animator { 3 | static versions = /^2\./; 4 | static properties = { 5 | uniform: "string" 6 | }; 7 | 8 | // TODO 9 | } 10 | -------------------------------------------------------------------------------- /examples/fullpage.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | QML Fullpage Auto-load Example 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/PropertiesAliasToId.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.Controls 1.1 3 | 4 | Item { 5 | property alias childA: child 6 | 7 | Item { 8 | id: child 9 | x: 125 10 | } 11 | 12 | Text { 13 | text: childA.x 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/somelib/RectangleColor.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import "." // import "" is not correct, qmlscene says 3 | 4 | Rectangle { 5 | color: 'green' 6 | width: 100 7 | height: 100 8 | ShinyButton { 9 | x: 10 10 | y: 10 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/modules/QtQuick/ListElement.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_ListElement extends QtQml_QtObject { 3 | $setCustomData(propName, value) { 4 | QmlWeb.createProperty("variant", this, propName, { 5 | initialValue: value 6 | }); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/QMLEngine/basepath/import/A.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.Controls 1.2 3 | 4 | Item { 5 | property var a 6 | property var b 7 | 8 | onAChanged: foo1() 9 | onBChanged: foo2() 10 | 11 | function foo1() { b = a+1; } 12 | function foo2() {} 13 | } -------------------------------------------------------------------------------- /tests/QMLEngine/qml/PropertiesChangedExpressionSignal.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | property int counter: 0 5 | 6 | property int value: 0 7 | Component.onCompleted: value++ 8 | 9 | property int foo: value > 0 ? 1 : 0 10 | onFooChanged: counter++ 11 | } 12 | -------------------------------------------------------------------------------- /tests/Qt.labs.settings/qml/SettingsAlias.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import Qt.labs.settings 1.0 3 | 4 | Item { 5 | id: root 6 | Settings { 7 | category: "QmlWebTestAlias" 8 | property alias width: root.width 9 | property alias height: root.height 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/modules/QtQuick.Controls.2/Label.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_Controls_2_Label extends QtQuick_Text { 3 | static versions = /^2\./; 4 | static properties = { 5 | background: "Item", 6 | palette: "palette" 7 | }; 8 | 9 | // TODO 10 | } 11 | -------------------------------------------------------------------------------- /tests/QtQuick.Layouts/qml/StackLayout.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtQuick.Layouts 1.15 3 | 4 | StackLayout { 5 | Rectangle { 6 | implicitHeight: 300 7 | implicitWidth: 200 8 | color: "black" 9 | } 10 | 11 | Rectangle { 12 | color: "red" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/QtQuick/qml/LoaderSourceComponentFromComponent.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Loader { 4 | height: 30 5 | width: 30 6 | sourceComponent: leComponent 7 | 8 | Component { 9 | id: leComponent 10 | Rectangle { 11 | color: "yellow" 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/Render/Async/Image.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Image { 4 | source: 'Image.png' 5 | 6 | onStatusChanged: { 7 | if (typeof window !== 'undefined' && 8 | status !== Image.Loading) { 9 | window.onTestLoad({ framesDelay: 2 }); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/Render/Simple/FlowRepeater.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Flow { 4 | width: 23 5 | height: 17 6 | Repeater { 7 | model: 11 8 | delegate: Rectangle { 9 | color: index % 3 ? '#ccc' : '#000' 10 | width: 5 11 | height: 5 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/qml/main.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Rectangle { 4 | color: "lightgray" 5 | width: 400 6 | height: 400 7 | 8 | Text { 9 | text: "Hello, world!" 10 | anchors.centerIn: parent 11 | font.pointSize: 24 12 | font.bold: true 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/BasicCreateObject.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.2 2 | 3 | Item { 4 | id: item 5 | property string contextVar: "42"; 6 | 7 | Component.onCompleted: { 8 | var c = Qt.createComponent("BasicCreateObjectSomeComponent.qml") 9 | c.createObject(item) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/PropertiesAliasToIdSameName.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.Controls 1.1 3 | 4 | Item { 5 | id: it 6 | 7 | property alias child: child 8 | 9 | Item { 10 | id: child 11 | x: 125 12 | } 13 | 14 | Text { 15 | text: it.child.x 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/modules/QmlWeb.Dom/DomParagraph.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QmlWeb_Dom_DomParagraph extends QmlWeb_Dom_DomElement { 3 | constructor(meta) { 4 | meta.tagName = "p"; 5 | if (!meta.style) meta.style = {}; 6 | meta.style.margin = 0; 7 | super(meta); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/modules/QtQuick.Particles/ParticlePainter.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_Particles_ParticlePainter extends QtQuick_Item { 3 | static versions = /^2\./; 4 | static properties = { 5 | groups: "list", 6 | system: "ParticleSystem" 7 | }; 8 | 9 | // TODO 10 | } 11 | -------------------------------------------------------------------------------- /tests/QtQuick/qml/LoaderComponent.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtWebSockets 1.0 as WS 3 | import "LoaderDirectory" as LD 4 | import "LoaderDirectory" 5 | 6 | Item { 7 | property int value: 42 8 | 9 | WS.WebSocket {} 10 | LoaderDirectoryComponent {} 11 | LD.LoaderDirectoryComponent {} 12 | } 13 | -------------------------------------------------------------------------------- /tests/Render/Simple/FlowTop.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Flow { 4 | width: 23 5 | height: 17 6 | flow: Flow.TopToBottom 7 | Repeater { 8 | model: 11 9 | delegate: Rectangle { 10 | color: index % 4 ? '#ccc' : '#000' 11 | width: 5 12 | height: 5 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/Auto/QtTest/tst_Math.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtTest 1.0 3 | 4 | TestCase { 5 | name: "Math" 6 | width: 30 + 10 7 | height: width - 5 8 | 9 | function test_width() { 10 | compare(width, 40) 11 | } 12 | 13 | function test_height() { 14 | compare(height, 35) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/BasicCreateObjectSomeComponent.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.2 2 | import QtQuick.Controls 1.0 3 | 4 | Rectangle { 5 | color: 'green' 6 | width: 320 7 | height: 32 8 | 9 | property var q: 22 10 | 11 | Text { 12 | color:'gold' 13 | text: 'variable from context = ' + contextVar 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ScopeMid.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | id: parentItem 5 | property int value: 100 6 | property int sum: childA.totalValue + childB.totalValue 7 | 8 | ScopeLeaf { 9 | id: childA 10 | value: 2 11 | } 12 | 13 | ScopeLeaf { 14 | id: childB 15 | value: 4 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/modules/QtQuick.Controls.2/TabBar.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_Controls_2_TabBar extends QtQuick_Controls_2_Container { 3 | static versions = /^2\./; 4 | static properties = { 5 | contentHeight: "real", 6 | contentWidth: "real", 7 | position: "enum" 8 | }; 9 | 10 | // TODO 11 | } 12 | -------------------------------------------------------------------------------- /src/modules/QtQuick.Particles/CustomParticle.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef, max-len 2 | class QtQuick_Particles_CustomParticle extends QtQuick_Particles_ParticlePainter { 3 | static versions = /^2\./; 4 | static properties = { 5 | fragmentShader: "string", 6 | vertexShader: "string" 7 | }; 8 | 9 | // TODO 10 | } 11 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/PropertiesStringConversion.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | property int intA: 10 5 | property string stringA: intA 6 | property string stringB: 11 7 | property string stringBinding: 1 + 1 8 | property string stringFalseVal: 0 9 | 10 | function reassign() { 11 | stringA = 333; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/QtQuick/qml/LoaderSourceDelayed.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Loader { 4 | id: loader 5 | 6 | function start() { 7 | timer.start() 8 | } 9 | 10 | Timer { 11 | id: timer 12 | interval: 10 13 | onTriggered: { 14 | loader.source = "LoaderComponent.qml" 15 | loader.yield() 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/QtQuick/qml/RepeaterListModel.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | property alias repeater: _repeater 5 | Repeater { 6 | id: _repeater 7 | model: ListModel { 8 | id: list_model 9 | } 10 | Item { 11 | property var firstRole: role1 12 | property var secondRole: role2 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/modules/QtWebEngine/WebEngineView.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtWebEngine_WebEngineView extends QtWebView_WebView { 3 | static versions = /^5\./; 4 | static properties = { 5 | // TODO 6 | }; 7 | static signals = { 8 | // TODO 9 | }; 10 | 11 | // TODO: implement more features on top of WebView 12 | } 13 | -------------------------------------------------------------------------------- /tests/Render/Simple/AnchorsFill.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Rectangle { 4 | color: "white" 5 | width: 16 6 | height: 16 7 | Rectangle { 8 | id: red 9 | color: "red" 10 | anchors.fill: parent 11 | Rectangle { 12 | color: "blue" 13 | anchors.fill: parent 14 | anchors.margins: 3 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/modules/QtQml/QValidator.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQml_QValidator extends QtQml_QtObject { 3 | static enums = { 4 | QValidator: { 5 | Invalid: 0, Intermediate: 1, Acceptable: 2 6 | } 7 | }; 8 | static properties = { 9 | locale: "string" 10 | }; 11 | 12 | fixup() {} // stub, does nothing 13 | } 14 | -------------------------------------------------------------------------------- /src/modules/QtQuick.Layouts/DirectionalLayout.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_Layouts_DirectionalLayout extends QtQuick_Layouts_Positioner { 3 | constructor(meta) { 4 | super(meta); 5 | this.spacingChanged.connect(this, this.layoutChildren); 6 | this.layoutDirectionChanged.connect(this, this.layoutChildren); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/BindingsArray.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | id: main 5 | property int value: 5 6 | property bool novalue 7 | property variant arr: [1, 2, "hello world", [1, 2, false]] 8 | property variant bindingArray: [1, 2, "hello world", [+1, main.value - 3, novalue]] 9 | property string text: "Value=" + value 10 | } 11 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/BindingsUpdate.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | property int intA: 10 5 | property int intB: intA * 2 6 | property string textA: "hello" 7 | property string textB: textA + " world" 8 | property size size: Qt.size(1, 2) 9 | property real sizeWidth: size.width 10 | property real sizeHeight: size.height 11 | } 12 | -------------------------------------------------------------------------------- /tests/Render/Simple/ScaleRectangle.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Rectangle { 4 | color: 'green' 5 | width: 60; height: 50 6 | 7 | Rectangle { 8 | width: 50; height: 50 9 | color: "#00f" 10 | transform: Scale { 11 | origin.x: 20 12 | origin.y: 15 13 | xScale: 0.5 14 | yScale: 0.8 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/QtQuick/qml/MouseAreaGeneric.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Rectangle { 4 | width: 20 5 | height: 20 6 | property bool pressed: mouse_area.pressed 7 | property Item area: mouse_area 8 | property int clicks: 0 9 | MouseArea { 10 | id: mouse_area 11 | width: 10 12 | height: 10 13 | onClicked: parent.clicks++ 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/Render/Simple/RepeaterNumber.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Rectangle { 4 | color: '#fff' 5 | width: 50 6 | height: 25 7 | 8 | Repeater { 9 | model: 10 10 | delegate: Rectangle { 11 | color: 'black' 12 | width: 5 13 | height: 5 14 | x: 5 * index 15 | y: 5 * index % parent.height 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/BasicSignalParameters.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | id: item 5 | 6 | signal someSignal(int a, string b) 7 | 8 | property int propA 9 | property string propB 10 | 11 | onSomeSignal: { 12 | propA = a 13 | propB = b 14 | } 15 | 16 | Component.onCompleted: { 17 | item.someSignal(42, "foo") 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/modules/QtQuick.Controls/TextArea.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_Controls_TextArea extends QtQuick_TextEdit { 3 | constructor(meta) { 4 | super(meta); 5 | const textarea = this.impl; 6 | textarea.style.padding = "5px"; 7 | textarea.style.borderWidth = "1px"; 8 | textarea.style.backgroundColor = "#fff"; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "8" 4 | - "stable" 5 | notifications: 6 | email: false 7 | cache: 8 | directories: 9 | - $HOME/.npm/ 10 | - node_modules 11 | before_install: 12 | - npm install -g codecov 13 | matrix: 14 | include: 15 | - node_js: "8" 16 | script: npm run coverage 17 | after_success: 18 | - codecov 19 | -------------------------------------------------------------------------------- /tests/Render/Simple/PropertyRectangle.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Rectangle { 4 | property real r: 3.4 5 | property int num: Math.round(1.5) 6 | property var arr: [1, 2, 3] 7 | property bool foo: true 8 | property string s: foo ? 'green' : 'red' 9 | color: s 10 | width: height * 2 11 | height: s.length + arr.length * arr[1] + (Math.round(r) - num) 12 | } 13 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/BasicCompletedOfDynamicObjects.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Rectangle { 4 | color: "red" 5 | id: item 6 | 7 | Component.onCompleted: { 8 | Qt.createQmlObject( 9 | "import QtQuick 2.2\nItem { Component.onCompleted: parent.color = 'cyan'; }", 10 | item, 11 | "inlinecode1", 12 | __executionContext 13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/QtQuick/qml/LoaderSourceComponentDelayed.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Loader { 4 | id: loader 5 | 6 | function start() { 7 | timer.start() 8 | } 9 | 10 | Timer { 11 | id: timer 12 | interval: 10 13 | onTriggered: { 14 | loader.sourceComponent = Qt.createComponent("LoaderComponent.qml") 15 | loader.yield() 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/modules/QtQuick.Particles/AngleDirection.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef, max-len 2 | class QtQuick_Particles_AngleDirection extends QtQuick_Particles_Direction { 3 | static versions = /^2\./; 4 | static properties = { 5 | angle: "real", 6 | angleVariation: "real", 7 | magnitude: "real", 8 | magnitudeVariation: "real" 9 | }; 10 | 11 | // TODO 12 | } 13 | -------------------------------------------------------------------------------- /tests/QtQml/qml/BindingBroken.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.5 2 | 3 | Item { 4 | property int targetValue: 0 5 | property alias sourceValue: sourceItem.value 6 | property bool when: false 7 | 8 | id: root 9 | 10 | Item { 11 | property int value: 0 12 | id: sourceItem 13 | } 14 | 15 | Binding { 16 | target: root; property: "targetValue"; when: root.when 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/modules/QtQuick/RegExpValidator.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_RegExpValidator extends QtQml_QValidator { 3 | static properties = { 4 | regExp: "var" 5 | }; 6 | 7 | validate(string) { 8 | if (!this.regExp) return true; 9 | return this.regExp.test(string) 10 | ? this.QValidator.Acceptable 11 | : this.QValidator.Invalid; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/phantom.callback.js: -------------------------------------------------------------------------------- 1 | /* global page */ 2 | 3 | module.exports = function(command, options) { 4 | if (options.offset) { 5 | page.clipRect = options.offset; 6 | } 7 | 8 | var system = require("system"); 9 | if (options.fileName && system.env.QMLWEB_SAVE_RENDER) { 10 | page.render("tmp/Render/" + options.fileName); 11 | } 12 | 13 | return page.renderBase64("PNG"); 14 | }; 15 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "qmlweb", 3 | "description": "QML port to Javascript", 4 | "main": "lib/qmlweb.min.js", 5 | "license": "BSD", 6 | "keywords": [ 7 | "qml", 8 | "qt" 9 | ], 10 | "homepage": "https://github.com/qmlweb/qmlweb", 11 | "moduleType": [ 12 | "globals" 13 | ], 14 | "ignore": [ 15 | "**/.*", 16 | "node_modules", 17 | "tests" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /src/modules/QtNfc/NearField.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtNfc_NearField extends QtQml_QtObject { 3 | static properties = { 4 | filter: "list", 5 | messageRecords: "list", 6 | orderMatch: "bool", 7 | polling: "bool" 8 | }; 9 | static signals = { 10 | tagFound: [], 11 | tagRemoved: [] 12 | }; 13 | 14 | // TODO: implementation based on Web NFC API 15 | } 16 | -------------------------------------------------------------------------------- /src/modules/QtQuick.Controls/ApplicationWindow.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_Controls_ApplicationWindow extends QtQuick_Window_Window { 3 | static versions = /^1\./; 4 | static properties = { 5 | //contentItem: "ContentItem", // TODO 6 | menuBar: "MenuBar", 7 | statusBar: "Item", 8 | style: "Component", 9 | toolBar: "Item" 10 | }; 11 | 12 | // TODO 13 | } 14 | -------------------------------------------------------------------------------- /tests/QtQml/qml/BindingOneWay.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.5 2 | 3 | Item { 4 | property int targetValue: 0 5 | property alias sourceValue: sourceItem.value 6 | property bool when: true 7 | 8 | id: root 9 | 10 | Item { 11 | property int value: 0 12 | id: sourceItem 13 | } 14 | 15 | Binding { 16 | target: root; property: "targetValue"; value: sourceItem.value; when: root.when 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/modules/QtQuick/Translate.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_Translate extends QtQml_QtObject { 3 | static properties = { 4 | x: "real", 5 | y: "real" 6 | }; 7 | 8 | constructor(meta) { 9 | super(meta); 10 | 11 | this.xChanged.connect(this.$parent, this.$parent.$updateTransform); 12 | this.yChanged.connect(this.$parent, this.$parent.$updateTransform); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ImportJavascript.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import "importTestSimple.js" as Imported 3 | 4 | Rectangle { 5 | height: 10 6 | width: Imported.importedTest(height) 7 | color: Imported.importedColor 8 | 9 | function importedColor() { 10 | return Imported.importedColor; 11 | } 12 | 13 | function setImportedColor(color) { 14 | return Imported.importedColor = color; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/StateSimple.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | Item { 3 | id: root 4 | property int value: 10 5 | states: [ 6 | State { 7 | name: "otherState" 8 | PropertyChanges { 9 | target: root 10 | value: 20 11 | } 12 | } 13 | ] 14 | function start() { 15 | yield() 16 | state = "otherState" 17 | yield() 18 | state = "" 19 | yield() 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/QtQml/qml/BindingUndefined.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.5 2 | 3 | Item { 4 | property var targetValue: null 5 | property alias sourceValue: sourceItem.value 6 | property bool when: true 7 | 8 | id: root 9 | 10 | Item { 11 | property var value: null 12 | id: sourceItem 13 | } 14 | 15 | Binding { 16 | target: root; property: "targetValue"; when: root.when; value: sourceItem.value 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/QtQuick.Layouts/qml/GridLayoutTopToBottom.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.Layouts 1.0 3 | 4 | GridLayout { 5 | flow: GridLayout.TopToBottom 6 | layoutDirection: Qt.LeftToRight 7 | rows: 3 8 | 9 | Repeater { 10 | model: 11 11 | delegate: Rectangle { 12 | implicitWidth: 100 13 | implicitHeight: 100 14 | color: ["red", "green", "blue"][index % 3] 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/Render/Simple/FlowReflowWidth.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Rectangle { 4 | width: 20 5 | height: 20 6 | 7 | Flow { 8 | width: 18 9 | Repeater { 10 | model: 7 11 | delegate: Rectangle { 12 | color: index % 2 ? '#ccc' : '#000' 13 | width: 5 14 | height: 5 15 | } 16 | } 17 | Component.onCompleted: { 18 | width = 20 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/QtQuick.Layouts/qml/GridLayoutLeftToRight.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.Layouts 1.0 3 | 4 | GridLayout { 5 | flow: GridLayout.LeftToRight 6 | layoutDirection: Qt.LeftToRight 7 | columns: 3 8 | 9 | Repeater { 10 | model: 11 11 | delegate: Rectangle { 12 | implicitWidth: 100 13 | implicitHeight: 100 14 | color: ["red", "green", "blue"][index % 3] 15 | } 16 | } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /tests/Render/Simple/Translate.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | width: 30; height: 24 5 | Rectangle { 6 | width: 10; height: 10 7 | color: '#0f0' 8 | transform: Translate { x: 2; y: 5 } 9 | } 10 | Rectangle { 11 | width: 10; height: 10 12 | anchors.bottom: parent.bottom 13 | anchors.right: parent.right 14 | color: '#00f' 15 | transform: Translate { x: -2; y : -5 } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/Render/Simple/res/LoaderScopeChild.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | Rectangle { 5 | anchors.top: parent.top 6 | anchors.right: parent.right 7 | width: 15 8 | height: 15 9 | color: 'green' 10 | } 11 | Rectangle { 12 | anchors.left: parent.left 13 | anchors.bottom: parent.bottom 14 | width: root.width / 2 15 | height: root.height / 2 16 | color: 'blue' 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/BindingsRecursiveInit3.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.2 2 | 3 | Item { 4 | width: 400 5 | property int intA: 3+3 6 | 7 | onIntAChanged: launch() 8 | 9 | property var log: "" 10 | function launch() { 11 | // perform something expensive and important, 12 | // where intA value really matters 13 | log = log + "Fly to planet N" + intA + "!"; 14 | } 15 | 16 | Text { 17 | text: log 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/BindingsRecursiveInit4.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.2 2 | 3 | Item { 4 | width: 400 5 | property int intA: 3 6 | 7 | onIntAChanged: launch() 8 | 9 | property var log: "" 10 | function launch() { 11 | // perform something expensive and important, 12 | // where intA value really matters 13 | log = log + "Fly to planet N" + intA + "!"; 14 | } 15 | 16 | Text { 17 | text: log 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/modules/QtQuick.Controls.2/Page.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_Controls_2_Page extends QtQuick_Controls_2_Control { 3 | static versions = /^2\./; 4 | static properties = { 5 | contentChildren: "list", 6 | contentData: "list", 7 | contentHeight: "real", 8 | contentWidth: "real", 9 | footer: "Item", 10 | header: "Item", 11 | title: "string" 12 | }; 13 | 14 | // TODO 15 | } 16 | -------------------------------------------------------------------------------- /tests/QtQuick.Layouts/qml/GridLayoutFill.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.Layouts 1.0 3 | 4 | GridLayout { 5 | flow: GridLayout.LeftToRight 6 | layoutDirection: Qt.LeftToRight 7 | columns: 3 8 | width: 445 9 | 10 | Repeater { 11 | model: 11 12 | delegate: Rectangle { 13 | implicitWidth: 100 14 | implicitHeight: 100 15 | color: ["red", "green", "blue"][index % 3] 16 | } 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/PropertiesBasic.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | property int intProperty: 10 5 | property double doubleProperty: 0.5 6 | property string stringProperty: "hello" 7 | property Item itemProperty: Item { } 8 | property var arrayProperty: [1, 2, "bar"] 9 | property int hexProperty: 0xFF 10 | property int octProperty: 077 11 | property double bigNumber: 1e8 12 | property size sizeProperty: Qt.size(5, 6) 13 | } 14 | -------------------------------------------------------------------------------- /tests/Render/Simple/FlowReflowHeight.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Rectangle { 4 | width: 20 5 | height: 20 6 | 7 | Flow { 8 | flow: Flow.TopToBottom 9 | height: 18 10 | Repeater { 11 | model: 7 12 | delegate: Rectangle { 13 | color: index % 2 ? '#ccc' : '#000' 14 | width: 5 15 | height: 5 16 | } 17 | } 18 | Component.onCompleted: { 19 | height = 20 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/Render/Simple/PropertyGrid.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import "./res" 3 | 4 | Grid { 5 | columns: 4 6 | spacing: 3 7 | Rectangle { color: "red"; width: 5; height: 5 } 8 | PropertyGridComponent { color: 'green'; width: 6; height: 3 } 9 | Rectangle { color: "#00f"; width: 2; height: 6 } 10 | PropertyGridComponent { color: 'cy' + 'an'; width: 1; height: 1 } 11 | Rectangle { color: false ? 'green' : "magenta"; width: 4; height: 4 } 12 | } 13 | -------------------------------------------------------------------------------- /tests/QtQuick/qml/FontWeights.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | property var weights: ["Thin", "ExtraLight", "Light", "Normal", "Medium", "DemiBold", "Bold", "ExtraBold", "Black"] 5 | property alias repeater: repeater_ 6 | Column { 7 | Repeater { 8 | id: repeater_ 9 | model: weights.length 10 | Text { 11 | text: weights[index] 12 | font.weight: eval("Font." + text) 13 | } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/.eslintrc: -------------------------------------------------------------------------------- 1 | env: 2 | jasmine: true 3 | globals: 4 | loadQmlFile: true 5 | prefixedQmlLoader: true 6 | loadQml: true 7 | setupDivElement: true 8 | customMatchers: true 9 | sendEvent: true 10 | Qt: true 11 | rules: 12 | block-scoped-var: 2 13 | no-var: 0 14 | prefer-arrow-callback: 0 15 | prefer-rest-params: 0 16 | prefer-spread: 0 17 | prefer-template: 0 18 | object-shorthand: 0 19 | no-invalid-this: 0 20 | no-unused-vars: 0 21 | -------------------------------------------------------------------------------- /src/engine/AutoLoader.js: -------------------------------------------------------------------------------- 1 | window.addEventListener("load", () => { 2 | const metaTags = document.getElementsByTagName("body"); 3 | for (let i = 0; i < metaTags.length; ++i) { 4 | const metaTag = metaTags[i]; 5 | const source = metaTag.getAttribute("data-qml"); 6 | if (source) { 7 | QmlWeb.qmlEngine = new QmlWeb.QMLEngine(); 8 | QmlWeb.qmlEngine.loadFile(source); 9 | QmlWeb.qmlEngine.start(); 10 | break; 11 | } 12 | } 13 | }); 14 | -------------------------------------------------------------------------------- /src/engine/jsparser.js: -------------------------------------------------------------------------------- 1 | function importJavascriptInContext(contextSetter, $context) { 2 | /* Set the QmlWeb.executionContext so that any internal calls to Qt.include 3 | * will have the proper context */ 4 | const oldExecutionContext = QmlWeb.executionContext; 5 | QmlWeb.executionContext = $context; 6 | contextSetter($context); 7 | QmlWeb.executionContext = oldExecutionContext; 8 | } 9 | 10 | QmlWeb.importJavascriptInContext = importJavascriptInContext; 11 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/BindingsRecursiveInit.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.2 2 | 3 | Item { 4 | width: 400 5 | property int intA: 10 / intB 6 | property int intB: 1+1 7 | 8 | onIntAChanged: launch() 9 | 10 | property var log: "" 11 | function launch() { 12 | // perform something expensive and important, 13 | // where intA value really matters 14 | log = log + "Fly to planet N" + intA + "!"; 15 | } 16 | 17 | Text { 18 | text: log 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/QtQml/qml/ConnectionsConnections.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | id: root 5 | property int value: 0 6 | 7 | property int test_value: 0 8 | 9 | property alias new_target: _new_target 10 | Item { 11 | id: _new_target 12 | property int value: 0 13 | } 14 | 15 | property alias connections: _connections 16 | Connections { 17 | id: _connections 18 | onValueChanged: { 19 | root.test_value++ 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/QtTest/qml/TestCaseSimple.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | import QtTest 1.1 3 | 4 | TestCase { 5 | name: "Simple" 6 | 7 | function test_one() { 8 | compare(1 + 2, 2 + 1, "1 + 2 = 2 + 1") 9 | } 10 | 11 | function test_two() { 12 | compare("abc", "ab" + "c", '"abc", "ab" + "c"') 13 | } 14 | 15 | function test_fail() { 16 | compare(0 + 2, 3, "0 + 2 = 3") 17 | } 18 | 19 | function test_skip() { 20 | skip("Let's skip") 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/BasicCreateQmlObject.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.2 2 | 3 | Item { 4 | id: item 5 | property string contextVar: "42"; 6 | 7 | Component.onCompleted: { 8 | var q = Qt.createQmlObject( 9 | "import QtQuick 2.2\nimport QtQuick.Controls 1.0\n Rectangle { color: 'green'; width: 320; height: 32; property var q: 22; Text{ color:'gold'; text: 'variable from context = ' + contextVar} }", 10 | item, 11 | "inlinecode1" 12 | ); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/QtQuick.Layouts/qml/ColumnLayoutImplicitSize.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.Layouts 1.0 3 | 4 | ColumnLayout { 5 | spacing: 0 6 | 7 | Rectangle { 8 | color: "red" 9 | implicitHeight: 20 10 | implicitWidth: 30 11 | } 12 | Rectangle { 13 | color: "green" 14 | Layout.preferredHeight: 21 15 | implicitWidth: 25 16 | } 17 | Rectangle { 18 | color: "blue" 19 | implicitHeight: 23 20 | implicitWidth: 31 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/QtQuick.Layouts/qml/RowLayoutImplicitSize.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.Layouts 1.0 3 | 4 | RowLayout { 5 | spacing: 0 6 | 7 | Rectangle { 8 | color: "red" 9 | implicitHeight: 20 10 | implicitWidth: 30 11 | } 12 | Rectangle { 13 | color: "green" 14 | implicitHeight: 25 15 | Layout.preferredWidth: 21 16 | } 17 | Rectangle { 18 | color: "blue" 19 | implicitHeight: 23 20 | implicitWidth: 31 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /tests/QtQuick/Behavior.js: -------------------------------------------------------------------------------- 1 | describe("QtQuick.Behavior", function() { 2 | setupDivElement(); 3 | var load = prefixedQmlLoader("QtQuick/qml/Behavior"); 4 | 5 | it("Basic", function(done) { 6 | var qml = load("Basic", this.div); 7 | expect(qml.gotX).toBe(false); 8 | expect(qml.gotY).toBe(false); 9 | setTimeout(function() { 10 | expect(qml.gotX).toBe(true); 11 | expect(qml.gotY).toBe(false); 12 | done(); 13 | }, 200); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /tests/QtQuick/qml/RepeaterPropertyRoleNameConflict.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | property alias repeater: _repeater 5 | Repeater { 6 | id: _repeater 7 | model: ListModel { 8 | ListElement { 9 | roleName: "foo" 10 | } 11 | } 12 | Item { 13 | property var roleName: "bar" 14 | property var implicitRoleNameReference: roleName 15 | property var explicitRoleNameReference: model.roleName 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/Render/Async/ColorAnimation.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | width: 10 5 | height: 10 6 | Rectangle { 7 | width: 10 8 | height: 10 9 | color: 'black' 10 | 11 | ColorAnimation on color { 12 | from: 'red'; to: 'green'; duration: 50 13 | running: true 14 | } 15 | } 16 | 17 | Timer { 18 | interval: 100 19 | running: typeof window !== 'undefined' 20 | onTriggered: window.onTestLoad() 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/QMLEngine/javascript.js: -------------------------------------------------------------------------------- 1 | describe("QMLEngine.javascript", function() { 2 | setupDivElement(); 3 | var load = prefixedQmlLoader("QMLEngine/qml/Javascript"); 4 | 5 | it("can be parsed", function() { 6 | load("BasicSyntax", this.div); 7 | }); 8 | 9 | it("can parse regexp", function() { 10 | var qml = load("Regexp", this.div); 11 | expect("toto".match(qml.reg)).toBe(null); 12 | expect("4242/firstsecond".match(qml.reg)).not.toBe(null); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /tests/QtQuick/Text.js: -------------------------------------------------------------------------------- 1 | describe("QtQuick.Text", function() { 2 | setupDivElement(); 3 | 4 | var load = prefixedQmlLoader("QtQuick/qml/Text"); 5 | it("implicit size", function() { 6 | var qml = load("ImplicitSize", this.div); 7 | expect(qml.text_item.width).toBeGreaterThan(0); 8 | }); 9 | 10 | it("default wrap mode", function() { 11 | var qml = load("WrapMode", this.div); 12 | expect(qml.dom.children[0].style.whiteSpace).toBe("pre"); 13 | }); 14 | }); 15 | 16 | -------------------------------------------------------------------------------- /src/modules/QtQuick/PropertyChanges.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_PropertyChanges extends QtQml_QtObject { 3 | static properties = { 4 | target: "QtObject", 5 | explicit: "bool", 6 | restoreEntryValues: { type: "bool", initialValue: true } 7 | }; 8 | 9 | constructor(meta) { 10 | super(meta); 11 | 12 | this.$actions = []; 13 | } 14 | $setCustomData(property, value) { 15 | this.$actions.push({ property, value }); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/QtQuick/qml/BehaviorBasic.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | property bool gotX 5 | property bool gotY 6 | 7 | Behavior on x { 8 | NumberAnimation { 9 | duration: 200 10 | } 11 | } 12 | Behavior on y { 13 | enabled: false 14 | NumberAnimation { 15 | duration: 200 16 | } 17 | } 18 | onXChanged: if (x > 0 && x < 1) gotX = true; 19 | onYChanged: if (y > 0 && y < 1) gotY = true; 20 | Component.onCompleted: x = y = 1; 21 | } 22 | -------------------------------------------------------------------------------- /tests/Render/Simple/RectanglesGrid.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Rectangle { 4 | color: 'white' 5 | width: 20 6 | height: 15 7 | Grid { 8 | columns: 3 9 | spacing: 2 10 | Rectangle { color: 'red'; width: 5; height: 5 } 11 | Rectangle { color: 'green'; width: 6; height: 3 } 12 | Rectangle { color: 'blue'; width: 2; height: 6 } 13 | Rectangle { color: 'cyan'; width: 1; height: 1 } 14 | Rectangle { color: 'black'; width: 4; height: 4 } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/modules/QtQuick.Controls.2/ApplicationWindow.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_Controls_2_ApplicationWindow extends QtQuick_Window_Window { 3 | static versions = /^2\./; 4 | static properties = { 5 | font: "font", 6 | activeFocusControl: "Control", 7 | background: "Item", 8 | contentData: "list", 9 | //contentItem: "ContentItem", // TODO 10 | footer: "Item", 11 | header: "Item", 12 | overlay: "Item" 13 | }; 14 | 15 | // TODO 16 | } 17 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/BasicSignalDisconnectOnDelete.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.2 2 | 3 | Item { 4 | id: item 5 | property variant child 6 | 7 | function foo() { 8 | console.log("colour changed"); 9 | } 10 | 11 | Item { 12 | id: some_child 13 | } 14 | 15 | function create_object() { 16 | return Qt.createQmlObject( 17 | "import QtQuick 2.2\nRectangle { color: 'green'; width: 320; height: 32; }", 18 | some_child, 19 | "inlinecode1" 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ScopeSafeFromLocals.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | property var a: 'a_init_value' 5 | property var b: 'b_init_value' 6 | property var c: '' 7 | property var d 8 | property var p 9 | property var q 10 | 11 | 12 | function foo() { 13 | a = '333'; 14 | var b = '3local'; 15 | var c = b; 16 | d = b; 17 | p = q = 17; 18 | } 19 | 20 | Component.onCompleted: foo() 21 | 22 | Text { 23 | text: 'a=' + a + ' b=' + b; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/QtQuick/qml/TimerRunning.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.5 2 | Item { 3 | id: root 4 | 5 | function start() { 6 | success_timer.running = true 7 | fail_timer.start() 8 | } 9 | 10 | Timer { 11 | id: fail_timer 12 | interval: 500 13 | onTriggered: { 14 | root.yield(false) 15 | } 16 | } 17 | 18 | Timer { 19 | id: success_timer 20 | interval: 250 21 | onTriggered: { 22 | fail_timer.stop() 23 | root.yield(true) 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/QtQuick/Font.js: -------------------------------------------------------------------------------- 1 | describe("QtQuick.Font", function() { 2 | setupDivElement(); 3 | var load = prefixedQmlLoader("QtQuick/qml/Font"); 4 | 5 | it("Weights", function() { 6 | var qml = load("Weights", this.div); 7 | for (var i = 0; i < 9; ++i) { 8 | /* Special case for "Normal", as it just unsets the fontWeight style */ 9 | expect(qml.repeater.itemAt(i).dom.children[0].style.fontWeight) 10 | .toBe("" + (i !== 3 ? (i + 1) * 100 : "")); 11 | } 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /tests/Render/Simple/AnchorsCenterAndFill2.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Rectangle { 4 | color: "green" 5 | width: 30; height: 30 6 | 7 | Rectangle { 8 | anchors.centerIn: parent 9 | color: "blue" 10 | width: 10 11 | height: 10 12 | 13 | Item { 14 | anchors.fill: parent 15 | anchors.margins: 2 16 | 17 | Rectangle { 18 | anchors.centerIn: parent 19 | width: 8 20 | height: 8 21 | color: "red" 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/Render/Simple/ScaleRectangleOrigin.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Rectangle { 4 | color: 'green' 5 | width: 60; height: 50 6 | 7 | Rectangle { 8 | width: 50; height: 50 9 | color: "#00f" 10 | transform: Scale { 11 | xScale: 0.5 12 | yScale: 0.8 13 | } 14 | } 15 | 16 | Rectangle { 17 | width: 50; height: 50 18 | color: "red" 19 | transform: Scale { 20 | origin.x: 0 21 | origin.y: 0 22 | xScale: 0.4 23 | yScale: 0.3 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/modules/QtTest/SignalSpy.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtTest_SignalSpy extends QtQuick_Item { 3 | static versions = /^1\./; 4 | static properties = { 5 | count: "int", 6 | signalArguments: "list", 7 | signalName: "string", 8 | target: "var", 9 | valid: "bool" 10 | }; 11 | 12 | // TODO 13 | 14 | clear() { 15 | this.count = 0; 16 | this.signalArguments.length = 0; 17 | //this.valid = false; 18 | } 19 | 20 | /* 21 | wait(timeout = 5000) { 22 | } 23 | */ 24 | } 25 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/PropertiesAliasChanged.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.Controls 1.1 3 | 4 | Item { 5 | property alias childX: child.x 6 | 7 | Item { 8 | id: child 9 | x: 125 10 | } 11 | 12 | property string log: "" 13 | onChildXChanged: log = log + "childX changed to "+childX+"!" 14 | 15 | function go() { 16 | child.x = 44; 17 | } 18 | 19 | Column { 20 | Text { 21 | text: log 22 | } 23 | Button { 24 | text: "go!" 25 | onClicked: go(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/QMLEngine/basepath/test.js: -------------------------------------------------------------------------------- 1 | describe("QMLEngine.basepath", function() { 2 | setupDivElement(); 3 | var webroot = "/base/tests/QMLEngine/basepath/"; 4 | 5 | // this checks the case of evalling properties during component init 6 | // when this component is imported from another directory 7 | // followed by loading of component in current directory 8 | it("engine.$basePath is not corrupted after recursive properties eval", 9 | function() { 10 | var qml = loadQmlFile(webroot + "test.qml", this.div); 11 | } 12 | ); 13 | }); 14 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/BasicResolvedUrl.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | property var current: Qt.resolvedUrl('.') 5 | property var inner1: Qt.resolvedUrl('foo/bar') 6 | property var inner2: Qt.resolvedUrl('foo/bar/') 7 | property var inner3: Qt.resolvedUrl('foo//bar/../foo////bar/./../lol/x../..s/../..') 8 | property var outer: Qt.resolvedUrl('../..') 9 | property var full: Qt.resolvedUrl('http://example.com/bar') 10 | property var absolute: Qt.resolvedUrl('/foo/bar') 11 | property var aboutBlank: Qt.resolvedUrl("about:blank") 12 | } 13 | -------------------------------------------------------------------------------- /tests/Render/Async/NumberAnimationAutorun.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | width: 20 5 | height: 10 6 | 7 | Rectangle { 8 | color: "blue" 9 | width: 10 10 | height: 10 11 | 12 | NumberAnimation on x { 13 | from: 0; to: 10; duration: 50 14 | } 15 | 16 | Component.onCompleted: color = x > 0 ? 'red' : 'green' 17 | } 18 | 19 | Timer { 20 | interval: 100 21 | running: typeof window !== 'undefined' 22 | onTriggered: window.onTestLoad() 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/QtQuick/qml/ParallelAnimationRunning.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | width: 900 5 | height: 300 6 | 7 | Row { 8 | Rectangle { id: rectA } 9 | Rectangle { id: rectB } 10 | Rectangle { id: rectC } 11 | } 12 | 13 | ParallelAnimation { 14 | id:ani 15 | ColorAnimation { target: rectA; property: "color"; to: 'red'; duration: 100 } 16 | ColorAnimation { target: rectB; property: "color"; to: 'green'; duration: 100 } 17 | ColorAnimation { target: rectC; property: "color"; to: 'blue'; duration: 100 } 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /src/modules/QtMultimedia/VideoOutput.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtMultimedia_VideoOutput extends QtQuick_Item { 3 | static versions = /^5\./; 4 | static enums = { 5 | VideoOutput: { PreserveAspectFit: 0, PreserveAspectCrop: 1, Stretch: 2 } 6 | }; 7 | static properties = { 8 | autoOrientation: "bool", 9 | contentRect: "rect", 10 | fillMode: "enum", // VideoOutput.PreserveAspectFit 11 | filters: "list", 12 | orientation: "int", 13 | source: "variant", 14 | sourceRect: "rect" 15 | }; 16 | 17 | // TODO: impl 18 | } 19 | -------------------------------------------------------------------------------- /tests/Render/Async/NumberAnimation.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | width: 20 5 | height: 10 6 | 7 | Rectangle { 8 | color: "blue" 9 | width: 10 10 | height: 10 11 | 12 | NumberAnimation on x { 13 | from: 0; to: 10; duration: 50 14 | running: true 15 | } 16 | 17 | Component.onCompleted: color = x > 0 ? 'red' : 'green' 18 | } 19 | 20 | Timer { 21 | interval: 100 22 | running: typeof window !== 'undefined' 23 | onTriggered: window.onTestLoad() 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/modules/QtQuick/GradientStop.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_GradientStop extends QtQml_QtObject { 3 | static properties = { 4 | color: { type: "color", initialValue: "black" }, 5 | position: { type: "real", initialValue: 0.0 }, 6 | }; 7 | 8 | constructor(meta) { 9 | super(meta); 10 | 11 | this.$item = this.$parent.$item; 12 | this.colorChanged.connect(this, this.onUpdate); 13 | this.positionChanged.connect(this, this.onUpdate); 14 | } 15 | 16 | onUpdate() { 17 | this.$parent.$onGradientStopChanged(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/PropertiesAliasChangedBack.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.Controls 1.1 3 | 4 | Item { 5 | property alias thechild: child 6 | property alias childData: child.somedata 7 | 8 | Rectangle { 9 | id: child 10 | x: somedata[0] 11 | y: somedata[1] 12 | property var somedata: [0,0] 13 | 14 | color: "red"; width: 64; height: 64 15 | } 16 | 17 | function go() { 18 | childData[0] = 100; 19 | childDataChanged(); 20 | } 21 | 22 | Column { 23 | Button { 24 | text: "go!" 25 | onClicked: go(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/QtQuick/qml/SequentialAnimationRunning.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Rectangle { 4 | id: rect 5 | width: 300 6 | height: 300 7 | property Item area: mouse_area 8 | SequentialAnimation { 9 | id:ani 10 | ColorAnimation { target: rect; property: "color"; to: 'red'; duration: 100 } 11 | ColorAnimation { target: rect; property: "color"; duration: 100 } 12 | ColorAnimation { target: rect; property: "color"; to: 'green'; duration: 100 } 13 | } 14 | MouseArea{ 15 | id: mouse_area 16 | onClicked: ani.running = !ani.running 17 | anchors.fill: parent; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/QtQuick/PropertyAnimation.js: -------------------------------------------------------------------------------- 1 | describe("QtQuick.PropertyAnimation", function() { 2 | setupDivElement(); 3 | var load = prefixedQmlLoader("QtQuick/qml/PropertyAnimation"); 4 | 5 | it("Loads", function() { 6 | load("Loads", this.div); 7 | }); 8 | xit("FailsToLoad", function() { 9 | var exception = null; 10 | try { 11 | load("FailsToLoad", this.div); 12 | } catch (err) { 13 | exception = err; 14 | } 15 | expect(exception).not.toBe(null); 16 | expect(exception.message).toContain( 17 | "Cannot assign to non-existent default property"); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/PropertiesChangedSignal.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Rectangle { 4 | property int result: 0 5 | 6 | property int value: 1 7 | onValueChanged: result += 2 8 | 9 | width: 40 10 | height: 41 11 | 12 | property string foo: 'foo' 13 | property string bar: 'bar' 14 | 15 | onWidthChanged: result += 4 16 | onHeightChanged: result += 8 17 | onFooChanged: result += 16 18 | onBarChanged: result += 32 19 | 20 | Component.onCompleted: { 21 | result += 1; 22 | width = 41; 23 | height = 41; 24 | foo = 'foo'; 25 | bar = ''; 26 | bar = 'bar'; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/Render/Fuzzy/RectanglesOpacity.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | // Fuzzy because opacity color rounding could differ between implementations 4 | 5 | Rectangle { 6 | width: 100 7 | height: 100 8 | color: '#fff' 9 | Item { 10 | opacity: 0.5 11 | Rectangle { 12 | color: '#0f0' 13 | width: 50 14 | height: 50 15 | } 16 | Rectangle { 17 | color: '#ff0000' 18 | width: 50; 19 | height: 50 20 | x: 25; y: 25 21 | } 22 | Rectangle { 23 | color: '#00f' 24 | width: 50; 25 | height: 50 26 | x: 70; y: 20 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/engine/QMLList.js: -------------------------------------------------------------------------------- 1 | function QMLList(meta) { 2 | const list = []; 3 | if (meta.object instanceof Array) { 4 | for (const i in meta.object) { 5 | list.push(QmlWeb.construct({ 6 | object: meta.object[i], 7 | parent: meta.parent, 8 | context: meta.context 9 | })); 10 | } 11 | } else if (meta.object instanceof QmlWeb.QMLMetaElement) { 12 | list.push(QmlWeb.construct({ 13 | object: meta.object, 14 | parent: meta.parent, 15 | context: meta.context 16 | })); 17 | } 18 | 19 | return list; 20 | } 21 | QMLList.plainType = true; 22 | QmlWeb.qmlList = QMLList; 23 | -------------------------------------------------------------------------------- /tests/QtQml/qml/BindingTwoWay.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.5 2 | 3 | Item { 4 | property alias targetValue: targetItem.value 5 | property alias sourceValue: sourceItem.value 6 | property bool when: true 7 | 8 | id: root 9 | 10 | Item { 11 | property int value: 0 12 | id: sourceItem 13 | } 14 | 15 | Item { 16 | property int value: 0 17 | id: targetItem 18 | } 19 | 20 | Binding { 21 | target: targetItem; property: "value"; value: sourceItem.value; when: root.when 22 | } 23 | 24 | Binding { 25 | target: sourceItem; property: "value"; value: targetItem.value; when: root.when 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/Render/Simple/AnchorsCenterAndFill.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Rectangle { 4 | color: "white" 5 | width: 16 6 | height: 16 7 | Rectangle { 8 | id: red 9 | color: "red" 10 | anchors.centerIn: parent 11 | width: 8 12 | height: 8 13 | Rectangle { 14 | color: "blue" 15 | anchors.horizontalCenter: parent.horizontalCenter 16 | anchors.top: parent.top 17 | anchors.bottom: parent.bottom 18 | width: 4 19 | } 20 | } 21 | Rectangle { 22 | anchors.verticalCenter: parent.verticalCenter 23 | width: parent.width 24 | height: 4 25 | color: "grey" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/Render/Simple/ZeroOpacityLayout.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Row { 4 | width: 30 5 | height: 20 6 | Rectangle { 7 | width: 10 8 | height: parent.height 9 | color: 'red' 10 | opacity: 0 11 | } 12 | Rectangle { 13 | width: 10 14 | height: parent.height 15 | color: 'black' 16 | } 17 | Column { 18 | height: parent.height 19 | width: 10 20 | Rectangle { 21 | height: 10 22 | width: parent.width 23 | color: 'red' 24 | opacity: 0 25 | } 26 | Rectangle { 27 | height: 10 28 | width: parent.width 29 | color: 'black' 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/QtQuick/Item.js: -------------------------------------------------------------------------------- 1 | describe("QtQuick.Item", function() { 2 | setupDivElement(); 3 | var load = prefixedQmlLoader("QtQuick/qml/Item"); 4 | 5 | it("Empty", function() { 6 | load("Empty", this.div); 7 | var div = this.div.children[0]; 8 | expect(div.innerHTML).toBe(""); 9 | expect(div.style.backgroundColor).toBe(""); 10 | }); 11 | it("Size", function() { 12 | load("Size", this.div); 13 | var div = this.div.children[0]; 14 | expect(div.offsetWidth).toBe(200); 15 | expect(div.offsetHeight).toBe(100); 16 | expect(div.clientWidth).toBe(200); 17 | expect(div.clientHeight).toBe(100); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /tests/Render/Fuzzy/RectanglesAlpha.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | // Fuzzy because opacity color rounding could differ between implementations 4 | 5 | Rectangle { 6 | width: 100 7 | height: 100 8 | color: '#fff' 9 | Item { 10 | opacity: 0.9 11 | Rectangle { 12 | color: '#6000ff00' 13 | width: 50 14 | height: 50 15 | opacity: 0.5 16 | } 17 | Rectangle { 18 | color: '#9000ff' 19 | width: 50; 20 | height: 50 21 | x: 25; y: 25 22 | } 23 | Rectangle { 24 | color: Qt.rgba(1, 0.4, 0.4, 0.9) 25 | width: 50; 26 | height: 50 27 | x: 70; y: 20 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/QtQuick/qml/ListModel.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.5 2 | 3 | ListModel { 4 | id: fruitModel 5 | 6 | ListElement { 7 | name: "Apple" 8 | cost: 2.45 9 | attributes: [ 10 | ListElement { description: "Core" }, 11 | ListElement { description: "Deciduous" } 12 | ] 13 | } 14 | ListElement { 15 | name: "Orange" 16 | cost: 3.25 17 | attributes: [ 18 | ListElement { description: "Citrus" } 19 | ] 20 | } 21 | ListElement { 22 | name: "Banana" 23 | cost: 1.95 24 | attributes: [ 25 | ListElement { description: "Tropical" }, 26 | ListElement { description: "Seedless" } 27 | ] 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/modules/QtQuick/ShaderEffect.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_ShaderEffect extends QtQuick_Item { 3 | static enums = { 4 | ShaderEffect: { 5 | NoCulling: 0, BackFaceCulling: 1, FrontFaceCulling: 2, 6 | Compiled: 0, Uncompiled: 1, Error: 2 7 | } 8 | }; 9 | static properties = { 10 | blending: { type: "bool", initialValue: true }, 11 | cullMode: "enum", // ShaderEffect.NoCulling 12 | fragmentShader: "string", 13 | log: "string", 14 | mesh: "var", 15 | status: { type: "enum", initialValue: 1 }, // ShaderEffect.Uncompiled 16 | supportsAtlasTextures: "bool", 17 | vertexShader: "string" 18 | }; 19 | 20 | // TODO 21 | } 22 | -------------------------------------------------------------------------------- /src/modules/QtQuick.Controls.2/SwipeView.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_Controls_2_SwipeView extends QtQuick_Controls_2_Container { 3 | static versions = /^2\./; 4 | static properties = { 5 | horizontal: "bool", 6 | interactive: "bool", 7 | orientation: "enum", 8 | vertical: "bool" 9 | }; 10 | 11 | // TODO 12 | 13 | layoutChildren() { 14 | let pos = 0; 15 | for (let i = 0; i < this.children.length; i++) { 16 | const child = this.children[i]; 17 | if (!child.visible) continue; 18 | child.height = this.height; 19 | child.width = this.width; 20 | child.x = pos; 21 | pos += child.width; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/QtQuick/qml/SequentialAnimationPaused.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Rectangle { 4 | id: rect 5 | width: 300 6 | height: 300 7 | property Item area: mouse_area 8 | SequentialAnimation { 9 | id:ani 10 | ColorAnimation { target: rect; property: "color"; to: 'red'; duration: 100 } 11 | ColorAnimation { target: rect; property: "color"; duration: 100 } 12 | ColorAnimation { target: rect; property: "color"; to: 'green'; duration: 100 } 13 | } 14 | MouseArea{ 15 | id: mouse_area 16 | onClicked: { 17 | if(ani.running){ 18 | ani.paused = !ani.paused 19 | }else{ 20 | ani.running = true; 21 | } 22 | } 23 | anchors.fill: parent; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/StateWhen.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | Item { 3 | id: root 4 | property int value: 10 5 | property int stateTrigger: 0 6 | 7 | states: [ 8 | State { 9 | name: "state1" 10 | PropertyChanges { 11 | target: root 12 | value: 20 13 | } 14 | when: root.stateTrigger == 1 15 | }, 16 | State { 17 | name: "state2" 18 | PropertyChanges { 19 | target: root 20 | value: 30 21 | } 22 | when: root.stateTrigger == 2 23 | } 24 | ] 25 | 26 | function start(){ 27 | yield() 28 | stateTrigger = 1 29 | yield() 30 | stateTrigger = 2 31 | yield() 32 | stateTrigger = 3 33 | yield() 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /examples/embed.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | QML Embed Example 5 | 12 | 13 | 14 | 15 |
16 |
17 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/BindingsRecursiveInit2.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.2 2 | import QtQuick.Controls 1.0 3 | 4 | Item { 5 | width: 800 6 | property int intA: 10 / intB + intD 7 | property int intB: intC 8 | property int intC: 1 9 | property int intD: 0 10 | 11 | onIntAChanged: launch() 12 | 13 | property var log: "" 14 | function launch() { 15 | // perform something expensive and important, 16 | // where intA value really matters 17 | log = log + "Fly to planet N" + intA + "!"; 18 | } 19 | 20 | function retarget() { 21 | intD = 5; 22 | } 23 | 24 | Text { 25 | text: log 26 | } 27 | 28 | Button { 29 | y: 30 30 | text: "retarget!" 31 | onClicked: retarget() 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/modules/QtQuick.Particles/ParticleSystem.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_Particles_ParticleSystem extends QtQuick_Item { 3 | static versions = /^2\./; 4 | static properties = { 5 | empty: "bool", 6 | particleStates: "list", 7 | paused: "bool", 8 | running: { type: "bool", initialValue: true } 9 | }; 10 | 11 | // TODO 12 | 13 | pause() { 14 | this.paused = true; 15 | } 16 | reset() { 17 | // TODO 18 | } 19 | restart() { 20 | this.running = false; 21 | this.running = true; 22 | } 23 | resume() { 24 | this.paused = false; 25 | } 26 | start() { 27 | this.running = true; 28 | } 29 | stop() { 30 | this.running = false; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/modules/QtQuick/IntValidator.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_IntValidator extends QtQml_QValidator { 3 | static properties = { 4 | bottom: { type: "int", initialValue: -2147483647 }, 5 | top: { type: "int", initialValue: 2147483647 } 6 | }; 7 | 8 | validate(string) { 9 | const regExp = /^(-|\+)?\s*[0-9]+$/; 10 | 11 | if (regExp.test(string.trim())) { 12 | const value = parseInt(string, 10); 13 | if (this.bottom <= value && this.top >= value) { 14 | return this.QValidator.Acceptable; 15 | } else if (string.length <= this.top.toString().length) { 16 | return this.QValidator.Intermediate; 17 | } 18 | } 19 | return this.QValidator.Invalid; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/modules/QmlWeb.Dom/DomStyle.js: -------------------------------------------------------------------------------- 1 | const styleProperties = {}; 2 | for (const property in document.createElement("div").style) { 3 | styleProperties[property] = "string"; 4 | } 5 | 6 | class QmlWeb_Dom_DomStyle extends QmlWeb.QObject { 7 | constructor(meta) { 8 | super(meta); 9 | 10 | this.updated = (new QmlWeb.Signal([], { obj: this })).signal; 11 | QmlWeb.createProperties(this, styleProperties); 12 | for (const propertyName in this.$properties) { 13 | const property = this.$properties[propertyName]; 14 | property.changed.connect(this, newVal => { 15 | this.$parent.dom.style[propertyName] = newVal; 16 | this.updated(); 17 | }); 18 | } 19 | } 20 | } 21 | 22 | QmlWeb.DomStyle = QmlWeb_Dom_DomStyle; 23 | -------------------------------------------------------------------------------- /tests/Render/Simple/RectangleBorderChildren.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.5 2 | 3 | Rectangle { 4 | width: 75 5 | height: 15 6 | border.width: 5 7 | border.color: 'grey' 8 | color: 'green' 9 | 10 | Rectangle { 11 | width: 10 12 | height: 10 13 | } 14 | Rectangle { 15 | width: 11 16 | height: 10 17 | x: 15 18 | border.color: 'red' 19 | } 20 | Rectangle { 21 | width: 10 22 | height: 12 23 | x: 30 24 | border.width: 2 25 | } 26 | Rectangle { 27 | // no width/heigth is set but border is set 28 | x: 45 29 | color: 'orange' 30 | border.width: 1 31 | } 32 | Rectangle { 33 | x: 60 34 | border.width: 0 35 | border.color: 'red' 36 | width: 10 37 | height: 10 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/modules/QtQuick/Animator.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_Animator extends QtQuick_Animation { 3 | static versions = /^2\./; 4 | static properties = { 5 | duration: { type: "int", initialValue: 250 }, 6 | from: "real", 7 | target: "Item", 8 | to: "real" 9 | }; 10 | 11 | constructor(meta) { 12 | super(meta); 13 | 14 | this.easing = new QmlWeb.QObject(this); 15 | QmlWeb.createProperties(this.easing, { 16 | type: { type: "enum", initialValue: this.Easing.Linear }, 17 | amplitude: { type: "real", initialValue: 1 }, 18 | overshoot: { type: "real", initialValue: 1.70158 }, 19 | period: { type: "real", initialValue: 0.3 }, 20 | bezierCurve: "list" 21 | }); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/Render/Simple/RepeaterListModel.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Rectangle { 4 | color: '#ff9' 5 | width: 25 6 | height: 25 7 | 8 | ListModel { 9 | id: list 10 | ListElement { my: 'blue' } 11 | ListElement { my: 'red' } 12 | ListElement { my: 'transparent' } 13 | ListElement { my: '#0f0' } 14 | ListElement { my: '#0ff' } 15 | } 16 | 17 | Repeater { 18 | model: list 19 | Rectangle { 20 | color: my 21 | width: 5 22 | height: 5 23 | x: 5 * index 24 | y: 5 * index 25 | } 26 | } 27 | Repeater { 28 | model: list 29 | delegate: Rectangle { 30 | color: my 31 | width: 5 32 | height: 5 33 | x: 5 * index 34 | y: 20 - 5 * index 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/engine/getset.js: -------------------------------------------------------------------------------- 1 | /* eslint accessor-pairs: 0 */ 2 | 3 | function setupGetter(obj, propName, func) { 4 | Object.defineProperty(obj, propName, { 5 | get: func, 6 | configurable: true, 7 | enumerable: true 8 | }); 9 | } 10 | 11 | function setupSetter(obj, propName, func) { 12 | Object.defineProperty(obj, propName, { 13 | set: func, 14 | configurable: true, 15 | enumerable: false 16 | }); 17 | } 18 | 19 | function setupGetterSetter(obj, propName, getter, setter) { 20 | Object.defineProperty(obj, propName, { 21 | get: getter, 22 | set: setter, 23 | configurable: true, 24 | enumerable: false 25 | }); 26 | } 27 | 28 | QmlWeb.setupGetter = setupGetter; 29 | QmlWeb.setupSetter = setupSetter; 30 | QmlWeb.setupGetterSetter = setupGetterSetter; 31 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/StateBinding.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | Item { 3 | id: root 4 | property int stateTrigger: 0 5 | property int variable: 5 6 | property int value: 10 + variable 7 | 8 | states: [ 9 | State { 10 | name: "state1" 11 | PropertyChanges { 12 | target: root 13 | value: 20 + variable 14 | } 15 | when: root.stateTrigger == 1 16 | }, 17 | State { 18 | name: "state2" 19 | PropertyChanges { 20 | target: root 21 | value: 30 + variable 22 | } 23 | when: root.stateTrigger == 2 24 | } 25 | ] 26 | 27 | function start(){ 28 | yield() 29 | stateTrigger = 1 30 | yield() 31 | stateTrigger = 2 32 | yield() 33 | stateTrigger = 3 34 | yield() 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/modules/QtQuick.Controls.2/Control.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_Controls_2_Control extends QtQuick_Item { 3 | static versions = /^2\./; 4 | static properties = { 5 | availableHeight: "real", 6 | availableWidth: "real", 7 | background: "Item", 8 | bottomPadding: "real", 9 | contentItem: "Item", 10 | focusPolicy: "enum", 11 | focusReason: "enum", 12 | font: "font", 13 | hoverEnabled: "bool", 14 | hovered: "bool", 15 | leftPadding: "real", 16 | locale: "Locale", 17 | mirrored: "bool", 18 | padding: "real", 19 | palette: "palette", 20 | rightPadding: "real", 21 | spacing: "real", 22 | topPadding: "real", 23 | visualFocus: "bool", 24 | wheelEnabled: "bool" 25 | }; 26 | 27 | // TODO 28 | } 29 | -------------------------------------------------------------------------------- /tests/qmlweb.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const path = require("path"); 3 | 4 | function include(file, window) { 5 | const document = window.document; 6 | const exports = global; 7 | // eslint-disable-next-line no-eval 8 | eval(fs.readFileSync(path.join(__dirname, file), "utf-8")); 9 | } 10 | 11 | require("jsdom").env("", (err, window) => { 12 | include("../lib/qmlweb.js", window); 13 | include("../lib/qmlweb.parser.js", window); 14 | 15 | const document = window.document; 16 | const file = process.argv[process.argv.length - 1]; 17 | const div = document.createElement("div"); 18 | document.body.appendChild(div); 19 | var engine = new QmlWeb.QMLEngine(div, {}); 20 | QmlWeb.urlContentCache[file] = fs.readFileSync(file, "utf-8"); 21 | engine.loadFile(file); 22 | engine.start(); 23 | }); 24 | -------------------------------------------------------------------------------- /src/modules/QtQuick/Column.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_Column extends QtQuick_Positioner { 3 | layoutChildren() { 4 | let curPos = this.padding; 5 | let maxWidth = 0; 6 | for (let i = 0; i < this.children.length; i++) { 7 | const child = this.children[i]; 8 | if (!child.visible || !child.width || !child.height) { 9 | continue; 10 | } 11 | maxWidth = child.width > maxWidth ? child.width : maxWidth; 12 | child.y = curPos + this.padding; 13 | if (this.padding > 0) child.x = this.padding; 14 | curPos += child.height + this.spacing; 15 | } 16 | this.implicitWidth = maxWidth + this.padding * 2; 17 | this.implicitHeight = curPos - this.spacing + this.padding; 18 | // We want no spacing at the bottom side 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ImportJavascriptScope.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import "importTestSimple.js" as Imported 3 | 4 | Item { 5 | property alias component: _component 6 | property alias component2: _component2 7 | property alias loader: _loader 8 | property alias repeater: _repeater 9 | 10 | function importedColor() { 11 | return Imported.importedColor; 12 | } 13 | function setImportedColor(color) { 14 | return Imported.importedColor = color; 15 | } 16 | 17 | ImportJavascript { 18 | id: _component 19 | } 20 | ImportJavascript { 21 | id: _component2 22 | } 23 | 24 | Repeater { 25 | id: _repeater 26 | model: 2 27 | ImportJavascript { 28 | } 29 | } 30 | 31 | Loader { 32 | id: _loader 33 | source: "ImportJavascript.qml" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/failingTests.js: -------------------------------------------------------------------------------- 1 | window.failingTests = { 2 | Render: { 3 | Simple: [ 4 | "RectangleImplicitSize" 5 | ] 6 | }, 7 | QMLEngine: { 8 | basic: [ 9 | "SignalDisconnect" 10 | ], 11 | imports: [ 12 | "Qmldir singleton" 13 | ], 14 | scope: [ 15 | "object id should override same-named property of base object" 16 | ] 17 | }, 18 | QtQml: { 19 | Binding: [ 20 | "binding undefined var" 21 | ] 22 | }, 23 | QtQuick: { 24 | Timer: [ 25 | "can roughly set short intervals" // flaky 26 | ], 27 | Repeater: [ 28 | "handle delegate property and role name conflict" 29 | ] 30 | }, 31 | Initialize: { 32 | QtQuick: [ 33 | "Translate", 34 | "Scale", 35 | "Rotation", 36 | "Font" 37 | ] 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /src/modules/QtQuick.Controls.2/AbstractButton.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_Controls_2_AbstractButton extends QtQuick_Controls_2_Control { 3 | static versions = /^2\./; 4 | static properties = { 5 | action: "Action", 6 | autoExclusive: "bool", 7 | checkable: "bool", 8 | checked: "bool", 9 | display: "enum", 10 | // icon is defined manually 11 | down: "bool", 12 | indicator: "Item", 13 | pressed: "bool", 14 | text: "string" 15 | }; 16 | 17 | constructor(meta) { 18 | super(meta); 19 | 20 | this.icon = new QmlWeb.QObject(this); 21 | QmlWeb.createProperties(this.icon, { 22 | name: "string", 23 | source: "url", 24 | width: "int", 25 | height: "int", 26 | color: "color" 27 | }); 28 | 29 | // TODO 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/Render/Simple/AnchorsSides.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Rectangle { 4 | color: "white" 5 | width: 16 6 | height: 16 7 | 8 | Rectangle { 9 | color: "orange" 10 | width: 8 11 | height: 8 12 | anchors { 13 | left: parent.left 14 | bottom: parent.bottom 15 | } 16 | } 17 | Rectangle { 18 | color: "green" 19 | width: 6 20 | height: 6 21 | anchors { 22 | left: parent.left 23 | top: parent.top 24 | } 25 | } 26 | Rectangle { 27 | color: "cyan" 28 | width: 8 29 | height: 8 30 | anchors { 31 | right: parent.right 32 | top: parent.top 33 | } 34 | } 35 | Rectangle { 36 | color: "red" 37 | width: 6 38 | height: 6 39 | anchors { 40 | right: parent.right 41 | bottom: parent.bottom 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tests/QtQuick/qml/RepeaterCompletedDestruction.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | id: root 5 | 6 | property int internal_created 7 | property int internal_destroyed 8 | 9 | Repeater { 10 | id: repeater 11 | Item { 12 | Repeater { 13 | model: 1 14 | Rectangle { 15 | Component.onCompleted: { 16 | root.internal_created++ 17 | } 18 | Component.onDestruction: { 19 | root.internal_destroyed++ 20 | } 21 | } 22 | } 23 | } 24 | } 25 | 26 | Component.onCompleted: { 27 | repeater.model = 1 28 | repeater.model = 0 29 | repeater.model = 2 30 | repeater.model = 0 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/QtQml/Connections.js: -------------------------------------------------------------------------------- 1 | describe("QtQml.Connections", function() { 2 | setupDivElement(); 3 | var load = prefixedQmlLoader("QtQml/qml/Connections"); 4 | 5 | it("Connections default target is parent", function() { 6 | var qml = load("Connections", this.div); 7 | expect(qml.connections.target).toBe(qml); 8 | qml.value = 1; 9 | expect(qml.test_value).toBe(1); 10 | }); 11 | 12 | it("Connections target change", function() { 13 | var qml = load("Connections", this.div); 14 | qml.connections.target = qml.new_target; 15 | qml.new_target.value = 1; 16 | expect(qml.test_value).toBe(1); 17 | }); 18 | 19 | it("Connections null target", function() { 20 | var qml = load("Connections", this.div); 21 | qml.connections.target = null; 22 | qml.value = 1; 23 | expect(qml.test_value).toBe(0); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/modules/QtQuick/Behavior.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_Behavior extends QtQml_QtObject { 3 | static properties = { 4 | animation: "Animation", 5 | enabled: { type: "bool", initialValue: true } 6 | }; 7 | static defaultProperty = "animation"; 8 | 9 | constructor(meta) { 10 | super(meta); 11 | this.$on = meta.object.$on; 12 | 13 | this.animationChanged.connect(this, this.$onAnimationChanged); 14 | this.enabledChanged.connect(this, this.$onEnabledChanged); 15 | } 16 | $onAnimationChanged(newVal) { 17 | newVal.target = this.$parent; 18 | newVal.property = this.$on; 19 | this.$parent.$properties[this.$on].animation = newVal; 20 | } 21 | $onEnabledChanged(newVal) { 22 | this.$parent.$properties[this.$on].animation = newVal 23 | ? this.animation 24 | : null; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/Auto/Globals/tst_i18n.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtTest 1.0 3 | 4 | TestCase { 5 | name: "Internationalization" 6 | 7 | function test_qsTr() { 8 | compare("Foo", qsTr("Foo")) 9 | compare("Foo %n!", qsTr("Foo %n!")) 10 | compare("Foo 10!", qsTr("Foo %n!", "", 10)) 11 | compare("Foo 25!", qsTr("Foo %n!", "x", 25)) 12 | } 13 | function test_qsTrId() { 14 | compare("Foo", qsTrId("Foo")) 15 | compare("Foo %n!", qsTrId("Foo %n!")) 16 | compare("Foo 10!", qsTrId("Foo %n!", 10)) 17 | compare("Foo 25!", qsTrId("Foo %n!", 25)) 18 | } 19 | function test_qsTranslate() { 20 | compare("Foo", qsTranslate("Bar", "Foo")) 21 | compare("Foo %n!", qsTranslate("Bar", "Foo %n!")) 22 | compare("Foo 10!", qsTranslate("Bar", "Foo %n!", "", 10)) 23 | compare("Foo 25!", qsTranslate("Bar", "Foo %n!", "x", 25)) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/Render/Async/BorderImage.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | BorderImage { 4 | width: 20 5 | height: 20 6 | source: "bg.png" 7 | smooth: false 8 | border { left: 1; top: 3; right: 2; bottom: 3 } 9 | onStatusChanged: { 10 | if (typeof window !== 'undefined' && status !== BorderImage.Loading) { 11 | window.onTestLoad({ framesDelay: 2 }); 12 | } 13 | } 14 | 15 | // TODO: this is a hack to work-around PhantomJS not supporting pixelated 16 | // rendering for border-image. Once that would be fixed, thes rectangles 17 | // should be removed and the expected test result should be rebuilt 18 | Rectangle { 19 | x: 0 20 | y: 3 21 | height: 14 22 | width: parent.width 23 | color: "#000" 24 | } 25 | Rectangle { 26 | x: 1 27 | y: 0 28 | height: parent.width 29 | width: 17 30 | color: "#000" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/modules/QtQuick/PauseAnimation.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_PauseAnimation extends QtQuick_Animation { 3 | static properties = { 4 | duration: { type: "int", initialValue: 250 } 5 | }; 6 | 7 | constructor(meta) { 8 | super(meta); 9 | 10 | this.$at = 0; 11 | 12 | QmlWeb.engine.$addTicker((...args) => this.$ticker(...args)); 13 | this.runningChanged.connect(this, this.$onRunningChanged); 14 | } 15 | $ticker(now, elapsed) { 16 | if (!this.running || this.paused) { 17 | return; 18 | } 19 | this.$at += elapsed / this.duration; 20 | if (this.$at >= 1) { 21 | this.complete(); 22 | } 23 | } 24 | $onRunningChanged(newVal) { 25 | if (newVal) { 26 | this.$at = 0; 27 | this.paused = false; 28 | } 29 | } 30 | complete() { 31 | this.running = false; 32 | this.$Signals.finished(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/Auto/QtWebKit/tst_enums.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtTest 1.0 3 | import QtWebKit 3.0 4 | 5 | TestCase { 6 | WebView { } 7 | 8 | function test_enums_WebView() { 9 | const enums = { 10 | // ErrorDomain 11 | NoErrorDomain: 0, InternalErrorDomain: 1, NetworkErrorDomain: 2, 12 | HttpErrorDomain: 3, DownloadErrorDomain: 4, 13 | 14 | // LoadStatus 15 | LoadStartedStatus: 0, LoadSucceededStatus: 2, LoadFailedStatus: 3, 16 | 17 | // NavigationRequestAction 18 | AcceptRequest: 0, IgnoreRequest: 255, 19 | 20 | // NavigationType 21 | LinkClickedNavigation: 0, FormSubmittedNavigation: 1, 22 | BackForwardNavigation: 2, ReloadNavigation: 3, 23 | FormResubmittedNavigation: 4, OtherNavigation: 5 24 | }; 25 | 26 | Object.keys(enums).forEach(function(key) { 27 | compare(WebView[key], enums[key], key); 28 | }); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/PropertiesUrlDir/PropertiesUrlImport.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | property url localBindingSimple: "localBindingSimple.png" 5 | property url localBinding: "local" + "Binding.png" 6 | property url localSet 7 | property url remoteBindingSimple 8 | property url remoteBinding 9 | property url remoteSet 10 | Component.onCompleted: { 11 | localSet = "localSet.png" 12 | } 13 | /* These are required as they force some slots to run in this context when 14 | * things are done in PropertiesUrl. This tests that running slots in this 15 | * context doesn't have any unintended consequences. The "return" statements 16 | * are to ensure that slot handling continues after a return. */ 17 | onRemoteSetChanged: { 18 | return 19 | } 20 | onRemoteBindingSimpleChanged: { 21 | return 22 | } 23 | onRemoteBindingChanged: { 24 | return 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/modules/QtQuick.Window/Window.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_Window_Window extends QtQuick_Item { 3 | static versions = /^2\./; 4 | static properties = { 5 | active: "bool", 6 | activeFocusItem: "Item", 7 | color: { type: "color", initialValue: "#ffffff" }, 8 | //contentItem: "Item", // TODO 9 | contentOrientation: "enum", 10 | flags: "int", 11 | maximumHeight: "int", 12 | maximumWidth: "int", 13 | minimumHeight: "int", 14 | minimumWidth: "int", 15 | modality: "enum", 16 | title: "string", 17 | visibility: "enum" 18 | }; 19 | static signals = { 20 | closing: [{ type: "CloseEvent", name: "close" }] 21 | }; 22 | 23 | constructor(meta) { 24 | super(meta); 25 | 26 | this.colorChanged.connect(this, this.$onColorChanged); 27 | } 28 | $onColorChanged(newVal) { 29 | this.dom.style.backgroundColor = newVal.$css; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/QtTest/qml/TestCaseDatadriven.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtTest 1.0 3 | 4 | Item { 5 | TestCase { 6 | name: "Datadriven" 7 | 8 | function test_one_data() { 9 | return [ 10 | { tag: "2 + 2 = 4", a: 2, b: 2, c: 4 }, 11 | { tag: "2 + 6 = 8", a: 2, b: 6, c: 8 }, 12 | { tag: "2 + 7 = 8", a: 2, b: 7, c: 8 } 13 | ] 14 | } 15 | 16 | function test_one(data) { 17 | compare(data.a + data.b, data.c); 18 | } 19 | 20 | function init_data() { 21 | return [ 22 | { tag: "init_data_1", a_skip: false, b_fail: true }, 23 | { tag: "init_data_2", a_skip: true, b_skip: false } 24 | ]; 25 | } 26 | 27 | function test_a(data) { 28 | if (data.a_skip) { 29 | skip("Skipping"); 30 | } 31 | } 32 | 33 | function test_b(data) { 34 | if (data.b_fail) { 35 | fail(); 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/QtQuick/qml/RepeaterModelRole.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | property alias repeater: _repeater 5 | Repeater { 6 | id: _repeater 7 | model: ListModel { 8 | ListElement { 9 | role1: "foo" 10 | role2: 42 11 | } 12 | ListElement { 13 | role1: "bar" 14 | role2: 43 15 | } 16 | } 17 | Item { 18 | id: outer_item 19 | property var firstRole: model.role1 20 | property var secondRole: model.role2 21 | property alias firstRoleInner: inner_item.firstRole 22 | property alias secondRoleInner: inner_item.secondRole 23 | property string role1: "blah" 24 | Component.onCompleted: { 25 | console.log(outer_item.role1, role1, model.role1) 26 | } 27 | Item { 28 | id: inner_item 29 | property var firstRole: model.role1 30 | property var secondRole: model.role2 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /docs/JSItemModel.md: -------------------------------------------------------------------------------- 1 | # JSItemModel 2 | 3 | JSItemModel is a QAbstractItemModel like class that allows to create models 4 | from javascript, that can later be used from QML. 5 | 6 | ## To implement a model 7 | 8 | * Create a `JSItemModel` object and add `rowCount()` and `data()` functions to 9 | the object, 10 | * use `setRoleNames` to define `roleNames`, 11 | * emit `dataChanged`, `rowsInserted`, `rowsMoved`, `rowsRemoved` and 12 | `modelReset` as your internal data changes. 13 | 14 | ## Example 15 | 16 | ```js 17 | var data = [{ name: 'Ann', age: 23 }, 18 | { name: 'John', age: 38 }, 19 | { name: 'Gottlieb', age: 67 }]; 20 | var myModel = new JSItemModel(); 21 | 22 | myModel.data = function(index, role) { 23 | if (index > data.length) 24 | return undefined; 25 | return data[index][role]; 26 | } 27 | myModel.rowCount = function() { 28 | return data.length; 29 | } 30 | myModel.setRoleNames(['name', 'age']); 31 | ``` 32 | -------------------------------------------------------------------------------- /examples/customelement.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | QML Custom Element Example 5 | 7 | 8 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/modules/QtBluetooth/BluetoothDiscoveryModel.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtBluetooth_BluetoothDiscoveryModel extends QtQml_QtObject { 3 | static enums = { 4 | BluetoothDiscoveryModel: { 5 | FullServiceDiscovery: 1, MinimalServiceDiscovery: 0, DeviceDiscovery: 2, 6 | NoError: 0, InputOutputError: 1, PoweredOffError: 2, 7 | InvalidBluetoothAdapterError: 4, UnknownError: 3 8 | } 9 | }; 10 | static properties = { 11 | discoveryMode: { type: "enum", initialValue: 3 }, // MinimalServiceDiscovery 12 | error: { type: "enum", initialValue: 0 }, // NoError 13 | remoteAddress: "string", 14 | running: "bool", 15 | uuidFilter: "string", 16 | url: "url" 17 | }; 18 | static signals = { 19 | deviceDiscovered: [{ type: "string", name: "device" }], 20 | serviceDiscovered: [{ type: "string", name: "device" }] 21 | }; 22 | 23 | // TODO: implementation based on navigator.bluetooth 24 | } 25 | -------------------------------------------------------------------------------- /src/modules/QtQuick/Animation.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_Animation extends QtQml_QtObject { 3 | static enums = { 4 | Animation: { Infinite: -1 }, 5 | Easing: QmlWeb.Easing 6 | }; 7 | static properties = { 8 | alwaysRunToEnd: "bool", 9 | loops: { type: "int", initialValue: 1 }, 10 | paused: "bool", 11 | running: "bool" 12 | }; 13 | 14 | static signals = { 15 | finished: [], 16 | started: [], 17 | stopped: [] 18 | }; 19 | 20 | restart() { 21 | this.stop(); 22 | this.start(); 23 | } 24 | start() { 25 | this.running = true; 26 | this.$Signals.started(); 27 | } 28 | stop() { 29 | this.running = false; 30 | this.$Signals.stopped(); 31 | } 32 | pause() { 33 | this.paused = true; 34 | } 35 | resume() { 36 | this.paused = false; 37 | } 38 | complete() { 39 | // To be overridden 40 | console.log("Unbound method for", this); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/qtbase/JSItemModel.js: -------------------------------------------------------------------------------- 1 | class JSItemModel { 2 | constructor() { 3 | this.roleNames = []; 4 | 5 | const Signal = QmlWeb.Signal; 6 | this.dataChanged = Signal.signal([ 7 | { type: "int", name: "startIndex" }, 8 | { type: "int", name: "endIndex" } 9 | ]); 10 | this.rowsInserted = Signal.signal([ 11 | { type: "int", name: "startIndex" }, 12 | { type: "int", name: "endIndex" } 13 | ]); 14 | this.rowsMoved = Signal.signal([ 15 | { type: "int", name: "sourceStartIndex" }, 16 | { type: "int", name: "sourceEndIndex" }, 17 | { type: "int", name: "destinationIndex" } 18 | ]); 19 | this.rowsRemoved = Signal.signal([ 20 | { type: "int", name: "startIndex" }, 21 | { type: "int", name: "endIndex" } 22 | ]); 23 | this.modelReset = Signal.signal(); 24 | } 25 | 26 | setRoleNames(names) { 27 | this.roleNames = names; 28 | } 29 | } 30 | 31 | QmlWeb.JSItemModel = JSItemModel; 32 | -------------------------------------------------------------------------------- /src/modules/QtQuick/ShaderEffectSource.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_ShaderEffectSource extends QtQuick_Item { 3 | static enums = { 4 | ShaderEffectSource: { 5 | Alpha: 0x6406, RGB: 0x6407, RGBA: 0x6408, 6 | NoMirroring: 0, MirrorHorizontally: 1, MirrorVertically: 2, 7 | ClampToEdge: 0, RepeatHorizontally: 1, RepeatVertically: 2, Repeat: 3 8 | } 9 | }; 10 | static properties = { 11 | format: { type: "enum", initialValue: 0x6408 }, // ShaderEffectSource.RGBA 12 | hideSource: "bool", 13 | live: { type: "bool", initialValue: true }, 14 | mipmap: "bool", 15 | recursive: "bool", 16 | sourceItem: "Item", 17 | sourceRect: "rect", 18 | textureMirroring: { type: "enum", initialValue: 2 }, // MirrorVertically 19 | textureSize: "size", 20 | wrapMode: "enum" // ShaderEffectSource.ClampToEdge 21 | }; 22 | 23 | // TODO 24 | 25 | scheduleUpdate() { 26 | // TODO 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/qtbase/QPointF.js: -------------------------------------------------------------------------------- 1 | class QPointF extends QmlWeb.QObject { 2 | constructor(...args) { 3 | super(); 4 | let data = args; 5 | if (args.length === 0) { 6 | data = [0, 0]; 7 | } else if (args.length === 1 && typeof args[0] === "string") { 8 | data = args[0].split(",").map(x => parseFloat(x.trim())); 9 | if (data.length !== 2) throw new Error("point expected"); 10 | } else if (args.length === 1 && args[0] instanceof QPointF) { 11 | data = [args[0].x, args[0].y]; 12 | } else if (args.length !== 2) { 13 | throw new Error("Invalid arguments"); 14 | } 15 | QmlWeb.createProperties(this, { 16 | x: { type: "real", initialValue: data[0] }, 17 | y: { type: "real", initialValue: data[1] } 18 | }); 19 | } 20 | toString() { 21 | return super.$toString(this.x, this.y); 22 | } 23 | 24 | static nonNullableType = true; 25 | static requireConstructor = true; 26 | } 27 | 28 | QmlWeb.QPointF = QPointF; 29 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ImportLocalComponentAsPropertyInAnotherDir.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | /* The issue that can arise is that LocalComponentProperty ends up with the 3 | * same importContextId as this file, so we import "ImportFrom" qualified, so 4 | * that a plain "ImportMe" in LocalComponentProperty will fail if it ends up 5 | * within this file's context. */ 6 | import "ImportFrom" as ImportFrom 7 | 8 | Item { 9 | property int value: local_component_property.count ? local_component_property.itemAt(0).value : 0 10 | ImportFrom.LocalComponentProperty { 11 | id: local_component_property 12 | /* Required to set model here, instead of within Repeater, as it causes the 13 | * Repeater's delegate to get created in this file's context, instead of 14 | * LocalComponentProperty's context. So if the delegate doesn't have an 15 | * importContextId set, it will default to this file's, which is incorrect. 16 | * */ 17 | model: 1 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/QtQuick/Rectangle.js: -------------------------------------------------------------------------------- 1 | describe("QtQuick.Rectangle", function() { 2 | setupDivElement(); 3 | var load = prefixedQmlLoader("QtQuick/qml/Rectangle"); 4 | 5 | it("White", function() { 6 | load("White", this.div); 7 | var div = this.div.children[0]; 8 | expect(div.children[0].innerHTML).toBe(""); 9 | expect(div.children[0].style.backgroundColor).toBe("rgb(255, 255, 255)"); 10 | expect(div.offsetWidth).toBe(200); 11 | expect(div.offsetHeight).toBe(100); 12 | expect(div.clientWidth).toBe(200); 13 | expect(div.clientHeight).toBe(100); 14 | }); 15 | it("Color", function() { 16 | load("Color", this.div); 17 | var div = this.div.children[0]; 18 | expect(div.children[0].style.backgroundColor).toBe("rgb(255, 0, 0)"); 19 | }); 20 | it("Transparent", function() { 21 | load("Transparent", this.div); 22 | var div = this.div.children[0]; 23 | expect(div.children[0].style.backgroundColor).toBe("transparent"); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /tests/Render/Simple/AnchorChains.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Rectangle { 4 | color: "white" 5 | width: 16 6 | height: 16 7 | 8 | Rectangle { 9 | id: bl 10 | color: "orange" 11 | width: 8 12 | height: 8 13 | anchors { 14 | left: parent.left 15 | bottom: parent.bottom 16 | } 17 | } 18 | Rectangle { 19 | id: tl 20 | color: "green" 21 | anchors { 22 | left: parent.left 23 | top: parent.top 24 | bottom: bl.top 25 | right: tr.left 26 | } 27 | } 28 | Rectangle { 29 | id: tr 30 | color: "cyan" 31 | width: 6 32 | anchors { 33 | right: parent.right 34 | top: parent.top 35 | bottom: br.top 36 | bottomMargin: 2 37 | } 38 | } 39 | Rectangle { 40 | id: br 41 | color: "red" 42 | height: 6 43 | anchors { 44 | right: parent.right 45 | bottom: parent.bottom 46 | left: bl.right 47 | margins: 2 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/qtbase/QSizeF.js: -------------------------------------------------------------------------------- 1 | class QSizeF extends QmlWeb.QObject { 2 | constructor(...args) { 3 | super(); 4 | let data = args; 5 | if (args.length === 0) { 6 | data = [-1, -1]; 7 | } else if (args.length === 1 && typeof args[0] === "string") { 8 | data = args[0].split("x").map(x => parseFloat(x.trim())); 9 | if (data.length !== 2) throw new Error("size expected"); 10 | } else if (args.length === 1 && args[0] instanceof QSizeF) { 11 | data = [args[0].width, args[0].height]; 12 | } else if (args.length !== 2) { 13 | throw new Error("Invalid arguments"); 14 | } 15 | QmlWeb.createProperties(this, { 16 | width: { type: "real", initialValue: data[0] }, 17 | height: { type: "real", initialValue: data[1] } 18 | }); 19 | } 20 | toString() { 21 | return super.$toString(this.width, this.height); 22 | } 23 | 24 | static nonNullableType = true; 25 | static requireConstructor = true; 26 | } 27 | 28 | QmlWeb.QSizeF = QSizeF; 29 | -------------------------------------------------------------------------------- /src/modules/QtQuick/Positioner.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_Positioner extends QtQuick_Item { 3 | static properties = { 4 | spacing: "int", 5 | padding: "int" 6 | }; 7 | 8 | constructor(meta) { 9 | super(meta); 10 | 11 | this.childrenChanged.connect(this, this.$onChildrenChanged); 12 | this.spacingChanged.connect(this, this.layoutChildren); 13 | this.childrenChanged.connect(this, this.layoutChildren); 14 | this.layoutChildren(); 15 | } 16 | $onChildrenChanged() { 17 | const flags = QmlWeb.Signal.UniqueConnection; 18 | for (let i = 0; i < this.children.length; i++) { 19 | const child = this.children[i]; 20 | child.widthChanged.connect(this, this.layoutChildren, flags); 21 | child.heightChanged.connect(this, this.layoutChildren, flags); 22 | child.visibleChanged.connect(this, this.layoutChildren, flags); 23 | } 24 | } 25 | layoutChildren() { 26 | // noop, defined in individual positioners 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # Authors ordered by first contribution. 2 | 3 | Lauri Paimen 4 | Anton Kreuzkamp 5 | Jan Gerrit José Marker 6 | Somsubhra Bairi 7 | Сковорода Никита Андреевич 8 | Joshua Kolden 9 | Michael Martin Moro 10 | Sam Segers 11 | Arno Pähler 12 | Henrik Rudstrøm 13 | Edwin Marshall 14 | Pavel Vasev 15 | Igor Andruszkiewicz 16 | Harsh Choudhary 17 | Alexander Potashev 18 | Stephen D'Angelo 19 | Heikki Haveri 20 | Alexander Rössler 21 | Gaubee 22 | Alexey Andreyev 23 | Yauhen Kotau 24 | Wian van Aggelen 25 | -------------------------------------------------------------------------------- /src/engine/i18n.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-vars */ 2 | 3 | function formatString(sourceText, n) { 4 | let text = sourceText; 5 | if (typeof n !== "undefined") { 6 | if (typeof n !== "number") { 7 | throw new Error("(n) must be a number"); 8 | } 9 | text = text.replace(/%n/, n.toString(10)); 10 | } 11 | return text; 12 | } 13 | 14 | QmlWeb.qsTr = function(sourceText, disambiguation, n) { 15 | return formatString(sourceText, n); 16 | }; 17 | 18 | QmlWeb.qsTrId = function(id, n) { 19 | return formatString(id, n); 20 | }; 21 | 22 | QmlWeb.qsTranslate = function(context, sourceText, disambiguation, n) { 23 | return formatString(sourceText, n); 24 | }; 25 | 26 | // Somewhy these are documented, but not defined in Qt QML 5.10 27 | /* 28 | QmlWeb.qsTrIdNoOp = function(id) { 29 | return id; 30 | }; 31 | 32 | QmlWeb.qsTrNoOp = function(sourceText, disambiguation) { 33 | return sourceText; 34 | }; 35 | 36 | QmlWeb.qsTranslateNoOp = function(context, sourceText, disambiguation) { 37 | return sourceText; 38 | }; 39 | */ 40 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/JavascriptBasicSyntax.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | //this is a line comment 5 | /* 6 | this is a block comment 7 | */ 8 | function ifstatements(arg) { 9 | const b = 10; 10 | var foo = 0; 11 | if (arg == 0) 12 | foo = 1; 13 | else if (arg == 1) 14 | foo = 2 * 2; 15 | else 16 | foo = 2; 17 | return foo; 18 | } 19 | 20 | function trycatch() { 21 | try { 22 | throw new Error(); 23 | } catch(e) { 24 | console.log(e); 25 | } finally { 26 | return 1; 27 | } 28 | } 29 | 30 | function foreach() { 31 | for (var i = 0; i < 5; i++) { 32 | continue; 33 | } 34 | var a = [1, 2, 3]; 35 | for (var k in a) { 36 | break; 37 | } 38 | } 39 | 40 | function switchcase(arg) { 41 | var a = 0 42 | switch (arg) { 43 | case 1: 44 | a = 1; 45 | break; 46 | case "32": 47 | a = "hm"; 48 | break; 49 | default: 50 | a = undefined; 51 | } 52 | return a; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /docs/Signal.md: -------------------------------------------------------------------------------- 1 | # Signal 2 | 3 | ## new Signal(\[params\[, options\]\]) 4 | 5 | * `params` {Array} Parameters of the signal. Defaults to `[]`. 6 | * `options` {Object} Options that allow finetuning of the signal. 7 | 8 | Returns a new Signal object with parameters specified in `params`. 9 | 10 | Each element of the `params` array has to be an object with the two properties: 11 | `type` and `name` specifying the datatype of the parameter and its name. 12 | The type is currently ignored. 13 | 14 | ## signal.execute(...args) 15 | 16 | Executes the signal. 17 | 18 | ## signal.connect(...args) 19 | 20 | ## signal.disconnect(...args) 21 | 22 | ## signal.isConnected(...args) 23 | 24 | ## signal.signal 25 | 26 | Returns a function that runs `signal.execute(...args)` when called and has 27 | `connect`, `disconnect` and `isConnected` properties that call corresponding 28 | methods from the `signal`. 29 | 30 | ## Class Method: Signal.signal(\[params\[, options\]\]) 31 | 32 | Constructs a `Signal` instance with the given `params` and `options` and returns 33 | its `.signal` property. 34 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/PropertiesUrl.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import "PropertiesUrlDir" 3 | 4 | Item { 5 | property alias localBindingSimple: properties_url_import.localBindingSimple 6 | property alias localBinding: properties_url_import.localBinding 7 | property alias localSet: properties_url_import.localSet 8 | property alias remoteBindingSimple: properties_url_import.remoteBindingSimple 9 | property alias remoteBinding: properties_url_import.remoteBinding 10 | property alias remoteSet: properties_url_import.remoteSet 11 | property url http: "http://http-url" 12 | property url aboutBlank: "about:blank" 13 | property url absolute: "/absolute-url" 14 | property url unset 15 | property url setToEmptyString: "will-be-empty-string" 16 | Component.onCompleted: { 17 | setToEmptyString = "" 18 | } 19 | PropertiesUrlImport { 20 | id: properties_url_import 21 | remoteBindingSimple: "remoteBindingSimple.png" 22 | remoteBinding: "remote" + "Binding.png" 23 | Component.onCompleted: { 24 | properties_url_import.remoteSet = "remoteSet.png" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/QtQuick/Shortcut.js: -------------------------------------------------------------------------------- 1 | describe("QtQuick.Shortcut", function() { 2 | setupDivElement(); 3 | var load = prefixedQmlLoader("QtQuick/qml/Shortcut"); 4 | 5 | // Works in live version. Doesn't work here. 6 | // The modifiers on the shortcut item is set to zero by 7 | // something. 8 | xit("Sequence", function() { 9 | var qml = load("Sequence", this.div); 10 | var called = 0; 11 | var event = { 12 | key: QmlWeb.Qt.Key_P, 13 | modifiers: QmlWeb.Qt.ControlModifer | QmlWeb.Qt.AltModifer 14 | }; 15 | 16 | expect(qml.sequences[0].$text).toBe("Ctrl+Alt+P"); 17 | expect(qml.sequences[0].$sequences.length).toBe(1); 18 | expect(qml.sequences[0].$sequences[0].key) 19 | .toBe(QmlWeb.Qt.Key_P); 20 | expect(qml.sequences[0].$sequences[0].modifiers) 21 | .toBe(QmlWeb.Qt.ControlModifer | QmlWeb.Qt.AltModifer); 22 | expect( 23 | qml.sequences[0].$match(event) 24 | ).toBe(true); 25 | qml.activated.connect(this, () => { 26 | called++; 27 | }); 28 | qml.Keys.pressed(event); 29 | expect(called).toBe(1); 30 | }); 31 | }); 32 | 33 | -------------------------------------------------------------------------------- /src/qtbase/QQuaternion.js: -------------------------------------------------------------------------------- 1 | class QQuaternion extends QmlWeb.QObject { 2 | constructor(...args) { 3 | super(); 4 | let data = args; 5 | if (args.length === 1 && typeof args[0] === "string") { 6 | data = args[0].split(",").map(x => parseFloat(x.trim())); 7 | if (data.length !== 4) data = []; 8 | } else if (args.length === 1 && args[0] instanceof QQuaternion) { 9 | data = [args[0].scalar, args[0].x, args[0].y, args[0].z]; 10 | } 11 | if (data.length === 0) { 12 | data = [1, 0, 0, 0]; 13 | } else if (data.length !== 4) { 14 | throw new Error("Invalid arguments"); 15 | } 16 | QmlWeb.createProperties(this, { 17 | scalar: { type: "real", initialValue: data[0] }, 18 | x: { type: "real", initialValue: data[1] }, 19 | y: { type: "real", initialValue: data[2] }, 20 | z: { type: "real", initialValue: data[3] } 21 | }); 22 | } 23 | toString() { 24 | return super.$toString(this.scalar, this.x, this.y, this.z); 25 | } 26 | 27 | static nonNullableType = true; 28 | static requireConstructor = true; 29 | } 30 | 31 | QmlWeb.QQuaternion = QQuaternion; 32 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/PropertiesUrlDir/PropertiesUrlImportWithExceptions.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | property url localBindingSimple: "localBindingSimple.png" 5 | property url localBinding: "local" + "Binding.png" 6 | property url localSet 7 | property url remoteBindingSimple 8 | property url remoteBinding 9 | property url remoteSet 10 | Component.onCompleted: { 11 | localSet = "localSet.png" 12 | } 13 | /* These are required as they force some slots to run in this context when 14 | * things are done in PropertiesUrlExceptionSafe. This tests that running 15 | * slots that throw an exception in this context doesn't have any unintended 16 | * consequences. */ 17 | onLocalSetChanged: { 18 | throw "Some Exception" 19 | } 20 | onLocalBindingSimpleChanged: { 21 | throw "Some Exception" 22 | } 23 | onLocalBindingChanged: { 24 | throw "Some Exception" 25 | } 26 | onRemoteSetChanged: { 27 | throw "Some Exception" 28 | } 29 | onRemoteBindingSimpleChanged: { 30 | throw "Some Exception" 31 | } 32 | onRemoteBindingChanged: { 33 | throw "Some Exception" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/modules/QtWebKit/WebView.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtWebKit_WebView extends QtWebView_WebView { 3 | static versions = /^3\./; 4 | static enums = { 5 | WebView: { 6 | // ErrorDomain 7 | NoErrorDomain: 0, InternalErrorDomain: 1, NetworkErrorDomain: 2, 8 | HttpErrorDomain: 3, DownloadErrorDomain: 4, 9 | 10 | // LoadStatus 11 | LoadStartedStatus: 0, LoadSucceededStatus: 2, LoadFailedStatus: 3, 12 | 13 | // NavigationRequestAction 14 | AcceptRequest: 0, IgnoreRequest: 255, 15 | 16 | // NavigationType 17 | LinkClickedNavigation: 0, FormSubmittedNavigation: 1, 18 | BackForwardNavigation: 2, ReloadNavigation: 3, 19 | FormResubmittedNavigation: 4, OtherNavigation: 5 20 | } 21 | }; 22 | static properties = { 23 | icon: "url" 24 | }; 25 | static signals = { 26 | navigationRequested: [ 27 | { type: "var", name: "request" } 28 | ], 29 | linkHovered: [ 30 | { type: "url", name: "hoveredUrl" }, 31 | { type: "string", name: "hoveredTitle" } 32 | ] 33 | }; 34 | 35 | // TODO: implement more features on top of WebView 36 | } 37 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/ScopeRepeater.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | /* A Flow is used because it will check the width of a new child that is added 4 | * to it (e.g. "new_item" below). This will happen when the Repeater creates a 5 | * new instance of "new_item" and then parents it to the Flow. If this happens 6 | * before the model's "the_width" role has been inserted into the scope of 7 | * "new_item", it will incorrectly resolve to "root.the_width" */ 8 | Flow { 9 | id: root 10 | 11 | Timer { 12 | interval: 1 13 | running: true 14 | onTriggered: { 15 | /* This needs to happen in a Timer, so that it is not with a 16 | * $createObject call that sets QmlWeb.engine.operationState = 17 | * QMLOperationState.Init */ 18 | list_model.append({"the_width" : 200}) 19 | root.yield(repeater.itemAt(0).width) 20 | } 21 | } 22 | 23 | // We shouldn't access this variable 24 | property int the_width: 100 25 | 26 | Repeater { 27 | id: repeater 28 | model: ListModel { 29 | id: list_model 30 | } 31 | Item { 32 | id: new_item 33 | height: 100 34 | width: the_width 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/modules/QtMobility/GeoLocation.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtMobility_GeoLocation extends QtQuick_Item { 3 | static properties = { 4 | accuracy: "double", 5 | altitude: "double", 6 | altitudeAccuracy: "double", 7 | heading: "double", 8 | latitude: "double", 9 | longitude: "double", 10 | speed: "double", 11 | timestamp: "date", 12 | label: "string" 13 | }; 14 | 15 | constructor(meta) { 16 | super(meta); 17 | 18 | if (!navigator.geolocation) { 19 | return; 20 | } 21 | 22 | navigator.geolocation.getCurrentPosition(pos => this.$updatePosition(pos)); 23 | navigator.geolocation.watchPosition(pos => this.$updatePosition(pos)); 24 | } 25 | $updatePosition(position) { 26 | this.accuracy = position.coords.accuracy; 27 | this.altitude = position.coords.altitude; 28 | this.altitudeAccuracy = position.coords.altitudeAccuracy; 29 | this.heading = position.coords.heading; 30 | this.latitude = position.coords.latitude; 31 | this.longitude = position.coords.longitude; 32 | this.speed = position.coords.speed; 33 | this.timestamp = position.timestamp; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/Qt.labs.settings/Settings.js: -------------------------------------------------------------------------------- 1 | describe("Qt.labs.settings.Settings", function() { 2 | setupDivElement(); 3 | var load = prefixedQmlLoader("Qt.labs.settings/qml/Settings"); 4 | 5 | it("Set plain", function() { 6 | var qml = load("Plain", this.div); 7 | qml.a = 100; 8 | qml.b = "foo"; 9 | expect(qml.a).toBe(100); 10 | expect(qml.b).toBe("foo"); 11 | qml.a = 20; 12 | qml.b = "bar"; 13 | expect(qml.a).toBe(20); 14 | expect(qml.b).toBe("bar"); 15 | }); 16 | 17 | it("Get plain", function() { 18 | var qml = load("Plain", this.div); 19 | expect(qml.a).toBe(20); 20 | expect(qml.b).toBe("bar"); 21 | }); 22 | 23 | it("Set alias", function() { 24 | var qml = load("Alias", this.div); 25 | qml.width = 100; 26 | qml.height = 100; 27 | expect(qml.width).toBe(100); 28 | expect(qml.height).toBe(100); 29 | qml.width = 20; 30 | qml.height = 30; 31 | expect(qml.width).toBe(20); 32 | expect(qml.height).toBe(30); 33 | }); 34 | 35 | it("Get alias", function() { 36 | var qml = load("Alias", this.div); 37 | expect(qml.width).toBe(20); 38 | expect(qml.height).toBe(30); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /src/modules/QtMultimedia/Camera.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtMultimedia_Camera extends QtQml_QtObject { 3 | static versions = /^5\./; 4 | static enums = { 5 | Camera: { 6 | Available: 0, Busy: 2, Unavailable: 1, ResourceMissing: 3, 7 | 8 | UnloadedState: 0, LoadedState: 1, ActiveState: 2 9 | } 10 | }; 11 | static properties = { 12 | availability: "enum", // Camera.Available 13 | cameraState: { type: "enum", initialValue: 2 }, // Camera.ActiveState 14 | cameraStatus: "enum", // TODO 15 | captureMode: "enum", // TODO 16 | deviceId: "string", 17 | digitalZoom: { type: "real", initialValue: 1 }, 18 | displayName: "string", 19 | errorCode: "enum", // TODO 20 | errorString: "string", 21 | lockStatus: "enum", // TODO 22 | maximumDigitalZoom: "real", 23 | maximumOpticalZoom: "real", 24 | opticalZoom: { type: "real", initialValue: 1 }, 25 | orientation: "int", 26 | position: "enum", // TODO 27 | }; 28 | static signals = { 29 | error: [ 30 | { type: "enum", name: "errorCode" }, 31 | { type: "string", name: "errorString" } 32 | ] 33 | }; 34 | 35 | // TODO: impl 36 | } 37 | -------------------------------------------------------------------------------- /src/modules/QtQuick.Particles/Emitter.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_Particles_Emitter extends QtQuick_Item { 3 | static versions = /^2\./; 4 | static properties = { 5 | acceleration: "StochasticDirection", 6 | emitRate: { type: "real", initialValue: 10 }, 7 | enabled: { type: "bool", initialValue: true }, 8 | endSize: { type: "real", initialValue: -1 }, 9 | group: "string", 10 | lifeSpan: { type: "int", initialValue: 1000 }, 11 | lifeSpanVariation: "int", 12 | maximumEmitted: { type: "int", initialValue: -1 }, 13 | shape: "Shape", 14 | size: { type: "real", initialValue: 16 }, 15 | sizeVariation: "real", 16 | startTime: "int", 17 | system: "ParticleSystem", 18 | velocity: "StochasticDirection", 19 | velocityFromMovement: "real" 20 | }; 21 | static signals = { 22 | emitParticles: [{ type: "Array", name: "particles" }] 23 | }; 24 | 25 | // TODO 26 | 27 | burst(/*count, x, y*/) { 28 | // TODO 29 | } 30 | pulse(duration) { 31 | if (this.enabled) return; 32 | this.enabled = true; 33 | setTimeout(() => { 34 | this.enabled = false; 35 | }, duration); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/modules/QtQuick/Scale.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_Scale extends QtQml_QtObject { 3 | static properties = { 4 | xScale: { type: "real", initialValue: 1 }, 5 | yScale: { type: "real", initialValue: 1 } 6 | }; 7 | 8 | constructor(meta) { 9 | super(meta); 10 | 11 | this.origin = new QmlWeb.QObject(this); 12 | QmlWeb.createProperties(this.origin, { 13 | x: "real", 14 | y: "real" 15 | }); 16 | 17 | this.xScaleChanged.connect(this.$parent, this.$parent.$updateTransform); 18 | this.yScaleChanged.connect(this.$parent, this.$parent.$updateTransform); 19 | this.origin.xChanged.connect(this, this.$updateOrigin); 20 | this.origin.yChanged.connect(this, this.$updateOrigin); 21 | 22 | /* QML default origin is top-left, while CSS default origin is centre, so 23 | * $updateOrigin must be called to set the initial transformOrigin. */ 24 | this.$updateOrigin(); 25 | } 26 | $updateOrigin() { 27 | const style = this.$parent.dom.style; 28 | style.transformOrigin = `${this.origin.x}px ${this.origin.y}px`; 29 | style.webkitTransformOrigin = `${this.origin.x}px ${this.origin.y}px`; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/modules/QtQuick/State.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_State extends QtQml_QtObject { 3 | static properties = { 4 | name: "string", 5 | changes: "list", 6 | extend: "string", 7 | when: "bool" 8 | }; 9 | static defaultProperty = "changes"; 10 | 11 | constructor(meta) { 12 | super(meta); 13 | 14 | this.$item = this.$parent; 15 | 16 | this.whenChanged.connect(this, this.$onWhenChanged); 17 | } 18 | $getAllChanges() { 19 | if (this.extend) { 20 | /* ECMAScript 2015. TODO: polyfill Array? 21 | const base = this.$item.states.find(state => state.name === this.extend); 22 | */ 23 | const states = this.$item.states; 24 | const base = states.filter(state => state.name === this.extend)[0]; 25 | if (base) { 26 | return base.$getAllChanges().concat(this.changes); 27 | } 28 | console.error("Can't find the state to extend!"); 29 | } 30 | return this.changes; 31 | } 32 | $onWhenChanged(newVal) { 33 | if (newVal) { 34 | this.$item.state = this.name; 35 | } else if (this.$item.state === this.name) { 36 | this.$item.state = ""; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/QMLEngine/parse.js: -------------------------------------------------------------------------------- 1 | describe("QMLEngine.parse", function() { 2 | setupDivElement(); 3 | var load = prefixedQmlLoader("QMLEngine/qml/Parse"); 4 | 5 | it("should throw error with line number and code extract", function() { 6 | var exception = null; 7 | try { 8 | load("Error", this.div); 9 | } catch (e) { 10 | exception = e; 11 | } 12 | expect(exception).not.toBe(null); 13 | expect(exception.message).toContain("properly int error:"); 14 | expect(exception.message).toContain("Unexpected token name"); 15 | expect(exception.message).toContain("line: 4"); 16 | expect(exception.line).toBe(4); 17 | }); 18 | 19 | it("can parse a function assigned to a var property", function() { 20 | var qml = load("FunctionVar", this.div); 21 | expect(typeof qml.aFunction).toBe("function"); 22 | }); 23 | 24 | it("can define signals from a QML component", function() { 25 | var qml = load("Signal", this.div); 26 | expect(qml.simpleSignal).not.toBe(undefined); 27 | expect(qml.signalWithParams).not.toBe(undefined); 28 | expect(typeof qml.simpleSignal.connect).toBe("function"); 29 | expect(typeof qml.signalWithParams.connect).toBe("function"); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /src/modules/QtQuick/Gradient.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_Gradient extends QtQml_QtObject { 3 | static enums = { 4 | Orientation: { 5 | Vertical: 0, Horizontal: 1 6 | } 7 | }; 8 | static properties = { 9 | orientation: { type: "enum", initialValue: 0 }, // Gradient.Orientation 10 | stops: "list" 11 | }; 12 | static defaultProperty = "stops"; 13 | 14 | constructor(meta) { 15 | super(meta); 16 | 17 | this.$item = this.$parent; 18 | 19 | this.orientationChanged.connect(this, this.$onGradientStopChanged); 20 | this.stopsChanged.connect(this, this.$onGradientStopChanged); 21 | } 22 | $onGradientStopChanged() { 23 | const style = this.$parent.impl.style; 24 | let linearGradient = ""; 25 | for (let i = 0; i < this.stops.length; i++) { 26 | const stop = this.stops[i]; 27 | linearGradient += `,${stop.color} ${stop.position * 100}%`; 28 | } 29 | if (this.stops.length > 0) { 30 | style.backgroundColor = "transparent"; 31 | 32 | const direction = this.orientation === this.Orientation.Vertical 33 | ? "to bottom" : "to right"; 34 | style.backgroundImage = `linear-gradient(${direction}${linearGradient})`; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/modules/QtQml/Binding.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQml_Binding extends QtQml_QtObject { 3 | static properties = { 4 | target: { type: "QtObject", initialValue: null }, 5 | property: { type: "string", initialValue: "" }, 6 | value: { type: "var", initialValue: undefined }, 7 | when: { type: "bool", initialValue: true } 8 | }; 9 | 10 | constructor(meta) { 11 | super(meta); 12 | 13 | this.$property = undefined; 14 | 15 | this.valueChanged.connect(this, this.$onValueChanged); 16 | this.targetChanged.connect(this, this.$updateBinding); 17 | this.propertyChanged.connect(this, this.$updateBinding); 18 | this.whenChanged.connect(this, this.$updateBinding); 19 | } 20 | 21 | $updateBinding() { 22 | if (!this.when || !this.target 23 | || !this.target.hasOwnProperty(this.property) 24 | || this.value === undefined) { 25 | this.$property = undefined; 26 | return; 27 | } 28 | this.$property = this.target.$properties[this.property]; 29 | this.$onValueChanged(this.value); // trigger value update 30 | } 31 | 32 | $onValueChanged(value) { 33 | if (value !== undefined && this.$property) { 34 | this.$property.set(value); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/BasicSignalDisconnect.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | id: mainitem 5 | 6 | signal sig1(); 7 | 8 | property string log: "" 9 | Text { 10 | text: log 11 | } 12 | 13 | Item { 14 | id: item1 15 | function foo() { 16 | console.log("Item 1 got signal"); 17 | mainitem.log = mainitem.log + "1"; 18 | mainitem.sig1.disconnect( item1, item1.foo ); 19 | } 20 | } 21 | 22 | Item { 23 | id: item2 24 | function foo() { 25 | console.log("Item 2 got signal"); 26 | mainitem.log = mainitem.log + "2"; 27 | } 28 | } 29 | 30 | Component.onCompleted: { 31 | mainitem.sig1.connect( item1, item1.foo ); 32 | mainitem.sig1.connect( item2, item2.foo ); 33 | mainitem.log = mainitem.log + "i"; 34 | sig1(); 35 | mainitem.log = mainitem.log + "i"; 36 | sig1(); 37 | } 38 | 39 | /* Expected behaviour (works well in qmlscene.exe Qt 5.3): 40 | sig1 => (item1.foo + disconnect item1.foo) + item2.foo 41 | sig1 => item2.foo 42 | e.g. log = "i12i2" 43 | 44 | Current qmlweb behaviour: 45 | sig1 => (item1.foo + disconnect item1.foo) + missing call to item2.foo 46 | sig1 => item2.foo 47 | e.g. log = "i1i2" 48 | */ 49 | } 50 | -------------------------------------------------------------------------------- /src/modules/QtQuick.Controls.2/Container.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_Controls_2_Container extends QtQuick_Controls_2_Control { 3 | static versions = /^2\./; 4 | static properties = { 5 | contentChildren: "list", 6 | contentData: "list", 7 | contentModel: "model", 8 | count: "int", 9 | currentIndex: "int", 10 | currentItem: "Item" 11 | }; 12 | 13 | constructor(meta) { 14 | super(meta); 15 | 16 | this.widthChanged.connect(this, this.layoutChildren); 17 | this.heightChanged.connect(this, this.layoutChildren); 18 | this.childrenChanged.connect(this, this.layoutChildren); 19 | this.childrenChanged.connect(this, this.$onChildrenChanged); 20 | this.layoutChildren(); 21 | } 22 | $onChildrenChanged() { 23 | const flags = QmlWeb.Signal.UniqueConnection; 24 | for (let i = 0; i < this.children.length; i++) { 25 | const child = this.children[i]; 26 | child.widthChanged.connect(this, this.layoutChildren, flags); 27 | child.heightChanged.connect(this, this.layoutChildren, flags); 28 | child.visibleChanged.connect(this, this.layoutChildren, flags); 29 | } 30 | } 31 | layoutChildren() { 32 | // noop, defined in individual positioners 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/qtbase/QRectF.js: -------------------------------------------------------------------------------- 1 | class QRectF extends QmlWeb.QObject { 2 | constructor(...args) { 3 | super(); 4 | let data = args; 5 | if (args.length === 0) { 6 | data = [0, 0, 0, 0]; 7 | } else if (args.length === 1 && typeof args[0] === "string") { 8 | const mask = /^\s*[-\d.]+\s*,\s*[-\d.]+\s*,\s*[-\d.]+\s*x\s*[-\d.]+\s*$/; 9 | if (!args[0].match(mask)) throw new Error("rect expected"); 10 | data = args[0].replace("x", ",").split(",") 11 | .map(x => parseFloat(x.trim())); 12 | } else if (args.length === 1 && args[0] instanceof QRectF) { 13 | data = [args[0].x, args[0].y, args[0].z, args[0].width]; 14 | } else if (args.length !== 4) { 15 | throw new Error("Invalid arguments"); 16 | } 17 | QmlWeb.createProperties(this, { 18 | x: { type: "real", initialValue: data[0] }, 19 | y: { type: "real", initialValue: data[1] }, 20 | width: { type: "real", initialValue: data[2] }, 21 | height: { type: "real", initialValue: data[3] } 22 | }); 23 | } 24 | toString() { 25 | return super.$toString(this.x, this.y, this.width, this.height); 26 | } 27 | 28 | static nonNullableType = true; 29 | static requireConstructor = true; 30 | } 31 | 32 | QmlWeb.QRectF = QRectF; 33 | -------------------------------------------------------------------------------- /tests/Render/Simple/RectangleBorder.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.5 2 | 3 | Rectangle { 4 | width: 75 5 | height: 21 6 | color: 'green' 7 | 8 | Rectangle { 9 | width: 5 10 | height: 10 11 | } 12 | Rectangle { 13 | width: 11 14 | height: 10 15 | x: 15 16 | border.color: "#27c1cf" 17 | } 18 | Rectangle { 19 | width: 10 20 | height: 10 21 | x: 30 22 | border.width: 2 23 | } 24 | Rectangle { 25 | x: 45 26 | color: 'orange' 27 | border.width: 1 28 | } 29 | Rectangle { 30 | x: 60 31 | border.width: 0 32 | border.color: 'red' 33 | width: 10 34 | height: 10 35 | } 36 | Rectangle { 37 | x: 0 38 | y: 11 39 | border.width: 20 40 | border.color: 'red' 41 | width: 10 42 | height: 10 43 | } 44 | Rectangle { 45 | x: 15 46 | y: 11 47 | border.width: -20 48 | border.color: 'pink' 49 | width: 10 50 | height: 10 51 | } 52 | Rectangle { 53 | x: 30 54 | y: 11 55 | border.width: 3 56 | border.color: 'red' 57 | width: -10 58 | height: 10 59 | } 60 | Rectangle { 61 | x: 45 62 | y: 11 63 | color: 'red' 64 | border.width: 3 65 | border.color: 'transparent' 66 | width: 10 67 | height: 10 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/modules/QtQuick.Controls/Button.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_Controls_Button extends QtQuick_Item { 3 | static properties = { 4 | text: "string", 5 | enabled: { type: "bool", initialValue: true } 6 | }; 7 | static signals = { 8 | clicked: [] 9 | }; 10 | 11 | constructor(meta) { 12 | super(meta); 13 | 14 | this.Component.completed.connect(this, this.Component$onCompleted); 15 | this.textChanged.connect(this, this.$onTextChanged); 16 | this.enabledChanged.connect(this, this.$onEnabledChanged); 17 | 18 | const button = this.impl = document.createElement("button"); 19 | button.style.pointerEvents = "auto"; 20 | this.dom.appendChild(button); 21 | 22 | button.onclick = () => { 23 | this.clicked(); 24 | }; 25 | } 26 | Component$onCompleted() { 27 | this.implicitWidth = this.impl.offsetWidth; 28 | this.implicitHeight = this.impl.offsetHeight; 29 | } 30 | $onTextChanged(newVal) { 31 | this.impl.textContent = newVal; 32 | //TODO: Replace those statically sized borders 33 | this.implicitWidth = this.impl.offsetWidth; 34 | this.implicitHeight = this.impl.offsetHeight; 35 | } 36 | $onEnabledChanged(newVal) { 37 | this.impl.disabled = !newVal; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/Auto/QtQuick/tst_point.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtTest 1.0 3 | 4 | TestCase { 5 | name: "point" 6 | property point def 7 | property point arg: "1,2.5" 8 | property point tmp 9 | 10 | function compareS(a, b) { 11 | return compare(a + "", b + "") 12 | } 13 | 14 | function test_construction() { 15 | compareS(def, "QPointF(0, 0)"); 16 | compareS(arg, "QPointF(1, 2.5)"); 17 | tmp = "-1, 20"; 18 | compareS(tmp, "QPointF(-1, 20)"); 19 | compareS(Qt.point(1, 2.5), "QPointF(1, 2.5)"); 20 | } 21 | 22 | function test_get() { 23 | compare(def.x, 0); 24 | compare(def.y, 0); 25 | compare(arg.x, 1); 26 | compare(arg.y, 2.5); 27 | tmp = "-5, 40.31"; 28 | compare(tmp.x, -5); 29 | compare(tmp.y, 40.31); 30 | } 31 | 32 | function test_set() { 33 | tmp = "60, -3"; 34 | compareS(tmp, "QPointF(60, -3)"); 35 | tmp.x = 100.5; 36 | compareS(tmp, "QPointF(100.5, -3)"); 37 | tmp.y = -0.125; 38 | compareS(tmp, "QPointF(100.5, -0.125)"); 39 | compare(tmp.x, 100.5); 40 | compare(tmp.y, -0.125); 41 | } 42 | 43 | function test_immut() { 44 | tmp = arg; 45 | tmp.x = 10.5; 46 | tmp.y = -20.25; 47 | compareS(tmp, "QPointF(10.5, -20.25)"); 48 | compareS(arg, "QPointF(1, 2.5)"); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /tests/Render/Async/ImageFill.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | 3 | Rectangle { 4 | width: 40 5 | height: 40 6 | color: '#fff' 7 | property int loaded: 0 8 | 9 | Image { 10 | x: 0 11 | y: 0 12 | height: 20 13 | width: 20 14 | source: "bg.png" 15 | fillMode: Image.Stretch 16 | smooth: false 17 | onStatusChanged: if (status !== Image.Loading) parent.loaded++ 18 | } 19 | Image { 20 | x: 0 21 | y: 20 22 | height: 20 23 | width: 20 24 | source: "bg.png" 25 | fillMode: Image.Tile 26 | smooth: false 27 | onStatusChanged: if (status !== Image.Loading) parent.loaded++ 28 | } 29 | Image { 30 | x: 20 31 | y: 0 32 | height: 20 33 | width: 20 34 | source: "bg.png" 35 | fillMode: Image.PreserveAspectCrop 36 | smooth: false 37 | onStatusChanged: if (status !== Image.Loading) parent.loaded++ 38 | } 39 | Image { 40 | x: 20 41 | y: 20 42 | height: 20 43 | width: 20 44 | source: "bg.png" 45 | fillMode: Image.PreserveAspectFit 46 | smooth: false 47 | onStatusChanged: if (status !== Image.Loading) parent.loaded++ 48 | } 49 | 50 | onLoadedChanged: { 51 | if (typeof window !== 'undefined' && loaded === 4) { 52 | window.onTestLoad({ framesDelay: 2 }); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /tests/QtQuick/Loader.js: -------------------------------------------------------------------------------- 1 | describe("QtQuick.Loader", function() { 2 | setupDivElement(); 3 | const load = prefixedQmlLoader("QtQuick/qml/Loader"); 4 | 5 | it("SourceImmediate", function() { 6 | const qml = load("SourceImmediate", this.div); 7 | expect(qml.item.value).toBe(42); 8 | }); 9 | it("SourceComponentImmediate", function() { 10 | const qml = load("SourceComponentImmediate", this.div); 11 | expect(qml.item.value).toBe(42); 12 | }); 13 | it("SourceDelayed", function(done) { 14 | const qml = load("SourceDelayed", this.div); 15 | qml.yield = function() { 16 | expect(qml.item.value).toBe(42); 17 | done(); 18 | }; 19 | qml.start(); 20 | }); 21 | it("SourceComponentDelayed", function(done) { 22 | const qml = load("SourceComponentDelayed", this.div); 23 | qml.yield = function() { 24 | expect(qml.item.value).toBe(42); 25 | done(); 26 | }; 27 | qml.start(); 28 | }); 29 | it("set source to an empty string", function() { 30 | const qml = load("EmptySource", this.div); 31 | expect(qml.sourceComponent).toBe(null); 32 | }); 33 | it("SourceComponentFromComponent", function() { 34 | const qml = load("SourceComponentFromComponent", this.div); 35 | expect(qml.item.color.toString()).toBe("#ffff00"); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /tests/Render/Simple/RectangleImplicitSize.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Rectangle { 4 | width: 90 5 | height: 10 6 | color: 'yellow' 7 | 8 | Rectangle { 9 | width: 0 10 | height: 10 11 | color: 'pink' 12 | } 13 | Rectangle { 14 | width: 10 15 | height: 0 16 | color: 'brown' 17 | } 18 | Rectangle { 19 | width: 0 20 | height: 0 21 | x: 10 22 | color: 'blue' 23 | } 24 | Rectangle { 25 | implicitWidth: 10 26 | implicitHeight: 10 27 | x: 20 28 | color: 'red' 29 | } 30 | Rectangle { 31 | width: 5 32 | height: 10 33 | implicitWidth: 10 34 | implicitHeight: 5 35 | x: 30 36 | color: 'pink' 37 | } 38 | Rectangle { 39 | width: 0 40 | height: 0 41 | implicitWidth: 10 42 | implicitHeight: 10 43 | x: 40 44 | color: 'orange' 45 | } 46 | Rectangle { 47 | implicitWidth: -5 48 | implicitHeight: 10 49 | x: 50 50 | color: "#00ffee" 51 | } 52 | Rectangle { 53 | width: 10 54 | implicitHeight: 10 55 | x: 60 56 | color: 'gray' 57 | } 58 | Rectangle { 59 | height: 10 60 | implicitWidth: 10 61 | x: 70 62 | color: 'green' 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/modules/QtQuick/Rotation.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_Rotation extends QtQml_QtObject { 3 | static properties = { 4 | angle: "real" 5 | }; 6 | 7 | constructor(meta) { 8 | super(meta); 9 | 10 | this.axis = new QmlWeb.QObject(this); 11 | QmlWeb.createProperties(this.axis, { 12 | x: "real", 13 | y: "real", 14 | z: { type: "real", initialValue: 1 } 15 | }); 16 | 17 | this.origin = new QmlWeb.QObject(this); 18 | QmlWeb.createProperties(this.origin, { 19 | x: "real", 20 | y: "real" 21 | }); 22 | 23 | this.angleChanged.connect(this.$parent, this.$parent.$updateTransform); 24 | this.axis.xChanged.connect(this.$parent, this.$parent.$updateTransform); 25 | this.axis.yChanged.connect(this.$parent, this.$parent.$updateTransform); 26 | this.axis.zChanged.connect(this.$parent, this.$parent.$updateTransform); 27 | this.origin.xChanged.connect(this, this.$updateOrigin); 28 | this.origin.yChanged.connect(this, this.$updateOrigin); 29 | this.$parent.$updateTransform(); 30 | } 31 | $updateOrigin() { 32 | const style = this.$parent.dom.style; 33 | style.transformOrigin = `${this.origin.x}px ${this.origin.y}px`; 34 | style.webkitTransformOrigin = `${this.origin.x}px ${this.origin.y}px`; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/modules/QtQuick/Row.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_Row extends QtQuick_Positioner { 3 | static properties = { 4 | layoutDirection: "enum" 5 | }; 6 | 7 | constructor(meta) { 8 | super(meta); 9 | 10 | this.layoutDirectionChanged.connect(this, this.layoutChildren); 11 | this.layoutChildren(); 12 | } 13 | layoutChildren() { 14 | let curPos = this.padding; 15 | let maxHeight = 0; 16 | // When layoutDirection is RightToLeft we need oposite order 17 | let i = this.layoutDirection === 1 ? this.children.length - 1 : 0; 18 | const endPoint = this.layoutDirection === 1 ? -1 : this.children.length; 19 | const step = this.layoutDirection === 1 ? -1 : 1; 20 | for (; i !== endPoint; i += step) { 21 | const child = this.children[i]; 22 | if (!(child.visible && child.width && child.height)) { 23 | continue; 24 | } 25 | maxHeight = child.height > maxHeight ? child.height : maxHeight; 26 | 27 | child.x = curPos; 28 | if (this.padding > 0) child.y = this.padding; 29 | 30 | curPos += child.width + this.spacing; 31 | } 32 | this.implicitHeight = maxHeight + this.padding * 2; 33 | // We want no spacing at the right side 34 | this.implicitWidth = curPos - this.spacing + this.padding; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/modules/QtQuick/ListView.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_ListView extends QtQuick_Repeater { 3 | static properties = { 4 | orientation: "enum", 5 | spacing: "real" 6 | }; 7 | 8 | constructor(meta) { 9 | super(meta); 10 | this.modelChanged.connect(this, this.$styleChanged); 11 | this.delegateChanged.connect(this, this.$styleChanged); 12 | this.orientationChanged.connect(this, this.$styleChanged); 13 | this.spacingChanged.connect(this, this.$styleChanged); 14 | this._childrenInserted.connect(this, this.$applyStyleOnItem); 15 | } 16 | container() { 17 | return this; 18 | } 19 | $applyStyleOnItem($item) { 20 | const Qt = QmlWeb.Qt; 21 | $item.dom.style.position = "initial"; 22 | if (this.orientation === Qt.Horizontal) { 23 | $item.dom.style.display = "inline-block"; 24 | if ($item !== this.$items[0]) { 25 | $item.dom.style["margin-left"] = `${this.spacing}px`; 26 | } 27 | } else { 28 | $item.dom.style.display = "block"; 29 | if ($item !== this.$items[0]) { 30 | $item.dom.style["margin-top"] = `${this.spacing}px`; 31 | } 32 | } 33 | } 34 | $styleChanged() { 35 | for (let i = 0; i < this.$items.length; ++i) { 36 | this.$applyStyleOnItem(this.$items[i]); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/QtQuick/Timer.js: -------------------------------------------------------------------------------- 1 | describe("QtQuick.Timer", function() { 2 | setupDivElement(); 3 | beforeEach(function() { 4 | jasmine.addMatchers(customMatchers); 5 | }); 6 | 7 | var load = prefixedQmlLoader("QtQuick/qml/Timer"); 8 | it("can roughly set short intervals", function(done) { 9 | var qml = load("Singleshot", this.div); 10 | qml.interval = 50; 11 | var now = new Date(); 12 | qml.yield = function(arg) { 13 | var t = new Date() - now; 14 | expect(t).toBeRoughly(50, 1); 15 | done(); 16 | }; 17 | qml.start(); 18 | }); 19 | 20 | it("can roughly set short intervals", function(done) { 21 | var qml = load("Singleshot", this.div); 22 | qml.interval = 500; 23 | var now = new Date(); 24 | qml.yield = function(arg) { 25 | var t = new Date() - now; 26 | expect(t).toBeRoughly(500, 0.1); 27 | done(); 28 | }; 29 | qml.start(); 30 | }); 31 | 32 | it("can set Timer.running = true to start", function(done) { 33 | var qml = load("Running", this.div); 34 | qml.yield = function(succeed) { 35 | expect(succeed).toBe(true); 36 | done(); 37 | }; 38 | qml.start(); 39 | }); 40 | 41 | it("Timer parent property", function() { 42 | var qml = load("ParentProperty", this.div); 43 | expect(qml.timer.value).toBe(42); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /tests/Auto/QtQuick/tst_size.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtTest 1.0 3 | 4 | TestCase { 5 | name: "size" 6 | property size def 7 | property size arg: "1x2.5" 8 | property size tmp 9 | 10 | function compareS(a, b) { 11 | return compare(a + "", b + "") 12 | } 13 | 14 | function test_construction() { 15 | compareS(def, "QSizeF(-1, -1)"); 16 | compareS(arg, "QSizeF(1, 2.5)"); 17 | tmp = "100.5 x 20"; 18 | compareS(tmp, "QSizeF(100.5, 20)"); 19 | compareS(Qt.size(1, 2.5), "QSizeF(1, 2.5)"); 20 | } 21 | 22 | function test_get() { 23 | compare(def.width, -1); 24 | compare(def.height, -1); 25 | compare(arg.width, 1); 26 | compare(arg.height, 2.5); 27 | tmp = "-5 x 40.31"; 28 | compare(tmp.width, -5); 29 | compare(tmp.height, 40.31); 30 | } 31 | 32 | function test_set() { 33 | tmp = "60 x -3"; 34 | compareS(tmp, "QSizeF(60, -3)"); 35 | tmp.width = 100.5; 36 | compareS(tmp, "QSizeF(100.5, -3)"); 37 | tmp.height = -0.125; 38 | compareS(tmp, "QSizeF(100.5, -0.125)"); 39 | compare(tmp.width, 100.5); 40 | compare(tmp.height, -0.125); 41 | } 42 | 43 | function test_immut() { 44 | tmp = arg; 45 | tmp.width = 100.5; 46 | tmp.height = -0.125; 47 | compareS(tmp, "QSizeF(100.5, -0.125)"); 48 | compareS(arg, "QSizeF(1, 2.5)"); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/engine/keyboard.js: -------------------------------------------------------------------------------- 1 | QmlWeb.keyCodeToQt = e => { 2 | const Qt = QmlWeb.Qt; 3 | e.keypad = e.keyCode >= 96 && e.keyCode <= 111; 4 | if (e.keyCode === Qt.Key_Tab && e.shiftKey) { 5 | return Qt.Key_Backtab; 6 | } 7 | if (e.keyCode >= 97 && e.keyCode <= 122) { 8 | return e.keyCode - (97 - Qt.Key_A); 9 | } 10 | return e.keyCode; 11 | }; 12 | 13 | QmlWeb.eventToKeyboard = e => ({ 14 | accepted: false, 15 | count: 1, 16 | isAutoRepeat: false, 17 | key: QmlWeb.keyCodeToQt(e), 18 | modifiers: e.ctrlKey * QmlWeb.Qt.ControlModifier 19 | | e.altKey * QmlWeb.Qt.AltModifier 20 | | e.shiftKey * QmlWeb.Qt.ShiftModifier 21 | | e.metaKey * QmlWeb.Qt.MetaModifier 22 | | e.keypad * QmlWeb.Qt.KeypadModifier, 23 | text: e.key || String.fromCharCode(e.charCode || e.keyCode) 24 | }); 25 | 26 | QmlWeb.keyboardSignals = {}; 27 | [ 28 | "asterisk", "back", "backtab", "call", "cancel", "delete", "escape", "flip", 29 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "hangup", "menu", "no", "return", "select", 30 | "space", "tab", "volumeDown", "volumeUp", "yes", "up", "right", "down", "left" 31 | ].forEach(key => { 32 | const name = key.toString(); 33 | const qtName = `Key_${name[0].toUpperCase()}${name.slice(1)}`; 34 | const prefix = typeof key === "number" ? "digit" : ""; 35 | QmlWeb.keyboardSignals[QmlWeb.Qt[qtName]] = `${prefix}${name}Pressed`; 36 | }); 37 | -------------------------------------------------------------------------------- /tests/Render/Async/ImageMirror.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | 3 | Rectangle { 4 | width: 16 5 | height: 10 6 | color: '#fff' 7 | property int loaded: 0 8 | 9 | Image { 10 | x: 0 11 | y: 0 12 | height: 10 13 | width: 4 14 | source: "bg.png" 15 | smooth: false 16 | onStatusChanged: if (status !== Image.Loading) parent.loaded++ 17 | } 18 | Image { 19 | x: 4 20 | y: 0 21 | height: 10 22 | width: 4 23 | source: "bg.png" 24 | fillMode: Image.Stretch 25 | smooth: false 26 | mirror: true 27 | onStatusChanged: if (status !== Image.Loading) parent.loaded++ 28 | } 29 | Image { 30 | id: image3 31 | x: 8 32 | y: 0 33 | height: 10 34 | width: 4 35 | source: "bg.png" 36 | fillMode: Image.Tile 37 | smooth: false 38 | onStatusChanged: if (status !== Image.Loading) parent.loaded++ 39 | } 40 | Image { 41 | id: image4 42 | x: 12 43 | y: 0 44 | height: 10 45 | width: 4 46 | source: "bg.png" 47 | fillMode: Image.Tile 48 | smooth: false 49 | onStatusChanged: if (status !== Image.Loading) parent.loaded++ 50 | } 51 | 52 | onLoadedChanged: { 53 | image3.mirror = true; 54 | image4.mirror = true; 55 | image4.mirror = false; 56 | if (typeof window !== 'undefined' && loaded === 4) { 57 | window.onTestLoad({ framesDelay: 2 }); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /tests/QtQuick.Layouts/StackLayout.js: -------------------------------------------------------------------------------- 1 | describe("QtQuick.Layouts.StackLayout", function() { 2 | setupDivElement(); 3 | var load = prefixedQmlLoader("QtQuick.Layouts/qml/"); 4 | 5 | it("sets implicit sizes", function() { 6 | var qml = load("StackLayout", this.div); 7 | 8 | expect(qml.implicitHeight).toBe(300); 9 | expect(qml.implicitWidth).toBe(200); 10 | }); 11 | 12 | it("respects fillWidth and fillHeight policy", function() { 13 | var qml = load("StackLayout", this.div); 14 | 15 | qml.width = 800; 16 | qml.height = 600; 17 | qml.layoutChildren(); 18 | expect(qml.children[0].width).toBe(800); 19 | expect(qml.children[0].height).toBe(600); 20 | qml.children[0].$Layout.fillWidth = false; 21 | expect(qml.children[0].width).toBe(200); 22 | qml.children[0].$Layout.fillHeight = false; 23 | expect(qml.children[0].height).toBe(300); 24 | }); 25 | 26 | it("only displays the current item", function() { 27 | var qml = load("StackLayout", this.div); 28 | 29 | expect(qml.children[0].visible).toBe(true); 30 | expect(qml.children[1].visible).toBe(false); 31 | qml.currentIndex = 1; 32 | expect(qml.children[1].visible).toBe(true); 33 | expect(qml.children[0].visible).toBe(false); 34 | qml.currentIndex = 2; 35 | expect(qml.children[1].visible).toBe(false); 36 | expect(qml.children[0].visible).toBe(false); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /src/modules/QtQml/Connections.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQml_Connections extends QtQml_QtObject { 3 | static properties = { 4 | target: "QtObject", 5 | ignoreUnknownSignals: "bool" 6 | }; 7 | 8 | constructor(meta) { 9 | super(meta); 10 | this.target = this.$parent; 11 | this.$connections = {}; 12 | 13 | this.$old_target = this.target; 14 | this.targetChanged.connect(this, this.$onTargetChanged); 15 | this.Component.completed.connect(this, this.Component$onCompleted); 16 | } 17 | $onTargetChanged() { 18 | this.$reconnectTarget(); 19 | } 20 | Component$onCompleted() { 21 | this.$reconnectTarget(); 22 | } 23 | $reconnectTarget() { 24 | const old_target = this.$old_target; 25 | for (const i in this.$connections) { 26 | const c = this.$connections[i]; 27 | if (c._currentConnection && old_target && old_target[i] && 28 | typeof old_target[i].disconnect === "function") { 29 | old_target[i].disconnect(c._currentConnection); 30 | } 31 | if (this.target) { 32 | c._currentConnection = QmlWeb.connectSignal(this.target, i, c.value, 33 | c.objectScope, c.componentScope); 34 | } 35 | } 36 | this.$old_target = this.target; 37 | } 38 | $setCustomSlot(propName, value, objectScope, componentScope) { 39 | this.$connections[propName] = { value, objectScope, componentScope }; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/engine/helpers.js: -------------------------------------------------------------------------------- 1 | class QmlWebHelpers { 2 | static arrayFindIndex(array, callback) { 3 | // Note: does not support thisArg, we don't need that 4 | if (!Array.prototype.findIndex) { 5 | for (const key in array) { 6 | if (callback(array[key], key, array)) { 7 | return key; 8 | } 9 | } 10 | return -1; 11 | } 12 | return Array.prototype.findIndex.call(array, callback); 13 | } 14 | static mergeObjects(...args) { 15 | const merged = {}; 16 | for (const i in args) { 17 | const arg = args[i]; 18 | if (!arg) { 19 | continue; 20 | } 21 | for (const key in arg) { 22 | merged[key] = arg[key]; 23 | } 24 | } 25 | return merged; 26 | } 27 | static reduceUri(uri) { 28 | let reducedUri = uri; 29 | let match; 30 | // eslint-disable-next-line no-cond-assign 31 | while (match = reducedUri.match(/\/?\.\//)) { 32 | const part1 = reducedUri.slice(0, match.index); 33 | const part2 = reducedUri.slice(match.index + match[0].length); 34 | reducedUri = `${part1}/${part2}`; 35 | } 36 | // eslint-disable-next-line no-cond-assign 37 | while (match = reducedUri.match(/([^/]+)(\/\.\.)\/?/)) { 38 | const part1 = reducedUri.slice(0, match.index); 39 | const part2 = reducedUri.slice(match.index + match[0].length); 40 | reducedUri = `${part1}/${part2}`; 41 | } 42 | return reducedUri; 43 | } 44 | } 45 | 46 | QmlWeb.helpers = QmlWebHelpers; 47 | -------------------------------------------------------------------------------- /src/modules/Qt.labs.settings/Settings.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class Qt_labs_settings_Settings extends QtQuick_Item { 3 | static properties = { 4 | category: "string" 5 | }; 6 | 7 | constructor(meta) { 8 | super(meta); 9 | 10 | if (typeof window.localStorage === "undefined") { 11 | return; 12 | } 13 | 14 | this.Component.completed.connect(this, this.Component$onCompleted); 15 | } 16 | Component$onCompleted() { 17 | this.$loadProperties(); 18 | this.$initializeProperties(); 19 | } 20 | $getKey(attrName) { 21 | return `${this.category}/${attrName}`; 22 | } 23 | $loadProperties() { 24 | this.$attributes.forEach(attrName => { 25 | if (!this.$properties[attrName]) return; 26 | 27 | const key = this.$getKey(attrName); 28 | this[attrName] = localStorage.getItem(key); 29 | }); 30 | } 31 | $initializeProperties() { 32 | this.$attributes.forEach(attrName => { 33 | if (!this.$properties[attrName]) return; 34 | 35 | let emitter = this; 36 | let signalName = `${attrName}Changed`; 37 | 38 | if (this.$properties[attrName].type === "alias") { 39 | emitter = this.$context[this.$properties[attrName].val.objectName]; 40 | signalName = `${this.$properties[attrName].val.propertyName}Changed`; 41 | } 42 | 43 | emitter[signalName].connect(this, () => { 44 | localStorage.setItem(this.$getKey(attrName), this[attrName]); 45 | }); 46 | }); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /tests/Auto/runner.js: -------------------------------------------------------------------------------- 1 | // For Qt QML, run with `qmltestrunner -input tests/Auto/` 2 | 3 | (function() { 4 | var regex = new RegExp("^/base/tests/Auto/.*/tst_[^/]+\\.qml$"); 5 | var tests = Object.keys(window.__karma__.files) 6 | .filter(function(path) { 7 | return regex.test(path); 8 | }) 9 | .map(function(path) { 10 | return { 11 | qml: path, 12 | group: path.replace("/base/tests/Auto/", "").replace(/\/[^/]+$/, "") 13 | .replace(/\//g, "."), 14 | name: path.replace(/^.*\//, "").replace(".qml", "") 15 | }; 16 | }) 17 | .reduce(function(data, entry) { 18 | if (!data.hasOwnProperty(entry.group)) { 19 | data[entry.group] = []; 20 | } 21 | 22 | data[entry.group].push(entry); 23 | return data; 24 | }, {}); 25 | 26 | Object.keys(tests).forEach(function(group) { 27 | describe("Auto." + group, function() { 28 | setupDivElement(); 29 | tests[group].forEach(function(test) { 30 | it(test.name, function() { 31 | loadQmlFile(test.qml, this.div); 32 | var t = QmlWeb.engine.tests; 33 | if (t.errors.length > 0) { 34 | throw new Error(t.errors.join("\n") + "\n"); 35 | } 36 | expect(t.total).toBe(1); 37 | expect(t.completed).toBe(1); 38 | expect(t.stats.pass + t.stats.skip).toBeGreaterThan(0); 39 | expect(t.stats.fail).toBe(0); 40 | }); 41 | }); 42 | }); 43 | }); 44 | }()); 45 | -------------------------------------------------------------------------------- /tests/QmlWeb.Dom/DomElementStyle.js: -------------------------------------------------------------------------------- 1 | describe("QmlWeb.Dom.DomElement", function() { 2 | setupDivElement(); 3 | var load = prefixedQmlLoader("QmlWeb.Dom/qml/DomElement"); 4 | 5 | it("initalizes style", function() { 6 | var qml = load("Style", this.div); 7 | expect(qml.dom.style.textAlign).toBe("center"); 8 | }); 9 | 10 | it("updates style", function() { 11 | var qml = load("Style", this.div); 12 | qml.style.textAlign = "right"; 13 | expect(qml.dom.style.textAlign).toBe("right"); 14 | }); 15 | 16 | it("supports style bindings", function() { 17 | var qml = load("Style", this.div); 18 | expect(qml.dom.style.fontSize).toBe("21px"); 19 | qml.bindSize = 14; 20 | expect(qml.style.fontSize).toBe("14px"); 21 | expect(qml.dom.style.fontSize).toBe("14px"); 22 | }); 23 | 24 | it("updates sizes", function() { 25 | var qml = load("Style", this.div); 26 | qml.style.width = "150px"; 27 | qml.style.height = "40px"; 28 | expect(qml.dom.style.width).toBe("150px"); 29 | expect(qml.dom.getBoundingClientRect().width).toBe(150); 30 | expect(qml.width).toBe(150); 31 | expect(qml.dom.getBoundingClientRect().height).toBe(40); 32 | expect(qml.height).toBe(40); 33 | }); 34 | 35 | it("updates implicit sizes", function() { 36 | var qml = load("Style", this.div); 37 | var spy = jasmine.createSpy(); 38 | qml.implicitWidthChanged.connect(spy); 39 | qml.text = "Hello world!"; 40 | expect(spy).toHaveBeenCalled(); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | QmlWeb is licensed under the MIT license, as follows: 2 | 3 | """ 4 | MIT License 5 | 6 | Copyright (c) 2011, 2012 Lauri Paimen 7 | Copyright (c) 2013 Anton Kreuzkamp 8 | Copyright (c) 2015 Pavel Vasev - initial and working 9 | import implementation. 10 | Copyright (c) 2016-2018 QmlWeb contributors 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining a copy of 13 | this software and associated documentation files (the "Software"), to deal in 14 | the Software without restriction, including without limitation the rights to 15 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 16 | the Software, and to permit persons to whom the Software is furnished to do so, 17 | subject to the following conditions: 18 | 19 | The above copyright notice and this permission notice shall be included in all 20 | copies or substantial portions of the Software. 21 | 22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 24 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 25 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 26 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 27 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | """ 29 | -------------------------------------------------------------------------------- /src/modules/QtQuick.Layouts/Positioner.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_Layouts_Positioner extends QtQuick_Layouts_AbstractLayout { 3 | layoutChildren() { 4 | if (this.children.length > 0) { 5 | const layout = this.$bareLayout(); 6 | 7 | this.implicitWidth = this.$isUsingImplicitWidth 8 | ? layout.contentWidth : layout.maxWidth; 9 | this.implicitHeight = this.$isUsingImplicitHeight 10 | ? layout.contentHeight : layout.maxHeight; 11 | this.$fillLayoutCells(layout); 12 | this.$applyDirection(layout); 13 | this.$applyLayout(layout); 14 | } else { 15 | this.implicitWidth = this.implicitHeight = 0; 16 | } 17 | } 18 | 19 | $plugChildrenSignals(children, action) { 20 | super.$plugChildrenSignals(children, action, ["visible"]); 21 | } 22 | 23 | $createLayoutDescriptor() { 24 | return { 25 | cells: [], 26 | maxWidth: this.$isUsingImplicitWidth ? 0 : this.width, 27 | maxHeight: this.$isUsingImplicitHeight ? 0 : this.height, 28 | contentWidth: 0, 29 | contentHeight: 0, 30 | fillColumnCount: 0, 31 | fillRowCount: 0 32 | }; 33 | } 34 | 35 | $applyDirection() { 36 | } 37 | 38 | $applyLayout(layout) { 39 | for (let i = 0; i < layout.cells.length; ++i) { 40 | const cell = layout.cells[i]; 41 | 42 | cell.item.x = cell.x; 43 | cell.item.y = cell.y; 44 | cell.item.width = cell.width; 45 | cell.item.height = cell.height; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/modules/QtQuick.Layouts/StackLayout.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_Layouts_StackLayout extends QtQuick_Layouts_AbstractLayout { 3 | static versions = /^1\./; 4 | static properties = { 5 | count: "int", 6 | currentIndex: "int" 7 | }; 8 | 9 | constructor(meta) { 10 | super(meta); 11 | window.bite = this; 12 | this.childrenChanged.connect(this, this.$updateCount); 13 | this.currentIndexChanged.connect(this, this.layoutChildren); 14 | } 15 | 16 | $updateCount() { 17 | this.count = this.children.length; 18 | } 19 | 20 | layoutChildren() { 21 | if (this.currentIndex < this.children.length) { 22 | const currentItem = this.children[this.currentIndex]; 23 | 24 | this.$updateSize(currentItem, "Width"); 25 | this.$updateSize(currentItem, "Height"); 26 | } 27 | this.children.forEach(this.$updateChildVisibility.bind(this)); 28 | } 29 | 30 | $updateSize(child, direction) { 31 | const propertyName = direction[0].toLowerCase() + direction.slice(1); 32 | 33 | if (this[`$isUsingImplicit${direction}`]) { 34 | this[`implicit${direction}`] = this.$inferCellSize(child, direction); 35 | } else if (child.$Layout[`fill${direction}`] !== false) { 36 | child[propertyName] = this[propertyName]; 37 | } else { 38 | child[propertyName] = child[`implicit${direction}`]; 39 | } 40 | } 41 | 42 | $updateChildVisibility(child) { 43 | child.visible = this.currentIndex === this.children.indexOf(child); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/modules/QtGraphicalEffects/FastBlur.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtGraphicalEffects_FastBlur extends QtQuick_Item { 3 | static properties = { 4 | radius: "real", 5 | source: { type: "var", initialValue: null } 6 | }; 7 | 8 | constructor(meta) { 9 | super(meta); 10 | 11 | this.$previousSource = null; 12 | this.$filterObject = undefined; 13 | 14 | this.radiusChanged.connect(this, this.$onRadiusChanged); 15 | this.sourceChanged.connect(this, this.$onSourceChanged); 16 | } 17 | $onRadiusChanged() { 18 | this.$updateEffect(this.source); 19 | } 20 | $onSourceChanged() { 21 | this.$updateEffect(this.source); 22 | } 23 | $updateFilterObject() { 24 | this.$filterObject = { 25 | transformType: "filter", 26 | operation: "blur", 27 | parameters: `${this.radius}px` 28 | }; 29 | } 30 | $updateEffect(source) { 31 | console.log("updating effect"); 32 | if (this.$previousSource) { 33 | const index = this.$previousSource.transform.indexOf(this.$filterObject); 34 | this.$previousSource.transform.splice(index, 1); 35 | this.$previousSource.$updateTransform(); 36 | } 37 | if (source && source.transform) { 38 | this.$updateFilterObject(); 39 | console.log("updating effect:", this.$filterObject, source); 40 | source.transform.push(this.$filterObject); 41 | source.$updateTransform(); 42 | this.$previousSource = source; 43 | } else { 44 | this.$previousSource = null; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/modules/QtMultimedia/MediaPlayer.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtMultimedia_MediaPlayer extends QtQml_QtObject { 3 | static versions = /^5\./; 4 | static enums = { 5 | MediaPlayer: { 6 | Available: 0, Busy: 2, Unavailable: 1, ResourceMissing: 3, 7 | 8 | NoError: 0, ResourceError: 1, FormatError: 2, NetworkError: 4, 9 | AccessDenied: 8, ServiceMissing: 16, 10 | 11 | StoppedState: 0, PlayingState: 1, PausedState: 2, 12 | 13 | NoMedia: 0, Loading: 1, Loaded: 2, Buffering: 4, Stalled: 8, 14 | EndOfMedia: 16, InvalidMedia: 32, UnknownStatus: 64 15 | } 16 | }; 17 | static properties = { 18 | audioRole: "enum", // TODO 19 | autoLoad: { type: "bool", initialValue: true }, 20 | autoPlay: "bool", 21 | availability: "enum", // MediaPlayer.Available 22 | bufferProgress: "real", 23 | duration: "int", 24 | error: "enum", // MediaPlayer.NoError 25 | errorString: "string", 26 | hasAudio: "bool", 27 | hasVideo: "bool", 28 | loops: "int", 29 | muted: "bool", 30 | playbackRate: { type: "real", initialValue: 1 }, 31 | playbackState: "enum", // MediaPlayer.StoppedState 32 | position: "int", 33 | seekable: "bool", 34 | source: "url", 35 | status: "enum", // MediaPlayer.NoMedia 36 | volume: "real" 37 | }; 38 | static signals = { 39 | error: [ 40 | { type: "enum", name: "error" }, 41 | { type: "string", name: "errorString" } 42 | ], 43 | paused: [], 44 | playing: [], 45 | stopped: [] 46 | }; 47 | 48 | // TODO: impl 49 | } 50 | -------------------------------------------------------------------------------- /tests/QMLEngine/qml/PropertiesUrlExceptionSafe.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import "PropertiesUrlDir" 3 | 4 | Item { 5 | property alias localBindingSimple: properties_url_import.localBindingSimple 6 | property alias localBinding: properties_url_import.localBinding 7 | property alias localSet: properties_url_import.localSet 8 | property alias remoteBindingSimple: properties_url_import.remoteBindingSimple 9 | property alias remoteBinding: properties_url_import.remoteBinding 10 | property alias remoteSet: properties_url_import.remoteSet 11 | PropertiesUrlImportWithExceptions { 12 | id: properties_url_import 13 | remoteBindingSimple: "remoteBindingSimple.png" 14 | remoteBinding: "remote" + "Binding.png" 15 | Component.onCompleted: { 16 | properties_url_import.remoteSet = "remoteSet.png" 17 | } 18 | /* These are required as they force some slots to run in this context when 19 | * things are done in PropertiesUrlExceptionSafe. This tests that running 20 | * slots that throw an exception in this context doesn't have any unintended 21 | * consequences. */ 22 | onLocalSetChanged: { 23 | throw "Some Exception" 24 | } 25 | onLocalBindingSimpleChanged: { 26 | throw "Some Exception" 27 | } 28 | onLocalBindingChanged: { 29 | throw "Some Exception" 30 | } 31 | onRemoteSetChanged: { 32 | throw "Some Exception" 33 | } 34 | onRemoteBindingSimpleChanged: { 35 | throw "Some Exception" 36 | } 37 | onRemoteBindingChanged: { 38 | throw "Some Exception" 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/modules/QtQuick.Layouts/Layout.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_Layouts_Layout extends QtQml_QtObject { 3 | static versions = /^1\./; 4 | 5 | constructor(meta) { 6 | super(meta); 7 | throw new Error("Do not create objects of type Layout"); 8 | } 9 | static getAttachedObject() { 10 | if (!this.$Layout) { 11 | this.$Layout = new QmlWeb.QObject(this); 12 | QmlWeb.createProperties(this.$Layout, { 13 | alignment: { type: "enum", initialValue: null }, 14 | bottomMargin: { type: "real", initialValue: null }, 15 | column: { type: "int", initialValue: null }, 16 | columnSpan: { type: "int", initialValue: 1 }, 17 | fillHeight: { type: "bool", initialValue: null }, 18 | fillWidth: { type: "bool", initialValue: null }, 19 | leftMargin: { type: "real", initialValue: null }, 20 | margins: "real", 21 | maximumHeight: { type: "real", initialValue: null }, 22 | maximumWidth: { type: "real", initialValue: null }, 23 | minimumHeight: { type: "real", initialValue: null }, 24 | minimumWidth: { type: "real", initialValue: null }, 25 | preferredHeight: { type: "real", initialValue: null }, 26 | preferredWidth: { type: "real", initialValue: null }, 27 | rightMargin: { type: "real", initialValue: null }, 28 | row: { type: "int", initialValue: null }, 29 | rowSpan: { type: "int", initialValue: 1 }, 30 | topMargin: { type: "real", initialValue: null } 31 | }); 32 | } 33 | return this.$Layout; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/modules/QtQuick/Canvas.js: -------------------------------------------------------------------------------- 1 | // TODO 2 | // Currently only a skeleton implementation 3 | 4 | // eslint-disable-next-line no-undef 5 | class QtQuick_Canvas extends QtQuick_Item { 6 | static properties = { 7 | available: { type: "bool", initialValue: true }, 8 | canvasSize: { type: "var", initialValue: [0, 0] }, 9 | canvasWindow: { type: "var", initialValue: [0, 0, 0, 0] }, 10 | context: { type: "var", initialValue: {} }, 11 | contextType: { type: "string", initialValue: "contextType" }, 12 | renderStrategy: "enum", 13 | renderTarget: "enum", 14 | tileSize: { type: "var", initialValue: [0, 0] } 15 | }; 16 | static signals = { 17 | imageLoaded: [], 18 | paint: [{ type: "var", name: "region" }], 19 | painted: [] 20 | }; 21 | 22 | cancelRequestAnimationFrame(/*handle*/) { 23 | return false; 24 | } 25 | getContext(/*context_id, ...args*/) { 26 | return {}; 27 | } 28 | isImageError(/*image*/) { 29 | return true; 30 | } 31 | isImageLoaded(/*image*/) { 32 | return false; 33 | } 34 | isImageLoading(/*image*/) { 35 | return false; 36 | } 37 | loadImage(image) { 38 | //loadImageAsync(image); 39 | if (this.isImageLoaded(image)) { 40 | this.imageLoaded(); 41 | } 42 | } 43 | markDirty(area) { 44 | // if dirty 45 | this.paint(area); 46 | } 47 | requestAnimationFrame(/*callback*/) { 48 | return 0; 49 | } 50 | requestPaint() { 51 | } 52 | save(/*file_name*/) { 53 | return false; 54 | } 55 | toDataURL(/*mime_type*/) { 56 | return ""; 57 | } 58 | unloadImage(/*image*/) { 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/modules/QtWebView/WebView.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtWebView_WebView extends QtQuick_Item { 3 | static versions = /^1\./; 4 | static properties = { 5 | canGoBack: "bool", // TODO 6 | canGoForward: "bool", // TODO 7 | loadProgress: "int", 8 | loading: "bool", 9 | title: "string", 10 | url: "url" 11 | }; 12 | static signals = { 13 | /* // TODO 14 | loadingChanged: [ 15 | { type: "WebViewLoadRequest", name: "loadRequest" } 16 | ] 17 | */ 18 | }; 19 | 20 | constructor(meta) { 21 | super(meta); 22 | 23 | this.urlChanged.connect(this, this.$onUrlChanged); 24 | 25 | const iframe = this.impl = document.createElement("iframe"); 26 | iframe.style.display = "block"; 27 | iframe.style.position = "absolute"; 28 | iframe.style.width = "100%"; 29 | iframe.style.height = "100%"; 30 | iframe.style.borderWidth = "0"; 31 | iframe.style.pointerEvents = "auto"; 32 | this.dom.appendChild(iframe); 33 | 34 | iframe.onload = () => { 35 | try { 36 | this.title = iframe.contentDocument.title; 37 | } catch (e) { 38 | console.log(`CSP prevents us from reading title for ${this.url}`); 39 | this.title = ""; 40 | } 41 | this.loadProgress = 100; 42 | this.loading = false; 43 | }; 44 | iframe.onerror = () => { 45 | this.title = ""; 46 | this.loadProgress = 0; 47 | this.loading = false; 48 | }; 49 | } 50 | $onUrlChanged(newVal) { 51 | this.loadProgress = 0; 52 | this.loading = true; 53 | this.impl.src = newVal; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | process.env.CHROMIUM_BIN = require("puppeteer").executablePath(); 2 | 3 | require("./tests/chromium.callback.js"); 4 | 5 | module.exports = function(config) { 6 | config.set({ 7 | basePath: "", 8 | frameworks: ["jasmine"], 9 | files: [ 10 | config.coverageEnabled ? "tmp/qmlweb.covered.js" : "lib/qmlweb.js", 11 | { pattern: "lib/*.js", included: false }, 12 | { pattern: "lib/*.js.map", included: false }, 13 | { pattern: "tmp/qmlweb.*.js", included: false }, 14 | { pattern: "tmp/*.js.map", included: false }, 15 | "tests/common.js", 16 | "tests/failingTests.js", 17 | "tests/*/*.js", 18 | "tests/*/**/test*.js", 19 | { pattern: "tests/*/**/qmldir", included: false }, 20 | { pattern: "tests/*/**/qml/*.js", included: false }, 21 | { pattern: "tests/*/**/*.qml", included: false }, 22 | { pattern: "tests/*/**/*.png", included: false } 23 | ], 24 | browsers: ["ChromiumHeadlessCustom"], 25 | reporters: ["spec", "coverage"], 26 | coverageReporter: { 27 | type: "lcov", 28 | dir: "coverage/" 29 | }, 30 | browserDisconnectTolerance: 5, // required for phantomjs in windows 31 | browserNoActivityTimeout: 100000, // required for phantomjs in windows 32 | customLaunchers: { 33 | ChromiumHeadlessCustom: { 34 | base: process.env.NOT_HEADLESS ? "Chromium" : "ChromiumHeadless", 35 | flags: [ 36 | "--no-sandbox", // FIXME 37 | "--force-device-scale-factor=1", 38 | "--remote-debugging-port=9222" 39 | ] 40 | } 41 | } 42 | }); 43 | }; 44 | -------------------------------------------------------------------------------- /tests/QtQml/Binding.js: -------------------------------------------------------------------------------- 1 | describe("QtQml.Binding", function() { 2 | setupDivElement(); 3 | 4 | var load = prefixedQmlLoader("QtQml/qml/Binding"); 5 | it("one way binding", function() { 6 | var qml = load("OneWay", this.div); 7 | qml.sourceValue = 50; 8 | expect(qml.targetValue).toBe(50); 9 | }); 10 | 11 | it("one way binding - when", function() { 12 | var qml = load("OneWay", this.div); 13 | qml.when = false; 14 | qml.sourceValue = 50; 15 | expect(qml.targetValue).toBe(0); 16 | 17 | qml.when = true; 18 | expect(qml.targetValue).toBe(50); 19 | }); 20 | 21 | it("two way binding", function() { 22 | var qml = load("TwoWay", this.div); 23 | qml.sourceValue = 50; 24 | expect(qml.targetValue).toBe(50); 25 | qml.targetValue = 23; 26 | expect(qml.sourceValue).toBe(23); 27 | }); 28 | 29 | it("two way binding - when", function() { 30 | var qml = load("TwoWay", this.div); 31 | qml.when = false; 32 | qml.sourceValue = 50; 33 | expect(qml.targetValue).toBe(0); 34 | qml.targetValue = 10; 35 | qml.when = true; 36 | expect(qml.targetValue).toBe(50); // note: the first binding applies first 37 | qml.targetValue = 10; 38 | expect(qml.sourceValue).toBe(10); 39 | }); 40 | 41 | it("broken binding", function() { 42 | var qml = load("Broken", this.div); 43 | expect(qml.targetValue).toBe(0); 44 | qml.when = true; 45 | expect(qml.targetValue).toBe(0); // should not override anything 46 | }); 47 | 48 | it("binding undefined var", function() { 49 | var qml = load("Undefined", this.div); 50 | qml.sourceValue = undefined; 51 | expect(qml.targetValue).toBe(undefined); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /tests/QtTest/TestCase.js: -------------------------------------------------------------------------------- 1 | describe("QtTest", function() { 2 | setupDivElement(); 3 | var load = prefixedQmlLoader("QtTest/qml/TestCase"); 4 | 5 | it("Empty", function() { 6 | load("Empty", this.div); 7 | var tests = QmlWeb.engine.tests; 8 | expect(tests.total).toBe(1); 9 | expect(tests.completed).toBe(1); 10 | expect(tests.stats.pass).toBe(2); 11 | expect(tests.stats.fail).toBe(0); 12 | expect(tests.stats.skip).toBe(0); 13 | }); 14 | 15 | it("Simple", function() { 16 | load("Simple", this.div); 17 | var tests = QmlWeb.engine.tests; 18 | expect(tests.total).toBe(1); 19 | expect(tests.completed).toBe(1); 20 | expect(tests.stats.pass).toBe(4); 21 | expect(tests.stats.fail).toBe(1); 22 | expect(tests.stats.skip).toBe(1); 23 | }); 24 | 25 | it("Datadriven", function() { 26 | load("Datadriven", this.div); 27 | var tests = QmlWeb.engine.tests; 28 | expect(tests.total).toBe(1); 29 | expect(tests.completed).toBe(1); 30 | expect(tests.stats.pass).toBe(6); 31 | expect(tests.stats.fail).toBe(2); 32 | expect(tests.stats.skip).toBe(1); 33 | }); 34 | 35 | it("API", function() { 36 | var qml = load("Empty", this.div); 37 | expect(function() { 38 | qml.compare(4, 2 + 2, "Compare"); 39 | }).not.toThrow(); 40 | expect(function() { 41 | qml.compare(5, 2 + 2, "Compare"); 42 | }).toThrowError("Compare"); 43 | expect(function() { 44 | qml.warn("Warning"); 45 | }).not.toThrow(); 46 | expect(function() { 47 | qml.verify(true, "True"); 48 | }).not.toThrow(); 49 | expect(function() { 50 | qml.verify(false, "False"); 51 | }).toThrowError(); 52 | }); 53 | }); 54 | 55 | -------------------------------------------------------------------------------- /src/modules/QtQuick/DoubleValidator.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | class QtQuick_DoubleValidator extends QtQml_QValidator { 3 | static enums = { 4 | DoubleValidator: { StandardNotation: 1, ScientificNotation: 2 } 5 | }; 6 | static properties = { 7 | bottom: { type: "real", initialValue: -Infinity }, 8 | top: { type: "real", initialValue: Infinity }, 9 | decimals: { type: "int", initialValue: 1000 }, 10 | // DoubleValidator.ScientificNotation 11 | notation: { type: "enum", initialValue: 2 } 12 | }; 13 | 14 | constructor(meta) { 15 | super(meta); 16 | this.$standardRegExp = /^(-|\+)?\s*[0-9]+(\.[0-9]+)?$/; 17 | this.$scientificRegExp = /^(-|\+)?\s*[0-9]+(\.[0-9]+)?(E(-|\+)?[0-9]+)?$/; 18 | } 19 | getRegExpForNotation(notation) { 20 | switch (notation) { 21 | case this.DoubleValidator.ScientificNotation: 22 | return this.$scientificRegExp; 23 | case this.DoubleValidator.StandardNotation: 24 | return this.$standardRegExp; 25 | } 26 | return null; 27 | } 28 | $getDecimalsForNumber(number) { 29 | if (Math.round(number) === number) { 30 | return 0; 31 | } 32 | const str = `${number}`; 33 | return /\d*$/.exec(str)[0].length; 34 | } 35 | validate(string) { 36 | const regExp = this.getRegExpForNotation(this.notation); 37 | if (!regExp.test(string.trim())) { 38 | return false; 39 | } 40 | const value = parseFloat(string); 41 | const acceptable = this.bottom <= value && this.top >= value && 42 | this.$getDecimalsForNumber(value) <= this.decimals; 43 | return acceptable 44 | ? this.QValidator.Acceptable 45 | : this.QValidator.Invalid; 46 | } 47 | } 48 | --------------------------------------------------------------------------------