diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..d134748e --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +# .gitignore template for skeleton-based apps +/compiled +/qx_packages +.package-cache.json diff --git a/Manifest.json b/Manifest.json new file mode 100644 index 00000000..6b969cfe --- /dev/null +++ b/Manifest.json @@ -0,0 +1,34 @@ +{ + "$schema": "https://raw.githubusercontent.com/qooxdoo/qooxdoo-compiler/master/source/resource/qx/tool/schema/Manifest-1-0-0.json", + "info": { + "name": "tutorial", + "summary": "", + "description": "", + "homepage": "", + "license": "MIT license", + "authors": [ + { + "name": "", + "email": "" + } + ], + "version": "1.0.0" + }, + "provides": { + "namespace": "tutorial", + "encoding": "utf-8", + "class": "source/class", + "resource": "source/resource", + "translation": "source/translation" + }, + "externalResources": { + "script": [], + "css": [ + "qxl/tutorial/scss/custom.scss" + ] + }, + "requires": { + "@qooxdoo/framework": "^6.0.0-beta", + "@qooxdoo/compiler": "^1.0.0-beta" + } +} \ No newline at end of file diff --git a/compile.json b/compile.json new file mode 100644 index 00000000..94ba0353 --- /dev/null +++ b/compile.json @@ -0,0 +1,38 @@ +{ + "$schema": "https://raw.githubusercontent.com/qooxdoo/qooxdoo-compiler/master/source/resource/qx/tool/schema/compile-1-0-0.json", + "targets": [ + { + "type": "source", + "outputPath": "compiled/source", + "bundle": { + "include": "qx.*" + } + }, + { + "type": "build", + "outputPath": "compiled/build" + } + ], + "defaultTarget": "source", + "locales": [ + "en" + ], + "environment": { + "qx.icontheme": "Tango" + }, + "applications": [ + { + "class": "qxl.tutorial.Application", + "theme": "qx.theme.Indigo", + "name": "tutorial", + "include": [ + "qx.*" + ] + } + + ], + "sass": { + "compiler": "legacy" + } + +} \ No newline at end of file diff --git a/qx-lock.json b/qx-lock.json new file mode 100644 index 00000000..6ef70375 --- /dev/null +++ b/qx-lock.json @@ -0,0 +1,29 @@ +{ + "libraries": [ + { + "library_name": "logpane", + "library_version": "1.0.0", + "path": "qx_packages/qooxdoo_qxl_logpane_v1_0_0", + "uri": "qooxdoo/qxl.logpane", + "repo_name": "qooxdoo/qxl.logpane", + "repo_tag": "v1.0.0" + }, + { + "library_name": "versionlabel", + "library_version": "1.0.0", + "path": "qx_packages/qooxdoo_qxl_versionlabel_v1_0_0", + "uri": "qooxdoo/qxl.versionlabel", + "repo_name": "qooxdoo/qxl.versionlabel", + "repo_tag": "v1.0.0" + }, + { + "library_name": "Playground", + "library_version": "1.0.0", + "path": "qx_packages/qooxdoo_qxl_playground_v1_0_0", + "uri": "qooxdoo/qxl.playground", + "repo_name": "qooxdoo/qxl.playground", + "repo_tag": "v1.0.0" + } + ], + "version": "2.1.0" +} \ No newline at end of file diff --git a/source/class/qxl/tutorial/Application.js b/source/class/qxl/tutorial/Application.js new file mode 100644 index 00000000..8cb37461 --- /dev/null +++ b/source/class/qxl/tutorial/Application.js @@ -0,0 +1,315 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2012 1&1 Internet AG, Germany, http://www.1und1.de + + License: + MIT: https://opensource.org/licenses/MIT + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Martin Wittemann (wittemann) + +************************************************************************ */ + +/* ************************************************************************ +************************************************************************ */ + +/** + * This is the main application class of your custom application "tutorial" + * + * @asset(qxl/tutorial/*) + * @require(qx.module.Manipulating) + * @require(qx.module.Attribute) + * @require(qx.module.Traversing) + */ +qx.Class.define("qxl.tutorial.Application", +{ + extend : qx.application.Standalone, + + statics : { + mobileSupported : function() { + var engine = qx.core.Environment.get("engine.name"); + + // all webkits are ok + if (engine == "webkit") { + return true; + } + // ie > 10 is ok + if (engine == "mshtml" && parseInt(qx.core.Environment.get("browser.documentmode")) >= 10) { + return true; + } + // ff > 10 is ok + if (engine == "gecko" && parseInt(qx.core.Environment.get("engine.version")) >= 10) { + return true; + } + return false; + }, + + + allowFade : function() { + return !(qx.core.Environment.get("engine.name") == "mshtml" && + parseInt(qx.core.Environment.get("browser.documentmode")) < 9); + } + }, + + members : + { + __header : null, + __playArea : null, + __editor : null, + __description : null, + __selectionWindow : null, + __actionArea : null, + + __desktopTutorials : null, + __mobileTutorials : null, + + __confirmWindow : null, + + main : function() { + // Call super class + this.base(arguments); + + // Enable logging in debug variant + if (qx.core.Environment.get("qx.debug")) { + // support native logging capabilities, e.g. Firebug for Firefox + qx.log.appender.Native; + // support additional cross-browser console. Press F7 to toggle visibility + qx.log.appender.Console; + } + + // Tutorials List + this.__desktopTutorials = { + "Hello_World" : "Basic usage of a button" + , "Form" : "Simple login form with validation" + , "Single_Value_Binding" : "Binding of simple values" + }; + this.__mobileTutorials = { + "Hello_World" : "One page showing a button" + , "Pages" : "App featuring two pages" + }; + + // Create main layout + var mainComposite = new qx.ui.container.Composite(new qx.ui.layout.VBox()); + this.getRoot().add(mainComposite, {edge:0}); + + // Create header + this.__header = new qxl.tutorial.view.Header(); + this.__header.addListener("selectTutorial", this.openSelectionWindow, this); + mainComposite.add(this.__header); + + // create the content + var content = new qx.ui.splitpane.Pane(); + content.setAppearance("app-splitpane"); + content.setPaddingTop(10); + mainComposite.add(content, {flex: 1}); + + this.__description = new qxl.tutorial.view.Description(); + this.__description.addListener("run", this.run, this); + this.__description.addListener("update", this.updateEditor, this); + + content.add(this.__description, 1); + + var actionArea = new qx.ui.splitpane.Pane(); + this.__actionArea = actionArea; + this.__editor = new qxl.playground.view.Editor(); + actionArea.add(this.__editor); + qxl.playground.view.Editor.loadAce(function() { + this.__editor.init(); + }, this); + + this.__playArea = new qxl.playground.view.PlayArea(); + this.__playArea.setBackgroundColor("white"); + + actionArea.add(this.__playArea); + this.__playArea.updateCaption(""); + this.__playArea.addListener("toggleMaximize", function(e) { + if (!this.__editor.isExcluded()) { + this.__editor.exclude(); + this.__description.exclude(); + } else { + this.__editor.show(); + this.__description.show(); + } + }, this); + + content.add(actionArea, 3); + + // set the blocker color + this.getRoot().setBlockerColor("rgba(0, 0, 0, 0.35)"); + }, + + // overridden + finalize: function() { + var state = qx.bom.History.getInstance().getState(); + if (state == "") { + // use the hello world desktop as default + this.loadTutorial("Hello_World", "desktop"); + } else { + state = state.split("~"); + if (state[0] == "desktop") { + this.loadTutorial(state[1], state[0]); + } else if ((qxl.tutorial.Application.mobileSupported())) { + this.loadTutorial(state[1], state[0]); + } else { + // use the hello world desktop as default + this.loadTutorial("Hello_World", "desktop"); + } + } + }, + + + openSelectionWindow : function() { + if (!this.__selectionWindow) { + this.__selectionWindow = new qxl.tutorial.view.SelectionWindow( + this.__desktopTutorials, + this.__mobileTutorials + ); + this.__selectionWindow.addListener("changeTutorial", this.__onChangeTutorial, this); + } + + this.__selectionWindow.open(); + this.render(); // make sure the DOM object is available for the fade + if (qxl.tutorial.Application.allowFade()) { + this.__selectionWindow.fadeIn(300); + } else { + this.__selectionWindow.show(); + } + }, + + + __onChangeTutorial : function(e) { + var type = e.getData().type; + var name = e.getData().name; + this.loadTutorial(name, type); + this.__editor.setCode(""); + this.__editor.setError(); + this.__playArea.reset(); + qx.bom.History.getInstance().setState(type + "~" + name); + }, + + + updateEditor : function(e) { + var code = e.getData().toString(); + this.confirm("This will replace the current code in the editor.", function(ok) { + if (ok.getData()) { + this.__editor.setCode(code); + this.run(); + } + }, this); + }, + + + confirm : function(text, callback, ctx) { + if (!this.__confirmWindow) { + this.__confirmWindow = new qxl.tutorial.view.Confirm(); + } + if (this.__confirmWindow.getIgnore()) { + callback.call(ctx, {getData : function() { + return true; +}}); + return; + } + this.__confirmWindow.setMessage(text); + this.__confirmWindow.open(); + this.render(); + if (qxl.tutorial.Application.allowFade()) { + this.__confirmWindow.fadeIn(300); + } else { + this.__confirmWindow.show(); + } + this.__confirmWindow.addListenerOnce("confirm", callback, ctx); + }, + + + run : function() { + var code = this.__editor.getCode(); + + // don't run if we have no code + if (code == "") { + return; + } + + // reset the play area + this.__playArea.reset({}, {}); + + var exc; + // try to create a function + try { + this.fun = new Function(code); + } catch (ex) { + exc = ex; + } + // run the code + try { + // run the application + this.fun.call(this.__playArea.getApp()); + } catch (ex) { + exc = ex; + } + if (exc) { + this.__editor.setBackgroundColor("#FFF0F0"); + this.__editor.setError(exc); + this.error(exc); + } else { + this.__editor.setError(); + this.__editor.setBackgroundColor("white"); + } + }, + + + /** + * @lint ignoreDeprecated(alert) + */ + loadTutorial : function(name, type) { + var htmlFileName = qx.util.ResourceManager.getInstance().toUri( + "qxl/tutorial/" + type + "/" + name + ".html" + ); + var req = new qx.io.request.Xhr(htmlFileName); + req.addListener("success", function(e) { + var req = e.getTarget(); + this.__description.setTutorial( + this.parseTutorial(name, type, req.getResponse()) + ); + this.__playArea.updateCaption(name.replace(/_/g, " ") + " (" + type + ")"); + this.__playArea.setMode(type !== "desktop" ? "mobile" : "ria"); + this.__actionArea.setOrientation(type == "desktop" ? "vertical" : "horizontal"); + }, this); + req.send(); + + req.addListener("fail", function(evt) { + this.error("Couldn't load file: " + htmlFileName); + if (window.location.protocol == "file:") { + // eslint-disable-next-line no-alert + alert("Failed to load the tutorials from the file system.\n\n" + + "The security settings of your browser may prohibit AJAX " + + "when using the file protocol. Please try the http protocol " + + "instead."); + } + }, this); + }, + + + parseTutorial : function(name, type, html) { + var tut = { + name : name, + type : type, + steps : [], + code : [] + }; + var div = q.create("
" + this.getTutorial().name.replace(/_/g, " ") + "
"; + var step = "Step " + (this.getStep() + 1) + "/" + this.getTutorial().steps.length + "
"; + var html = headline + step + this.getTutorial().steps[this.getStep()]; + + this.__embed.setHtml(html); + qx.html.Element.flush(); + + q(this.__embed.getContentElement().getDomElement()).getChildren("pre").setStyles({ + color: "#262626", + backgroundColor: "#EEE", + borderRadius : "4px", + padding: "7px" + }).filter("pre").forEach(function(el) { + q(el).addClass("javascript"); + window.hljs && window.hljs.highlightBlock(el); + }); + }, + + + __createButtonContainer : function() { + var pref = new qx.ui.toolbar.Button(null, "icon/22/actions/media-skip-backward.png"); + var update = new qx.ui.toolbar.Button("Help me out"); + var run = new qx.ui.toolbar.Button("Run", "icon/22/actions/media-playback-start.png"); + var next = new qx.ui.toolbar.Button(null, "icon/22/actions/media-skip-forward.png"); + this.__next = next; + + // tooltips + pref.setToolTipText("Previous step"); + update.setToolTipText("Replace the source code with a working copy"); + run.setToolTipText("Run the application"); + next.setToolTipText("Next step"); + + // states + pref.addState("left"); + update.addState("middle"); + run.addState("middle"); + next.addState("right"); + next.setIconPosition("right"); + + // constant width for all buttons + pref.setWidth(90); + update.setWidth(90); + run.setWidth(90); + next.setWidth(90); + + // align text middle + pref.setCenter(true); + update.setCenter(true); + run.setCenter(true); + next.setCenter(true); + + // enabled for next / pref + var self = this; + this.bind("step", pref, "enabled", {converter : function(data) { + return data > 0; + }}); + this.bind("step", next, "enabled", {converter : function(data) { + return Boolean(self.getTutorial()) && data < self.getTutorial().steps.length - 1; + }}); + + // next, pref control + pref.addListener("execute", function() { + this.setStep(this.getStep() - 1); + }, this); + next.addListener("execute", function() { + this.setStep(this.getStep() + 1); + }, this); + + // run / update events + run.addListener("execute", function() { + this.fireEvent("run"); + }, this); + update.addListener("execute", function() { + this.fireDataEvent("update", this.getTutorial().code[this.getStep()]); + }, this); + + // container + var container = new qx.ui.container.Composite(); + var layout = new qx.ui.layout.HBox(); + layout.setAlignX("center"); + container.setLayout(layout); + container.setPadding([0, 10, 10, 10]); + container.add(pref); + container.add(update); + container.add(run); + container.add(next); + + return container; + } + } +}); diff --git a/source/class/qxl/tutorial/view/Header.js b/source/class/qxl/tutorial/view/Header.js new file mode 100644 index 00000000..e42c7315 --- /dev/null +++ b/source/class/qxl/tutorial/view/Header.js @@ -0,0 +1,54 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2012 1&1 Internet AG, Germany, http://www.1und1.de + + License: + MIT: https://opensource.org/licenses/MIT + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Martin Wittemann (wittemann) + +************************************************************************ */ + +/** + * The Application's header + */ +qx.Class.define("qxl.tutorial.view.Header", +{ + extend : qx.ui.container.Composite, + + events : { + "selectTutorial" : "qx.event.type.Event" + }, + + /** + * @ignore(qxc) + */ + construct : function() { + this.base(arguments); + + this.setLayout(new qx.ui.layout.Canvas()); + this.setAppearance("app-header"); + + var title = new qx.ui.basic.Label("Live Tutorial"); + var select = new qx.ui.form.Button("Select Tutorial"); + select.setToolTipText("Choose another tutorial"); + select.setFont("default"); + select.setTextColor("black"); + select.addListener("execute", function() { + this.fireEvent("selectTutorial"); + }, this); + var version = new qxl.versionlabel.VersionLabel(); + version.setFont("default"); + + this.add(title, {left: 10, top: 5}); + this.add(select, {left: "40%", right: "40%"}); + this.add(version, {right: 10, top: 3}); + } +}); diff --git a/source/class/qxl/tutorial/view/SelectionWindow.js b/source/class/qxl/tutorial/view/SelectionWindow.js new file mode 100644 index 00000000..dc8add2f --- /dev/null +++ b/source/class/qxl/tutorial/view/SelectionWindow.js @@ -0,0 +1,130 @@ +/* ************************************************************************ + + qooxdoo - the new era of web development + + http://qooxdoo.org + + Copyright: + 2004-2012 1&1 Internet AG, Germany, http://www.1und1.de + + License: + MIT: https://opensource.org/licenses/MIT + See the LICENSE file in the project's top-level directory for details. + + Authors: + * Martin Wittemann (wittemann) + +************************************************************************ */ + +/** + * @ignore(tutorial) + */ +qx.Class.define("qxl.tutorial.view.SelectionWindow", +{ + extend : qx.ui.window.Window, + + + construct : function(desktopTutorials, mobileTutorials) { + this.base(arguments, "Select Tutorial"); + + // configure window + this.setModal(true); + this.setShowMaximize(false); + this.setShowMinimize(false); + this.setMovable(false); + this.setResizable(false); + + this.setLayout(new qx.ui.layout.Grid(10, 5)); + this.getLayout().setRowAlign(0, "center", "top"); + + this.__buttonFont = new qx.bom.Font(12, ["Lucida Grande", "DejaVu Sans", "Verdana", "sans-serif"]); + this.__buttonFont.set({ + color: "font", + lineHeight: 1.3 + }); + + // build the headlines + var desktop = new qx.ui.basic.Label("Desktop"); + desktop.setFont("bold"); + this.add(desktop, {row: 0, column: 0}); + + var mobileSupported = qxl.tutorial.Application.mobileSupported(); + var title = "Mobile" + (mobileSupported ? "" : " (unsupported browser)"); + var mobile = new qx.ui.basic.Label(title); + mobile.setFont("bold"); + this.add(mobile, {row: 0, column: 1}); + + this.__buildSelection(desktopTutorials, mobileTutorials); + + this.center(); + }, + + events : { + "changeTutorial" : "qx.event.type.Data" + }, + + members : + { + __buttonFont : null, + + __createButton : function(name, desc) { + var button = new qx.ui.form.Button( + name + "+ In this tutorial, we want to build a simple login form containing a text field for the user name and a password field for the password. Additionally, a button for the login is needed. +
++ Forms are abstract objects in qooxdoo which hold the input fields and buttons. As we need two input fields we should create them as well. After that, we can add these input fields to the form, as you can see in the following code snippet. +
+var form = new qx.ui.form.Form(); + +var userName = new qx.ui.form.TextField(); +form.add(userName, "Name"); + +var password = new qx.ui.form.PasswordField(); +form.add(password, "Password");+
+ Running this code creates the form, but does not show anything in the app. As described above, forms are abstract objects and do not contain any information on how to layout the form on the screen. For this, a form renderer can be used. +
++ Take a simple, one column renderer and render the form. +
+this.getRoot().add( + new qx.ui.form.renderer.Single(form), + {left: 10, top: 10} +);+
+ Running these two code snippets will render a simple form showing the two input fields. You can also see labels in front of each form item showing the name we gave it with the add
call. Give it a try and enter some values or even rename the labels in the code and run it again.
+
+ As a next step, we want to add the login button. For adding buttons, the form offers a separate method, which will be used in the following snippet. +
+var login = new qx.ui.form.Button("Login"); +form.addButton(login);+
+ Copy this code in front of the form rendering to make sure the renderer knows about the button. Run and see the new added Login button. +
++ But the button does not do much right now. We should add a listener to validate the form and send the login request. Of course, sending data would stretch this tutorial a bit too much so we simply show an alert. +
+login.addListener("execute", function() { + if (form.validate()) { + alert("send..."); + } +});+
+ Appending these code lines to the bottom of the whole sample will attach a listener to the button, which will be executed on tap but also on pressing enter when the button is focused. As you can see in the code, we only show the alert in case the validation reported back as valid. Of course, as we did not add any validation information, everything is valid currently! +
+ +We use two simple cases, the user name is required and the password field should at least have 6 characters.
++ Making the user name required is really easy. Just tell the user name object to be required. +
+userName.setRequired(true);+
+ Adding this line right after creating the text field will mark the field as required. Running the code now will show you a little red asterisk right beside the name of the field which marks it as required. Hitting the login button now without a user name will fail and highlight the input. Hovering will show a pop-up containing the error message. +
++ Adding a custom validator is also easy. Search for the line where we added the password field to the form and add a function as third parameter. This function will be your validator. The validator will have access to the current set value as its first argument. The new line could look like this. +
+form.add(password, "Password", function(data) { + return !!(data && data.length >= 6); +});+
+ After you have replaced the original add
call with the new one, give it a try and see that also the password field needs to be filled. Hovering the field does not show an error message, but we can add one in a single line of code.
+
password.setInvalidMessage("Password too short.");+
+ Adding this line after the password field fixes this issue. +
+ +Welcome to the first qooxdoo tutorial. As usual, this is a basic Hello World app which features a button and a listener on the button's execution.
+Let's get started by creating a simple button. Please copy the following line over to the source code editor on the top right.
+var button = new qx.ui.form.Button("Hello...");+
Hitting the run button now will not change anything in the application in the lower right corner because we simply created the button but did not add it to our application.
+this.getRoot().add(button, {left: 30, top: 20});+ Pasting this line right below the first line and hitting run will now shows the first button. As you see in the code, we placed the button relative to the root's top left corner. Try to change it a bit to see how the button can be positioned. + +
Having a button is a good first step but we wanted to react on taps as well. For that, qooxdoo offers an event. As a proof of concept, we simple show an alert to confirm that the listener has been executed. But instead of using the click
event, we use the execute
event, which will also be fired in case the user uses the keyboard instead of the pointer.
button.addListener("execute", function() { + alert("... World!"); +});+
Copy this code over and run it again. A tap on the button shows the alert message.
Congratulations! You have build your first Application using qooxdoo.
+ Single Value Binding is the basic concept behind all of qooxdoo's data binding mechanisms. But it is also a very useful helper during the development. In this tutorial, we connect a slider value to the text state of the button. +
++ The first step is to setup the basic UI. Therefore, we need a slider and a button next to each other. First, we create a slider with a width of 100 pixel and a range between 0 and 8. +
+var slider = new qx.ui.form.Slider(); +slider.setWidth(100); +slider.setMinimum(0); +slider.setMaximum(8); +this.getRoot().add(slider, {left: 10, top: 15});+
+ As you can see, we also add the slider to the root widget so running this code will already show the slider. But the button is still missing. Creating a button is also easy. +
+var button = new qx.ui.form.Button("x pieces"); +this.getRoot().add(button, {left: 120, top: 10});+
+ The text of the button should show how many pieces we have selected with the slider. As we did not set up the binding, a change of the slider does not change the buttons text. +
+ ++ After setting up the UI, we have two tasks left. First, we need to update the button's text as soon as we move the slider. For this we can use data binding. But we nee to know two things. Single Value Binding connects two properties of qooxdoo objects, no matter what objects. In our case, we want to connect the value property of the slider to the label property of the button. +
+slider.bind("value", button, "label");+
+ Adding this line to the bottom of the code will connect the two properties. Give it a try and run the sample. You will see that the button label changes right away to the value the slider currently has. Move the slider to see the label change. +
++ But that is not what we planed. We wanted to have a text like "x pieces" in the button. So we need a converter which will convert the value of the slider (which is a number) to the text we want to show. The converter can be added as a additional argument to the bind function. +
+slider.bind("value", button, "label", { + converter: function(data) { + return data + " pieces"; + } +});+
+ Replace the bind call we added with this one. The converter will add the missing text. These converters are really powerful because you can decide, based on the source's value, what to set on the target. +
+ +"+w.value+"
";u=v.firstChild.firstChild;v.firstChild.cN=r.cN;r.parentNode.replaceChild(v.firstChild,r)}else{u.innerHTML=w.value}u.className=t;u.result={language:s,kw:w.keyword_count,re:w.r};if(w.second_best){u.second_best={language:w.second_best.language,kw:w.second_best.keyword_count,re:w.second_best.r}}}function k(){if(k.called){return}k.called=true;var r=document.getElementsByTagName("pre");for(var p=0;p+ In this tutorial, we want to introduce you to qooxdoo mobile. As a first sample, we want to add a page to our mobile app showing one button. This button should bring up an alert window when pressed. +
++ Creating a page is like creating any other widget. As soon as we have this page, we need to tell the page manager to take care of it. Initially, we want to show this page as well. +
+var page = new qx.ui.mobile.page.NavigationPage(); + +this.getManager().addDetail(page); +page.show();+
+ Running this code shows a blank page, not even having a page title. Let's change that and add a page title. +
+page.setTitle("Hello World");+
+ Add this line between the creation of the page and the show call. This will set the title of the page. Run the sample to see the result. +
+ +
+ Next, we want to add a button. As mobile devices are usually not that performant, it is always a good idea to delay execution as much as possible. To make sure we don't create every widget on startup, qooxdoo offers an initialize
event which will be fired when the page needs to initialize. In our case, we use that to create our button and add it to the page's content.
+
page.addListener("initialize", function() { + var button = new qx.ui.mobile.form.Button( + "Hello..." + ); + page.getContent().add(button); +}, this);+
+ Add these lines of code to the sample right after setting the title (and before the show
call) and run it. It will show you your mobile app, a page with a button.
+
+ As a final step, we want to show an alert every time we tap on the button. For that, we need to add a listener to the buttons tap
event.
+
button.addListener("tap", function() { + alert("... World!"); + }, this);+
+ Place this code in the handler for the initialize
event, run your app and see the final result.
+
+ Mobile apps usually consist of many pages. In this tutorial, we want to show you how you can create two pages and link between them. We won't go into much detail about how a page is created, which we already covered in the Hello World tutorial. +
++ Lets get started with the first page. +
+var page1 = new qx.ui.mobile.page.NavigationPage(); +page1.setTitle("Page 1"); +this.getManager().addDetail(page1);+
+ This is the basic setup for our page. We add a button in the initialize
handler to jump to the next page.
+
page1.addListener("initialize", function() { + var button = new qx.ui.mobile.form.Button( + "Next Page" + ); + page1.getContent().add(button); +},this); +page1.show();+
+ Now, lets add the second page which is almost like page one. +
+var page2 = new qx.ui.mobile.page.NavigationPage(); +page2.set({ + title : "Page 2", + showBackButton : true, + backButtonText : "Back" +}); +this.getManager().addDetail(page2);+
+ The main difference to page one is that we tell the page to show a back button with a certain text. +
++ Of course, you will only see page one after running your app because we did not connect the buttons. +
+ +
+ The next step is to connect the pages. That means we need to tell the application to jump to the second page in case we press the button on the first page. Add a tap
listener to the button of page one in the initialize
handler.
+
button.addListener("tap", function() { + page2.show(); + }, this);+
Now run your code and tap the button. You will see that your second page will slide in as expected. But taping on the back button does not work like expected. That will be our next task, connecting the back button.
+page2.addListener("back", function() { + page1.show({reverse:true}); +}, this);+
Ad these lines of code after the creation of page two. As you see in the code, its like the listener we added to the button on the first page. The only exception is that we tell the show method to reverse the animation. Now give it a try, your final mobile app featuring two pages is ready!
+If you want to continue, try to add content to the second page like a qx.ui.mobile.basic.Label
, or add a third page.