tag:blogger.com,1999:blog-22976987704917016742024-03-12T20:53:23.074-07:00Code On TimeBuild amazing Universal Business Apps in minutes!Customer Servicehttp://www.blogger.com/profile/04471166550881539854noreply@blogger.comBlogger1005125tag:blogger.com,1999:blog-2297698770491701674.post-74042163455379374492021-12-14T14:11:00.086-08:002021-12-17T15:43:04.490-08:00December / January 2022 Roadmap<p>We are happy to introduce the <a href="https://codeontime.com/blog/2021/12/restful-apps-with-hypermedia" target="_blank">Level 3 REST API Engine</a>, the new amazing feature of Code On Time apps. Automatic production of <i>Progressive Web Apps</i> and the <i>barcode scanning with the device camera </i>will follow shortly </p><h2>Level 3 REST API Engine</h2><p>The work on our own content management system and numerous inquiries from customers have prompted us to build a new REST API Engine. It is built directly into the server-side framework and exemplifies an exceptional piece of technology. Your app converts into powerful middleware with just a few keystrokes. <b>The API of the app evolves as you create new data models and customize your app with actions and views.</b> The new engine classifies as the <i>Level 3 REST API </i>according to the <a href="https://martinfowler.com/articles/richardsonMaturityModel.html" target="_blank">Richardson Maturity Model</a>. </p><p>The <a href="https://en.wikipedia.org/wiki/HATEOAS" target="_blank">hypermedia </a>links are self-documenting the API. Developers can extend their own Code On Time app frontend with the help of the built-in RESTful interface. Alternatively the entire application can become the backend of a custom mobile or web client making HTTP requests to the REST API to read and write data.</p><p>Here is an example of an application resource with the hypermedia controls embedded in it. The singleton of a product has the hypermedia links for the SupplierID and CategoryID lookup fields. Links to “edit”, “replace”, “delete”, and execute a custom action “custom-action2” are also available with the corresponding HTTP methods.</p><div><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiP34WDmKGGCneaqddn8FWesP_U_4kQu8FCdVhiDJ7giObJ4kUlubrKSFf44w4w9RRB-SfeNN-nnb_H0Ltoyeisv6nFKtyTYdB4JvQZej6dAq1daWhwJm_sAIbjCaMgA8tIP8tIAJ3_MHb32zF0XDNicCCzsdWsfBl4EhSTZ0x4RVVdml97MLkdkuy91g=s1345"><img border="0" data-original-height="1345" data-original-width="663" src="https://blogger.googleusercontent.com/img/a/AVvXsEiP34WDmKGGCneaqddn8FWesP_U_4kQu8FCdVhiDJ7giObJ4kUlubrKSFf44w4w9RRB-SfeNN-nnb_H0Ltoyeisv6nFKtyTYdB4JvQZej6dAq1daWhwJm_sAIbjCaMgA8tIP8tIAJ3_MHb32zF0XDNicCCzsdWsfBl4EhSTZ0x4RVVdml97MLkdkuy91g=s16000" /></a></div><p>This is the same data item presented in the <i>editForm1 </i>view of the <i>Products </i>controller. Change the form and the API will change automatically.</p><div><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjmxHh1obs4iEwwLwflaGerQPKKkQ4jx3NFuz3_Q4tnS8088X_cUYACOmpaoqng2ccnEppjv2B2oJZsu3O9clOR43wmzuwascdrad1vfiwIayH-bl6HFhv5NAclJQZ07SjktGirAER9p4KSugt8txD25GfPvQbqf0ElySagDw3RkGh5_qUh1_nXC3nFmA=s1146"><img border="0" data-original-height="1019" data-original-width="1146" src="https://blogger.googleusercontent.com/img/a/AVvXsEjmxHh1obs4iEwwLwflaGerQPKKkQ4jx3NFuz3_Q4tnS8088X_cUYACOmpaoqng2ccnEppjv2B2oJZsu3O9clOR43wmzuwascdrad1vfiwIayH-bl6HFhv5NAclJQZ07SjktGirAER9p4KSugt8txD25GfPvQbqf0ElySagDw3RkGh5_qUh1_nXC3nFmA=s16000" /></a></div><br /><p>The <i>inventory </i>resource corresponding to the <a href="https://www.youtube.com/watch?v=wVyc0iGHrkw&list=PLy2g3SjvDe2b2cl9i0msBaMVLntQucZtb&index=43" target="_blank">dashboard </a>controller Inventory is presented next. It has <i>Categories</i>, <i>Products</i>, and <i>Suppliers </i>fields of the <i>dataview </i>type and an alternative <i>dashboard2 </i>view. </p><div><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiMzCWmvmLAydJvNXBqYHD_aWm455IlG6FGlNgdvUnEBq9qCYiuo38UjyGIWIAM01lS4rClNEuZaGqHGV9mxvSlEPvP0f1roW4i0MNRXsq3K1MvVFrCQpFLXs_bYqtznpy4zPCNfyz4D7LP0FvVFhJC__BYXkRywrjQ0E7CGmfmzDPT8CrHmBGH2vRurA=s1098"><img border="0" data-original-height="1098" data-original-width="574" src="https://blogger.googleusercontent.com/img/a/AVvXsEiMzCWmvmLAydJvNXBqYHD_aWm455IlG6FGlNgdvUnEBq9qCYiuo38UjyGIWIAM01lS4rClNEuZaGqHGV9mxvSlEPvP0f1roW4i0MNRXsq3K1MvVFrCQpFLXs_bYqtznpy4zPCNfyz4D7LP0FvVFhJC__BYXkRywrjQ0E7CGmfmzDPT8CrHmBGH2vRurA=s16000" /></a></div><p>This is how the <i>Inventory </i>dashboard looks like in the application when running in the development mode.</p><div><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjOl1iFU0iesoRnxi3764qdkInmozMehJPDs1lx5AuZPXpWBUJC_aTQpnWdOBxvJ8UpCrXb0EIPUblFolCbRr3k1W5LWMeqlpjqhDHMqauc48tnQAJ3-CuU5xm6e4lfmdENmD5swGZBXc5lshfHoYlbed4N1T2DqmFAWPA4E5aE9wK0506ut1WwRUcgPQ=s1146"><img border="0" data-original-height="945" data-original-width="1146" src="https://blogger.googleusercontent.com/img/a/AVvXsEjOl1iFU0iesoRnxi3764qdkInmozMehJPDs1lx5AuZPXpWBUJC_aTQpnWdOBxvJ8UpCrXb0EIPUblFolCbRr3k1W5LWMeqlpjqhDHMqauc48tnQAJ3-CuU5xm6e4lfmdENmD5swGZBXc5lshfHoYlbed4N1T2DqmFAWPA4E5aE9wK0506ut1WwRUcgPQ=s16000" /></a></div><br /><p>The standard frontend of your application provides the visual interpretation of its <i>REST API r</i>esources. Naturally you can use this frontend as the primary user interface for your application or create custom mobile or web apps using the technology of your choice.</p><p><br /></p><p>The new REST API engine produces the responses in JSON, Yaml, and XML formats.</p><p><br /></p><p>Future releases of the product will include a complete <a href="https://codeontime.com/blog/2021/12/restful-apps-with-hypermedia">GraphQL runtime</a> that will convert the queries and mutations into the internal <i>REST API </i>calls.</p><h2>Barcode Scanning With Device Camera</h2><p>Your apps will finally have an option to scan the barcodes and QR codes without relying on the external scanners. The powerful <a href="https://codeontime.com/blog/2020/05/tutorial-barcodes-qr-codes-and-rfid-tags">UI Automation and Kiosk UI</a> already available to the app developers are getting a boost! The QR code icon on the toolbar activates the camera-based scanner powered by the <a href="https://opensource.google/projects/zxing" target="_blank">Zxing </a>(zebra crossing) library. </p><p>The camera scanner icon is available when barcode support is enabled. Developers will also have an option to automatically activate the scanner when a particular form is displayed or a field is focused. The scanned barcodes and QR codes are placed in the barcode processing queue, which is also populated by the external scanners and readers.</p><p>The simple and powerful <i>IfThisThenThat </i>API allows creating complex rules that force the UI of the app to perform various actions in response to the contents of the barcode queue.</p><h2>Automatic Production of PWA </h2><p>We are finally bringing a unified native experience to Android, Chrome OS, and Windows. Code On Time apps are getting built-in support for<i> Progressive Web Apps </i>technology. Users running your application in Microsoft Edge and Google Chrome will see a prompt to install the app. Installed applications will have no address bar and will behave just like any native application does.</p><p>We will continue to support the <a href="https://www.youtube.com/watch?v=DqEpNX2IwQQ&t=3s" target="_blank">Cloud On Time</a> universal client for Apple and Mac OS platforms. </p><h2>Last But Not Least</h2><p>REST API engine provides the missing building block for the <i>Content Hub</i>, the new <i>Content Management System</i> (CMS) for Code On Time applications. The new CMS will infuse them with the community forum, help desk, blog, and documentation library. </p><p>Our website will move to our own technology. The documentation library and community forum will become integrated into <a href="https://my.codeontime.com">https://my.codeontime.com</a>. New live design environment <i>v9</i> integrates with the <i>Content Hub</i> to deliver the unmatched level of productivity when building applications with Code On Time. </p><p><br /></p>Customer Servicehttp://www.blogger.com/profile/04471166550881539854noreply@blogger.com0tag:blogger.com,1999:blog-2297698770491701674.post-81588243998724818902021-12-14T13:45:00.051-08:002021-12-17T13:56:58.860-08:00Price Changes<h2 style="text-align: left;"> “Code On Time” Price Changes</h2><p>The prices of our products will change on <b>February 1, 2022</b>. </p><p>The new price for Code On Time <b>Unlimited Edition </b>/ 1 user / 12 months of updates is<b> $1999 USD</b>.<br />The new price for Code On Time <b>Premium Edition</b> / 1 user / 12 months of updates is <b>$1199 USD</b>.</p><p>The prices for multi-user licenses for <i>Unlimited Edition </i>will also change to reflect the increase. </p><p>We are also introducing the <b>renewal pricing</b>. The renewal price will be what you have used to pay for the new product license prior to February 1, 2022. </p><p>For example, if you purchase Code On Time <i>Unlimited Edition </i>/ 1 user / 12 months of updates on or after <i>February 1, 2022 </i>for <i>$1999 USD</i>, then you will be able to get the product license renewal for <i>$1699 USD </i>if you choose to renew before <i>March 1, 2023</i>. </p><p>The <b>current product owners </b>will be able to renew the product for the <b>same price </b>it was purchased prior to February 1, 2022 if they do so <b>within 30 days </b>from the activation code <b>expiration date</b>. </p><p>The licenses will <b>remain perpetual</b>. You do not have to renew the license if you do not wish to receive the product updates. Your applications built with Code On Time will continue to work. The app generator will have the same level of features that were available at the time of activation code expiration. </p><p>The price increase is due to the following major enhancements:</p><p></p><ul style="text-align: left;"><li>Code On Time injects the <b>middleware </b>in the generated apps with the introduction of the <a href="https://codeontime.com/blog/2021/12/restful-apps-with-hypermedia">REST API engine</a>. This significantly <b>increases </b>the <b>value </b>of applications created by developers.</li><li>Code On Time will include <b> Progressive Web Apps </b>support in the generated applications, which will allow <b>installing </b>apps <b>natively </b>on Android, Chrome OS, and Windows.</li><li>Code On Time <b>V9 </b>introduces the new <b>Live Project Designer</b> integrated with online documentation, community forum, and help desk. This will increase <b>productivity </b>and <b>ease-of-use</b>.</li></ul><div></div><p></p><div>Please consult the <a href="https://codeontime.com/blog/2021/12/december-january-2022-roadmap">near term</a> and <a href="https://codeontime.com/blog/2021/12/roadmap-2022-2024">long term</a> product roadmaps for more information about the upcoming features and enhancements.</div><h2 style="text-align: left;">“Offline Sync” Price Changes</h2><p><b>Offline Sync Add-On</b> will be sold only in packs of <b>10-device perpetual licenses</b> for <b>$990 USD</b> per pack starting on <b>February 1, 2022</b>. The software will include 12 months of maintenance updates. </p><p>The add-on will be hard-wired to work with the particular Internet domain only. The domain will be specified by the customer at the time of purchase. The “wildcard” domains are allowed. The “localhost” domain is included. One time change of the domain is permitted. The license is bound to the server (domain). <a href="https://www.youtube.com/watch?v=7iOhaP6nOLI&list=PLy2g3SjvDe2bPlCqk2PDA_UEPsa9SbDcd&index=2&t=30s">Offline Sync Add-on</a> will work in <i>Progressive Web Apps</i> mode. The required software will be automatically installed on the device along with the app. </p><p>For example, if you purchase <i>5 packs </i>of <i>10-device perpetual licenses </i>for <a href="https://demo.codeontime.com">https://demo.codeontime.com</a> and include the add-on in the application, then up to 50 simultaneous client devices running the app frontend in offline/disconnected mode will be able to synchronize the data with this application. The same license will also work with the “localhost” domain for developers.</p><p><br /></p>Customer Servicehttp://www.blogger.com/profile/04471166550881539854noreply@blogger.com0tag:blogger.com,1999:blog-2297698770491701674.post-70416121753047060712021-12-14T13:31:00.071-08:002021-12-17T13:42:27.179-08:00Roadmap 2022/2024<p>This roadmap does not represent a guarantee that the features will be delivered on the specified dates as described in this document. The delivery dates may change, and features may be added or removed at any time. It is merely an outline of our thoughts for the future, and is subject to change at our discretion.</p><h2>Roadmap: January - April 2022 </h2><p><b>Full implementation of project configuration in the browser with v9 Live Project Designer. This will be followed by the official announcement of Code On Time v9. </b></p><p>The new Project Designer is activated directly in the “development” mode of the application. The screenshot of the app in the development mode is shown next. Application is sized to fit a particular device and orientation. </p><div><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjDkWOhFevnbyO8KV9Hx6yHX0bzhRhlBqrDkv4agbavLM9IZW2CgnHTAK-CzUAArN13b4X5p8EmYsIur6kG6_he13ZUI5_SImorjzP8g4Os7arDCBxdTJ86646N41nOd6ENjXIIuAM_lMxFKCwKUvlOfyjt0ULKY3RbZW4bEs9AH6bXoUW6SeUhFK7nsw=s1146"><img border="0" data-original-height="1019" data-original-width="1146" src="https://blogger.googleusercontent.com/img/a/AVvXsEjDkWOhFevnbyO8KV9Hx6yHX0bzhRhlBqrDkv4agbavLM9IZW2CgnHTAK-CzUAArN13b4X5p8EmYsIur6kG6_he13ZUI5_SImorjzP8g4Os7arDCBxdTJ86646N41nOd6ENjXIIuAM_lMxFKCwKUvlOfyjt0ULKY3RbZW4bEs9AH6bXoUW6SeUhFK7nsw=s16000" /></a></div><br /><p>The main elements of the Project Designer are the <i>Project Explorer</i> and <i>Properties Window</i>. Both are activated in the sidebar that overlays the live application. The end user can inspect any visible user interface element of the application with a click. <i>Project Explorer</i> will synchronize the hierarchy of the project configuration with the developer’s selection. <i>Properties Window </i>will display all available properties of the selection. Standard properties such as Label or Header Text will be presented together with the “virtual” properties derived from the various tags supported in the application framework. Hunting for the tag description in the blog posts will be no more!</p><p><i>Project Explorer</i> and <i>Properties Window </i>are driven by the project configuration database. The first components of the database will begin shipping with the regular product releases by the end of January 2022. The first target of the live project configuration will be the contents of <i>~/touch-settings.json </i>and the main project settings currently configured in the Project Wizard. The developers will be able to continue using the current project designer and the new browser-based designer simultaneously. The browser-based designer will communicate with the <i>~/bin/addon.appbuilder.dll </i>through the REST API. This DLL is required only during development and works if Code On Time is installed on the development machine. The DLL is removed from the output when the app is published for deployment.</p><p>The project configuration database is also shared with the <b>new content management system </b>that replaced the current <a href="https://codeontime.com">https://codeontime.com</a> and <a href="https://my.codeontime.com">https://my.codeontime.com</a>. The content management system (CMS) is implemented as a Code On Time application. It will offer the community forum, help desk, blog, and documentation library. The CMS is <b>integrated with</b> the <b>Live Project Designer</b>. Developers will jump straight to the relevant documentation and will have an option to contribute the content, start discussion on the community forum, or open a help desk ticket. The new CMS will be offered as an add-on for purchase to help infuse the powerful content publishing features into custom applications created with Code on Time. The live project designer itself will also be packaged as an add-on for integration into custom apps built with Code On Time. </p><p>The current user interface of Code On Time generator will become hidden when the new <i>Live Project Designer </i>meets and exceeds the configuration capabilities of the “original”<i> Project Wizard</i> and <i>Project Designer</i>. The app generator will put itself into the icon tray when started. Management of projects and configuration will become entirely browser-based. We expect to complete this process over multiple regular product releases by the <b>middle of Spring 2022</b>. The app generator project number will change to v9.0.0.0 at that time.</p><div><h2>Roadmap: Summer - Fall 2022</h2><div><b>Transition of HTTP request/response processing of the server-side framework to a shared class and implementation of this class for .NET Core. This will enable cross platform deployment to Windows, Mac OS, and Linux. Code On Time version number will switch to v10.</b></div><div><br /></div><div>We will begin the transitioning to .NET Core right on the heels of the v9.0.0.0 release to production. The server-side framework in the foundation of the generated application is overriding the handling of request/response by .NET Framework. First, the server-side code references to <i>HttpContext </i>class and its various properties will be replaced with the new <b>wrapper class</b> implementation. Next, we will migrate an app created with Code On Time to the <b>.NET Core 6</b>. The wrapper class will be changed to make use of the .NET Core facilities. Finally, a<b> new target</b> will become available in the project configuration settings as we put together the new code generation templates. </div><div><br /></div><div>The changes will not affect the application framework and will not require any additional knowledge from developers. Selection of the .NET Core as the target for the project will produce the output that can be deployed to Windows, Mac OS, and Linux. We expect to complete the work before the end of the year 2022. </div><div><br /></div><div>Code On Time <b>v9</b> allows configuration of the apps entirely in the browser.</div><div><br /></div><div>Code On Time <b>v10</b> makes it possible to deploy the server-side components of applications on multiple operating systems.</div></div><div><h2>Roadmap: Winter - Summer 2023</h2><div><b>The app generator will migrate from .NET Framework to .NET Core and allow cross platform development on Windows, Mac, and Linux. Code On Time version number will switch to v11.</b></div><div><br /></div><div>Cross platform frontend and its development tools along with the cross platform deployment will leave behind the only element of Code On Time tooling tied to Windows - the app generator itself. Presently the app generator is implemented as the <i>Windows Forms Application</i> with the <i>Project Wizard </i>and <i>Project Designer </i>with the <i>WebBrowser </i>control instances hosting the locally stored HTML files to enable the project configuration. The code generator can also run in the command-line mode to perform various tasks. </div><div><br /></div><div>With the release of Code On Time v9 the “original” <i>Project Wizard </i>and <i>Project Designer </i>will become dormant since the entire project configuration process will be browser-based. Instead the command-line capabilities of the app generator will be heavily in use. </div><div><br /></div><div>Our research shows that the implementation of all tasks can be ported to the .NET Core. Successful migration will make Code On Time into a fully cross-platform development environment with the cross platform deployment of the frontend and backend. </div><div><br /></div><div>Cross platform server-side code can be deployed in a container to various cloud providers. The cross-platform frontend will not know the difference given that it can also execute in the offline/disconnected mode. </div></div><div><br /></div><div><h2>Roadmap: Fall 2023 - Winter 2024</h2><div><b>Visual Database Schema Builder. Hosted version of Code On Time becomes a reality. </b></div><div><br /></div><div>Extending the <i>Live Project Designer</i> with the ability to create data models on top of the automatically generated database tables appears to be the next logical step. Our <a href="https://www.youtube.com/watch?v=dP3yicSmlfE&list=PLy2g3SjvDe2b2cl9i0msBaMVLntQucZtb&index=10" target="_blank">Model Builder</a> makes use of the existing relational databases to create the denormalized views of data suitable for consumption by human beings through the user interface. </div><div><br /></div><div>Code On Time will introduce the <i>Visual Database Schema Builder</i> that will automatically create the corresponding models and physical database tables. Multiple database engines will be supported. The schema builder will create the database tables with the structure “preferred” by Code On Time data models. Tight integration with the Model Builder will radically simplify the app development. </div><div><br /></div><div><b>Visual Database Schema Builder</b> and <b>Live Project Designer </b>will deliver the enterprise-quality application production in the hands of the developers with any level of expertise. Code On Time will be offered a <b>cloud container </b>available with a <b>subscription </b>and also as a <b>standalone tool </b>that is available today!</div></div><div><br /></div>Customer Servicehttp://www.blogger.com/profile/04471166550881539854noreply@blogger.com0tag:blogger.com,1999:blog-2297698770491701674.post-29290518012147184492021-12-14T00:09:00.006-08:002021-12-17T10:19:55.040-08:00RESTful Apps With Hypermedia<p>Code On Time release <a href="https://codeontime.com/releases/application-generator">8.9.24.0</a> creates apps with the hypermedia-enabled <b>REST API </b>engine. The hypermedia controls elevate the engine to the Level 3 of <a href="https://martinfowler.com/articles/richardsonMaturityModel.html" target="_blank">Richardson Maturity Model</a>. </p><p>The new REST API engine significantly increases the value of your applications. It also offers new opportunities to leverage your Code On Time expertise in modern application development. The best part is that you accomplish both with just a few keystrokes!</p><div><h2>Architecture of Code On Time Applications</h2><div>Applications are composed of the server-side code and JavaScript-based frontend with the beautiful and responsive user interface. The frontend operates in any modern web browser and is capable of running in a completely disconnected mode on the native devices. The frontend makes HTTP calls into the server-side code to read and write data. </div><div><br /></div><div><i>Data Aquarium</i> is the custom framework in the core of the server-side code. It provides a powerful foundation for application of any size. <a href="https://www.youtube.com/watch?v=dP3yicSmlfE&list=PLy2g3SjvDe2b2cl9i0msBaMVLntQucZtb&index=10" target="_blank">Model Builder</a>, <a href="https://www.youtube.com/watch?v=Qh9TCyxRnKI&list=PLy2g3SjvDe2b2cl9i0msBaMVLntQucZtb&index=25" target="_blank">Access Control Rules</a>, and <a href="https://www.youtube.com/watch?v=5_DUqb3SxkI&list=PLy2g3SjvDe2b2cl9i0msBaMVLntQucZtb&index=12" target="_blank">Data Controller Virtualization</a> give developers the tools to build out the application data presentation and processing. Custom business rules are written either in SQL or in the implementation language of the app (C# or Visual Basic). The framework provides the RPC-style endpoints for the frontend to request data and execute actions over HTTP. </div><h2>Server-Side Code as a RESTful App</h2><div>Previously the frontend of a Code On Time application was the only client of the server-side code. The new REST API engine extends the applications to the infinite number of clients capable of making HTTP requests. The response data is returned in JSON, Yaml, or XML formats. Each response includes the hypermedia controls providing the clients with the options to navigate the resources and to change the state of data. </div><div><br /></div><div>Here is an example of the GET request to the REST API engine via the standard <i>/v2</i> endpoint. The response is presented in the <a href="https://www.postman.com/" target="_blank">Postman</a>, the popular API development tool. The “self” link in the “shippers” key suggests the means to obtain the corresponding data. The “first” link will lead to the first page of the data items. The “schema” link will assist in learning more about the data structure.</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjUdAGEXBwuDlvhtlTG5MLeJ_IFy78LV-4PCOhPi5VKdHwdPy-p-z0Fjt_EqzSwR1Nm2HmmC8LeES04789KFrElKKQeD6dLbTVhLG1lwoSUKm85iamod1iUKL-xVVya4pcabgZbfdmwp9pH8O3RMAn-YkMK0o6hmLDK1iNo10f5SQdEKbA7M9YGNvCqXw=s501"><img border="0" data-original-height="448" data-original-width="501" src="https://blogger.googleusercontent.com/img/a/AVvXsEjUdAGEXBwuDlvhtlTG5MLeJ_IFy78LV-4PCOhPi5VKdHwdPy-p-z0Fjt_EqzSwR1Nm2HmmC8LeES04789KFrElKKQeD6dLbTVhLG1lwoSUKm85iamod1iUKL-xVVya4pcabgZbfdmwp9pH8O3RMAn-YkMK0o6hmLDK1iNo10f5SQdEKbA7M9YGNvCqXw=s16000" /></a></div><div><br /></div><div><div>Follow the “self” link and you will get the response presented next. It includes the “collection” of items. Each item is provided with its own hypermedia controls. In this instance only the “self” link is available. The entire collection also has the hypermedia explaining how the data was obtained (the “self” link), how to transition to the first page of data (the “first” link), and how to create a new item with the POST method (the “create” link).</div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgxP0zZGrs8gh_nwPArLHhTxVoo8iL-q1YyY3BXfiaXgUWGIWaGrBOKyNPiMHwmShZJ1vbWm-I0D0pM_wuDc78Rrpab7Y9Y1rhecmcACPp1ILoy2lvQG-33YpG_MMvJFXOENIGEcnokQKwnepquCRA_p3l4DLJMu4Jkf_hO36xU6M7J8hF-nN3BAzPJYw=s1074"><img border="0" data-original-height="1074" data-original-width="775" src="https://blogger.googleusercontent.com/img/a/AVvXsEgxP0zZGrs8gh_nwPArLHhTxVoo8iL-q1YyY3BXfiaXgUWGIWaGrBOKyNPiMHwmShZJ1vbWm-I0D0pM_wuDc78Rrpab7Y9Y1rhecmcACPp1ILoy2lvQG-33YpG_MMvJFXOENIGEcnokQKwnepquCRA_p3l4DLJMu4Jkf_hO36xU6M7J8hF-nN3BAzPJYw=s16000" /></a></div><div><br /></div></div><div><div>Follow the “create” link with the POST HTTP method. The engine will respond with the 403 HTTP error explaining that the field <i>companyName </i>is expected in the body of the request. The data schema is also included.</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjQIu9QdD3xhzQ7aHTlOcecGFo6uEl5sYomAcTdMfp86rYSForJ7Y2AS1qATgGCeL5oEVV5O2sj3GFlD739HCTdMtDq8P9T-mIhMlIGGa8zEA9q2N3E6Uonyl55c4yqcoUBsBqwjGZYTx0KN8fY_-rd5iA8HeZxIYfANBV9shSFL3_rZ-9UqLp3kgKtVA=s811"><img border="0" data-original-height="811" data-original-width="568" src="https://blogger.googleusercontent.com/img/a/AVvXsEjQIu9QdD3xhzQ7aHTlOcecGFo6uEl5sYomAcTdMfp86rYSForJ7Y2AS1qATgGCeL5oEVV5O2sj3GFlD739HCTdMtDq8P9T-mIhMlIGGa8zEA9q2N3E6Uonyl55c4yqcoUBsBqwjGZYTx0KN8fY_-rd5iA8HeZxIYfANBV9shSFL3_rZ-9UqLp3kgKtVA=s16000" /></a></div><br /><div><div>Let’s define the request body with the <i>companyName </i>and <i>phone </i>fields. Execute POST and the API will respond with 201 HTTP code indicating that the resource was created. The hypermedia controls give options to access the “collection” of items and to get the “first” page of data. We can also “edit”, “replace”, and “delete” the resource.</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/a/AVvXsEh-sB10VM4hp1cvTvQYHzu-iX6l3fJDBKmVDr1QAaj8SUWmBgt2Ak1tDoSBTEDgeKPOe6Z-z6T6GyKflHgHVNBctXPtzRWe5rW2afkSSk3F5ncHJ0p__4VdqVEXe9KN6DkoJJagTGfvky_qiNJZazFT4EfnWrfWdKxiVwEnLjGDwCYIB5tBefF9yxTucg=s924"><img border="0" data-original-height="924" data-original-width="607" src="https://blogger.googleusercontent.com/img/a/AVvXsEh-sB10VM4hp1cvTvQYHzu-iX6l3fJDBKmVDr1QAaj8SUWmBgt2Ak1tDoSBTEDgeKPOe6Z-z6T6GyKflHgHVNBctXPtzRWe5rW2afkSSk3F5ncHJ0p__4VdqVEXe9KN6DkoJJagTGfvky_qiNJZazFT4EfnWrfWdKxiVwEnLjGDwCYIB5tBefF9yxTucg=s16000" /></a></div><div><br /></div><div><div>Let’s follow the “edit” link to change the phone number. We will need to execute the PATCH HTTP method for this link. The resource will change accordingly. </div></div><div><br /></div><div class="separator"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgRSfUoko45l4RxVz9ZB0s-czqDyVnp5VI3UCqw5CMs11Ca9Cqo_HqYQWstxLT3jBTbgV9bcBj_It77SXkLQWi9yHnERemnhQbLSqsQalLcdeXwnqKizNaccpu8GQsyUKsIUxDtdMo6cL6_Dy3xYIU1y_gAeAKnWewydFgyyNhka9Ev-QTHkErfuyvNFg=s906"><img border="0" data-original-height="906" data-original-width="615" src="https://blogger.googleusercontent.com/img/a/AVvXsEgRSfUoko45l4RxVz9ZB0s-czqDyVnp5VI3UCqw5CMs11Ca9Cqo_HqYQWstxLT3jBTbgV9bcBj_It77SXkLQWi9yHnERemnhQbLSqsQalLcdeXwnqKizNaccpu8GQsyUKsIUxDtdMo6cL6_Dy3xYIU1y_gAeAKnWewydFgyyNhka9Ev-QTHkErfuyvNFg=s16000" /></a></div><br /><div><div>Now destroy the resource by following the “delete” link with the DELETE method. The response with the HTTP code 200 will present you with the links to navigate to the “collection” or the “first” page of data.</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/a/AVvXsEg1t6v0VQ48TaDnUTsQ_YBay4eFFglfhUcJd1spzQ4ftMI1jHDgRSGxJuXWh4Fw76G9MnleYzl5HsCuYusBvLBcp7VnIHdmOUQ8_JTSvR-SH38FTXzuWREHMbqYHdG4ocQHJrC3hMzMTaFuOP28DjXWNxMmajNJXZK0fvtjjhV_5-enZu9dMIPPv5O8tQ=s438"><img border="0" data-original-height="417" data-original-width="438" src="https://blogger.googleusercontent.com/img/a/AVvXsEg1t6v0VQ48TaDnUTsQ_YBay4eFFglfhUcJd1spzQ4ftMI1jHDgRSGxJuXWh4Fw76G9MnleYzl5HsCuYusBvLBcp7VnIHdmOUQ8_JTSvR-SH38FTXzuWREHMbqYHdG4ocQHJrC3hMzMTaFuOP28DjXWNxMmajNJXZK0fvtjjhV_5-enZu9dMIPPv5O8tQ=s16000" /></a></div><div>Retry the same request and the HTTP response 404 will let you know that the resource does not exist.</div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhLUAtOTF8YYFc2D5FoNC2qF-t40onv_FpQJYtwkRlzjBtrZBfrDuZYtXfmeJy3-YIknunZ8Bxsh2plbEvI4xgvjP2Yoz4BlBdWapDwY-nA6Wapa5g6dhNMDjF2Usyec8BB4jFTYjfNBL94kzaSn5c0xY_2o4n_d2tsKbInPav-NqZdVG7Y6GuICkbVUw=s572"><img border="0" data-original-height="414" data-original-width="572" src="https://blogger.googleusercontent.com/img/a/AVvXsEhLUAtOTF8YYFc2D5FoNC2qF-t40onv_FpQJYtwkRlzjBtrZBfrDuZYtXfmeJy3-YIknunZ8Bxsh2plbEvI4xgvjP2Yoz4BlBdWapDwY-nA6Wapa5g6dhNMDjF2Usyec8BB4jFTYjfNBL94kzaSn5c0xY_2o4n_d2tsKbInPav-NqZdVG7Y6GuICkbVUw=s16000" /></a></div><br /><div><h2>Working With Hypermedia</h2><div><i>Hypermedia as the Engine of Application State</i> (HATEOAS) is the core feature of the REST API in the Code On Time applications. The hypermedia links are created dynamically to represent the state of a resource. The REST client needs only the basic understanding of the hypermedia to use the API. The clients programmed to use the hypermedia links are decoupled from the hard-coded URLs and can evolve independently from the server-side application.</div><div><br /></div><div>Data View fields are contributing links to the <i>details </i>of the singleton <i>master </i>resources. Additional views in a data controller will contribute “collection-”, “first-”, and “create-” links. Custom actions will also supply their own links. <a href="https://www.youtube.com/watch?v=5_DUqb3SxkI&list=PLy2g3SjvDe2b2cl9i0msBaMVLntQucZtb&index=12" target="_blank">Data Controller Virtualization</a> is instrumental in providing the precise set of the resource hypermedia links that match the user identity of the request. <a href="https://www.youtube.com/watch?v=Qh9TCyxRnKI&list=PLy2g3SjvDe2b2cl9i0msBaMVLntQucZtb&index=25" target="_blank">Access Control Rules</a> are limiting the data items presented in the responses. </div><div><br /></div><div>This is the example of the “supplier” singleton resource with the additional “self-”, “collection-” and “products” links.</div></div><div><br /></div><div class="separator"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhdT3hl_yW4EwHONlOj9kiRo8okZ9-hB5uMAeXFHvDLAHY_L2s3hQKJPdbu5FdPGXXLCAPjpQ0TjuaH2t0MMO-x7pTN3Nd3RLxRTm99BIbuLhzd1R7KymzsZr0R4fkNNvk_TjBQyxKKLoU2-GVvVr7wvj61ofxrI1eCOgIuiJ_PQzWdpSSKWLqTrAg9Cg=s1297"><img border="0" data-original-height="1297" data-original-width="566" src="https://blogger.googleusercontent.com/img/a/AVvXsEhdT3hl_yW4EwHONlOj9kiRo8okZ9-hB5uMAeXFHvDLAHY_L2s3hQKJPdbu5FdPGXXLCAPjpQ0TjuaH2t0MMO-x7pTN3Nd3RLxRTm99BIbuLhzd1R7KymzsZr0R4fkNNvk_TjBQyxKKLoU2-GVvVr7wvj61ofxrI1eCOgIuiJ_PQzWdpSSKWLqTrAg9Cg=s16000" /></a></div><br /><div>The “products” links are <i>embeddable </i>in the resource when specified in the <i>_embed </i>parameter of the request URL. Here is the response to the request that uses the parameter and also excludes the hypermedia from the output with <i>_links=false</i> specified in the URL. </div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgJ68vEAsUIEO_mN-wvQPmYP9kZAJzntQbQL2_jsHmnAk--Iz0U2OwJoip6Ep3w1wnnv8-Uu8mZJGLa4GF8FDr7Xjx3hvPN88tGCm0H6UcK0xkw_IGaK7C6PsqbagO4S5uU6EWpXOWD03wZVkvTElAzAjcZ_e8r6_NDHTz1yCdGNKLRkZcyFRbzwT7nFA=s1117"><img border="0" data-original-height="1117" data-original-width="582" src="https://blogger.googleusercontent.com/img/a/AVvXsEgJ68vEAsUIEO_mN-wvQPmYP9kZAJzntQbQL2_jsHmnAk--Iz0U2OwJoip6Ep3w1wnnv8-Uu8mZJGLa4GF8FDr7Xjx3hvPN88tGCm0H6UcK0xkw_IGaK7C6PsqbagO4S5uU6EWpXOWD03wZVkvTElAzAjcZ_e8r6_NDHTz1yCdGNKLRkZcyFRbzwT7nFA=s16000" /></a></div><div>The links above are excluded to make it easier to see the shape of data. If you are not convinced that programming the clients to use the hypermedia is a good idea, then specify the <i>_links=false</i> parameter in the URL of your requests. Hypermedia is still instrumental in understanding the API and resources.</div><h2>Over-Fetching, Under-Fetching, and GraphQL</h2><div>Facebook (Meta) has pioneered the <a href="https://graphql.org/" target="_blank">GraphQL </a>query language that has allowed it to unify the hundreds of the in-house APIs and eliminate the over-fetching and under-fetching of data. The term “over-fetching” generally refers to the REST APIs returning more data than the client needs. The response above pulls all fields of the supplier and products even though only some of the data may be needed for a particular client. Under-fetching describes the situation when the complex clients are required to make multiple calls to the API to pull the full set of required data.</div><div><br /></div><div>The <i>Data Aquarium</i> framework in the foundation of Code On Time applications was designed to prevent over-fetching by the frontend. The REST API possesses the same gift. Developers can specify the <i>fields</i> parameter to represent the required fields in the GraphQL query style. The <i>fields </i>parameter parser will automatically configure the <i>_embed </i>parameter behind the scene. The hypermedia links are excluded in the response shown in the screenshot to improve the readability. You can see that the shape of data matches exactly the query in the <i>fields</i>.</div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/a/AVvXsEg3QOvZoyHgKHazrkUQKZvsWeuicds-GlfP7AtaFD2-3GtKmSOTcT_KWS7KS7R_QzIogVwUNqb5l3VsJNT_zr18ZQL2ji3n_WazYjWeuZRmhrcJXsavdt-XltC97PhOOydwmL-wz8qkS7a2Pj658ZlP3Uhb9Ufqejugc0zmUj1P-BLNrWXIEBU1SsxHmw=s829"><img border="0" data-original-height="829" data-original-width="810" src="https://blogger.googleusercontent.com/img/a/AVvXsEg3QOvZoyHgKHazrkUQKZvsWeuicds-GlfP7AtaFD2-3GtKmSOTcT_KWS7KS7R_QzIogVwUNqb5l3VsJNT_zr18ZQL2ji3n_WazYjWeuZRmhrcJXsavdt-XltC97PhOOydwmL-wz8qkS7a2Pj658ZlP3Uhb9Ufqejugc0zmUj1P-BLNrWXIEBU1SsxHmw=s16000" /></a></div><br /><div><div>A space or comma separated list of field names can be specified in the <i>fields </i>parameter when only the main resource data is needed.</div><div><br /></div><div>Fragment <i>products {unitPrice productName categoryId { picture description}} </i>specified in the fields query is instructing the <i>REST API Engine </i>to follow the hypermedia link to the <i>products </i>and then to follow the link to the <i>categoryId </i>for each product. This solves the problem of under-fetching by incorporating the entire data set in the response of a single request. </div><div><br /></div><div><div>Filtering and sorting on each level of the query graph is also supported.</div><div><br /></div><div>The rigorous type checking of the request payload against the resource schemas is assisting developers in creating error-free requests.</div></div><h2>Why Are We Building It?</h2><div>The long-time fans follow the saga of our effort to rebuild the new community site. We have designed an ambitious content management system (CMS) called the <i>Content Hub</i>. This CMS can be integrated into any application created with Code On Time to infuse them with the built-in community forum, help desk, blog, and documentation platform. We are getting ready to roll it out soon! The new REST API is the foundation of the <i>Content Hub</i> backend.</div><div><br /></div><div>The REST API engine also answers the persistent stream of requests from our customers to allow taking advantage of the data services of the applications they create. The new API is built on top of the HTTP architecture, making use of the resource-based URLs, HTTP methods, and content caching. The hypermedia makes it uniquely easy to learn and use. The REST API engine turns Code on Time into the <i>middleware </i>provider, while the app developers are becoming the expert <i>backend gurus</i>. </div><div><br /></div><div>Code On Time applications can serve as the backend for custom mobile and web apps, cloud process orchestration services, and much more. Start selling your data and business logic with state-of-the-art technology!</div><div><br /></div><div>Our previous roadmaps have pointed to <a href="https://graphql.org/" target="_blank">GraphQL </a>as the core backend technology for Code On Time applications. The query demonstrated in the discussion of over-fetching is written with the GraphQL syntax. The follow-up releases will introduce the full GraphQL runtime for queries and mutations with the automatic generation of data and input types. The runtime will automatically resolve queries into the REST API engine requests. </div><div><br /></div><div><i>Assistant UI</i>, the new text-based user interface for Code On Time applications is also in the works. It will allow the end users to text, email, and talk to your applications with the help of hypermedia!</div><h2>RESTFul App Security</h2><div>REST API engine must be explicitly enabled by setting the <i>server.rest.enabled</i> option to <i>true</i>. All data controllers will become accessible via the hypermedia links in the /v2 application endpoint unless restricted to a specific subset in the settings.</div><div><br /></div><div>The authorization of the requests is mandatory. API keys can be listed explicitly in the settings or retrieved from the database. Each key must be associated with a particular user name. The keys will work great with the server-to-server communications. For example, a cloud function can invoke a custom method of a particular resource to cause the application to perform the background processing. API keys can be passed in the request header<i> X-Api-Key </i>or as <i>api_key </i>parameter in the URL. The latter will work best when submitting the data from the anonymous HTML forms.</div><div><br /></div><div>If the “bearer token” authorization is enabled, then a dedicated “authorize” hypermedia link will become available in the<i> /v2</i> endpoint. The link will allow the user to sign in and obtain an access token via the OAuth protocol. This authorization method works best for standalone mobile and web applications.</div><div><br /></div><div>The client-side business rules of the Code On Time app frontend can invoke the <i>$app.restful </i>function to access the REST API via <i>fetch</i>. The access token of the logged in user is automatically obtained from Touch UI. The function will also renew the access token when needed. </div><div><br /></div><div>Developers may opt to create the frontend pages without Touch UI by placing the <i>data-user-interface=”custom”</i> attribute on the body element. The page will render as-is when the attribute is detected. Custom JavaScript and CSS libraries can be linked to such pages as needed to create a unique presentation in the frontend. Link the file <i>~/js/sys/restful-2.0.js</i> to the page to make it possible to invoke <i>$app.restful </i>and access the REST API of the application with the current user identity. The pages with the custom user interface will co-exist with the Touch UI pages of the application and share the common login screens.</div></div>Customer Servicehttp://www.blogger.com/profile/04471166550881539854noreply@blogger.com0tag:blogger.com,1999:blog-2297698770491701674.post-24657288786168203742021-10-04T12:59:00.061-07:002021-10-05T01:39:52.563-07:002-Factor Authentication, "Actions" Lookup Style, Tap to Copy, Login Responses<p> Code On Time release 8.9.23.0 is introducing the enterprise-grade security feature that helps secure the user accounts. <a href="https://codeontime.com/blog/2021/09/2-factor-authentication">2-Factor Authentication</a> is opt-in by default. It can also be applied to all users accounts in the existing and new apps automatically. Another highlight of the release is the option to inject the actions directly into the flow of the data fields in the forms. Multiple enhancements and bug fixes are also included in this release.</p><h2>2-Factor Authentication</h2><p>The new feature will require the verification code to be entered after the valid combination of username and password was provided by the user during login. The verification code can be delivered by an authenticator app installed on the personal mobile device. Other options include an email, text message, or voice call. Developers may even choose to hide the password field in the login form if the 2-Factor Authentication setup mode is automatic. </p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEje2TRkgSiep-bwhwTsh6xQZxG90YVBn86-oN6BeaQQ_z4QUUAYh4NoFuV9Mt-t0JcS9tpfP2l9J31FMypD3grz-6ynlxSY9G52TEOvTzfykpVLFt3CdD0rtGBm4JYR7ntqVdHZNfz3pACz/s859/01-2FA-small.png"><img border="0" data-original-height="800" data-original-width="859" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEje2TRkgSiep-bwhwTsh6xQZxG90YVBn86-oN6BeaQQ_z4QUUAYh4NoFuV9Mt-t0JcS9tpfP2l9J31FMypD3grz-6ynlxSY9G52TEOvTzfykpVLFt3CdD0rtGBm4JYR7ntqVdHZNfz3pACz/s16000/01-2FA-small.png" /></a></div><br /><p>The new multi-factor authentication enhances the protection of the user accounts. This feature was sponsored by Peter Marchal of Wonderland Office, Belgium. </p><div><h2>“Actions” Lookup Style</h2><div>The new lookup style <i>“Actions”</i> makes it easy to <a href="https://codeontime.com/blog/2021/10/actions-lookup-style">inject the actions in the flow of data fields</a> of a form. Action buttons placed right next to the relevant data fields gain better context and improve the user experience. The visibility of the individual action is controlled by <i>“When…” </i>properties associated with the action. The visibility of the entire cluster of action buttons is controlled through the <i>Visible When </i>property of the data field that has its lookup style set to <i>Actions </i>and the <i>Name </i>set to match the <i>Id </i>of the corresponding action group. </div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSH7cPmo_2n59THdZ9hYjksIHkQPEhnT_8a7_wy0r2zkoJItpMFKkofvuCF2_ejkIGimGeXMsUEj7u331Fy5culiQhLyjYyFTIP686XG435n9UltPbwKTFdJ7GhKLrPUSYbwUHJCPB1_Qt/s1081/02-text-action-copy.png"><img border="0" data-original-height="968" data-original-width="1081" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSH7cPmo_2n59THdZ9hYjksIHkQPEhnT_8a7_wy0r2zkoJItpMFKkofvuCF2_ejkIGimGeXMsUEj7u331Fy5culiQhLyjYyFTIP686XG435n9UltPbwKTFdJ7GhKLrPUSYbwUHJCPB1_Qt/s16000/02-text-action-copy.png" /></a></div><div><br /></div><div><h2>Tap to Copy</h2><div>The new tag text-action-copy will cause the “Copy” button displayed next to the data field value. Tapping or clicking on the button will cause the field value to be copied into the clipboard. See this feature in action in the screenshot above. The text is copied to the clipboard and also displayed in the notification at the bottom of the screen when the button is clicked.</div><h2>Custom Login Responses</h2><div>If the user login has failed, then the generic message “Your user name and password are not valid” is displayed by the apps. If the login was successful then the user is silently signed in. Sometimes a custom message or system response is desired. </div><div><br /></div><div>Consider the following examples:</div><div><ul><li>The user account is locked and it is preferable to let the user know what actions must be performed to recover the account. </li><li>Developers may need to inform the user about the number of remaining login attempts before the account is locked.</li><li>Multi-factor authentication must force the user to enter the verification code if the login was successful. </li></ul></div><div>Learn about <a href="https://codeontime.com/blog/2021/10/custom-user-login-responses">Custom Login Responses</a> in Code On Time apps.</div><h2>Releases Notes</h2><div>The the following features, enhancements and bug fixes are included in the release:</div><div><div><ul><li>(Classic UI) Removed the link that allowed downloading the import template. </li><li>(Touch UI) Fixed the incorrect reference to the API function in the import processor. This was causing the error with the long running imports when the status was updated.</li><li>(App Gen) Replaced the legacy community reference with my.codeontime.com.</li><li>(Virtual Keyboard) The keyboard is minimized when the window loses focus and re-activates when the focus is restored.</li><li>(Framework) Moved methods and classes from ApplicationServices.cs(vb) to ApplicationServices.Auth.cs(vb).</li><li>(Class Library Apps) Files touch-edit.js and touch-input.js are copied to the ~/app/js/daf folder of the apps with the class library to enable debugging in Unlimited Edition apps.</li><li>(Framework) Method $app.prettyText formats international names as "pretty" strings.</li><li>(Universal Input) List box/ Check Box List / Radio Button List with 1 item has a compact presentation.</li><li>(Input) Qr code does not show the tooltip if the field is tagged as <i>input-qrcode-tooltip-hidden</i>.</li><li>(TouchUI) Check Box List item state transition is twice faster.</li><li>(Touch UI) Survey actions support the position=before|after option. If the option is not specified then actions are inserted just before the Cancel button. Actions with "before" position are placed before the "Submit" button. Actions with the position "after" are placed after the Cancel button.</li><li>(Framework) Method <i>dataView.data('survey')</i> returns the context data or a "survey" dataview. Used in the Property Grid and 2FA forms.</li><li>(Touch UI) The first row in the form category without the header will have a slightly large top padding.</li><li>(Touch UI) Freezing of the column in the grid with aggregates will not cause the exception.</li><li>(Touch UI) Keys F2 and Arrow Down will focus the first row in the focused DataView field in the form.</li><li>(Framework) Transaction processor correctly parses the temporary UIDs and resolves negative primary keys into "old" values encoded as UID if the corresponding new value is also the UID.</li><li>(Framework) Method <i>Commit </i>resolves the temporary primary key presented as negative integer or as uid in the format 000000000000-0000-0000-0000-00000001 with the key value recorded in the last segment.</li><li>(ODP) Client-side temp GUID primary keys are generated in the following format: 00000000-0000-0000-0000-00000000001. Only the last 12 digits are used to encode the temporary primary key, while the leading characters are set to 0. The server-side framework resolves such GUIDs with the physical database values.</li><li>(Model Builder) Data View fields created in the model builder will have the filter fields correctly matched to the corresponding field names. Previously the original column name was used instead. If the output field name based on the column was not spelled in the same way then there will be incorrect filtering at runtime.</li><li>(App Gen) The codedom compiler now supports << (left shift) and >> (right shift) operators in C# and VB.</li><li>(Touch UI) Tag <i>merge-with-prevous </i>will cause the row to render without a separator line at the top to allow creating a contiguous group of fields in the form layout.</li><li>(Surveys) Setting the "text" of the question to "false" will cause the label to be blank.</li><li>(Touch UI) Setting the Label or Header Text of a field to $blank will result in a blank label of the field.</li><li>(Touch UI) Removed legacy references to the class ui-group-theme-a and ui-panel-page-container-a.</li><li>(Framework) If the style of field items is set to Actions then the field is marked as "virtual".</li><li>(Universal Input) Tag<i> input-qrcode-size-192x192</i> will also trigger a custom input creation. The only input implemented now is "qrcode".</li><li>(Surveys) Survey definitions support <i>causesCalculate </i>on the actions and <i>htmlEncode </i>on the questions.</li><li>(Framework) Server-side method <i>PopulateStaticItems </i>will correctly assign Controller and View of the request to the internal <i>ViewPage </i>instance to ensure correct population of Many-to-many field with the static values (Check Box List, Drop Down List basket, List Box basket) when the Context Fields property of the many-to-many field property is set to X=Y. (X is the name of the filter and Y is the name of the field that will provide the value for X).</li><li>(Virtual Keyboard) Event <i>beforefocus.keypboard.app</i> is triggered on the data input prior to the keyboard gaining the focus. The handler can assign the callback method to the <i>e.context.change</i> property through the "e" argument of the event handler to be notified about changes to the text in the keyboard input.</li><li>(Virtual Keyboard) The virtual keyboard API is loaded when [data-input] elements are detected on the page to reduce the initial JS payload of the page.</li><li>(Universal Input) New virtual keyboard "pin" is now included with the framework. Tag a field as <i>kbd-pin</i> to have the keyboard displayed on touch devices.</li><li>(Universal Input) Virtual keyboard will not shift focus to the next input on tab or enter key if the user interface is in transition to another page at the moment of closure.</li><li>Thank you Roberto Ivon for contributing the "es" localization files.</li></ul></div></div><div><br /></div><div><br /></div></div><div><br /></div>Customer Servicehttp://www.blogger.com/profile/04471166550881539854noreply@blogger.com0tag:blogger.com,1999:blog-2297698770491701674.post-25945695558037538262021-10-04T07:07:00.036-07:002021-10-05T00:52:41.978-07:00Custom User Login Responses<p> The introduction of the <a href="https://codeontime.com/blog/2021/09/2-factor-authentication">2-Factor Authentication</a> in the application framework has required changes to the login process. The framework challenges the users to enter a verification code to confirm their identity. Method <i>CreateUserLoginResponse(username, success) </i> in the <i>ApplicationServices</i> partial class creates the JSON object with the instructions for the client-side code when the verification is needed.</p><p>Developers can take advantage of the new method to provide custom responses informing the user about the remaining login attempts, locked account, and other special cases. Otherwise the framework displays a generic message “Your user name and password are not valid.”</p><p>The sample code below will let the user name if the account is locked or display a notification at the bottom of the screen. The code executes only if there is no login response created by the base implementation to avoid conflicts with the multi-factor authentication.<br /><br /></p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikdKG9nENuB1AnzYOLp1BW_6OesXEQRt-8ajAUYzgotLwN_D2V8sAkJB_HoE_C69wNfTHc-Vw3HMSl_71tADoV-E7iVGmIFG_BxcMOCRmCRwDwQcBtOABQk-xypxKx4okCkg4Rdwy02nv9/s865/01-create-custom-user-login-response.png"><img border="0" data-original-height="647" data-original-width="865" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikdKG9nENuB1AnzYOLp1BW_6OesXEQRt-8ajAUYzgotLwN_D2V8sAkJB_HoE_C69wNfTHc-Vw3HMSl_71tADoV-E7iVGmIFG_BxcMOCRmCRwDwQcBtOABQk-xypxKx4okCkg4Rdwy02nv9/s16000/01-create-custom-user-login-response.png" /></a></div><br /><p>Invalid username or password will yield a notification message when the JSON object with the <i>notify </i>property is returned.</p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifu17Y8wXLYez-JgKLxqsne0DWHGT1xyulCAKaFgPHQ83ubBBI_ILr_5vAdIDpxaASLTTXvL0Xo18VyHX4-SGuuG2HDCP1nvOhqIrWyaB3lPsRI14sYnVsoT3CX3KYPlOf4y4dxJDyYxaM/s787/02-login-response-notify.png" ><img border="0" data-original-height="750" data-original-width="787" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifu17Y8wXLYez-JgKLxqsne0DWHGT1xyulCAKaFgPHQ83ubBBI_ILr_5vAdIDpxaASLTTXvL0Xo18VyHX4-SGuuG2HDCP1nvOhqIrWyaB3lPsRI14sYnVsoT3CX3KYPlOf4y4dxJDyYxaM/s16000/02-login-response-notify.png" /></a></div><br /><p>A more prominent response is provided if the responses includes the <i>alert </i>property.</p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjA7a0NRQkHv5f6MA65wRIWzf97754Ooutvz9sCPFBVqqIvPuIXgXZ74BdyrXVIzt7yNlCxXXtVGqfIxqYn2ZMH2LNd_OQk2no44wSwPAwxxUdwuvEjQaEbuN39FdxGtHIq2rB2M7E2h8hl/s787/03-login-response-alert.png"><img border="0" data-original-height="750" data-original-width="787" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjA7a0NRQkHv5f6MA65wRIWzf97754Ooutvz9sCPFBVqqIvPuIXgXZ74BdyrXVIzt7yNlCxXXtVGqfIxqYn2ZMH2LNd_OQk2no44wSwPAwxxUdwuvEjQaEbuN39FdxGtHIq2rB2M7E2h8hl/s16000/03-login-response-alert.png" /></a></div><br /><p>If the <i>event </i>property is returned in the response, then the framework will raise the client-side event on the document object with the response passed as the <i>args </i>property of the event. 2FA implementation uses this method to pass extended information to the client library.</p>Customer Servicehttp://www.blogger.com/profile/04471166550881539854noreply@blogger.com0tag:blogger.com,1999:blog-2297698770491701674.post-89134702245956079452021-10-03T14:05:00.114-07:002021-10-04T02:22:52.697-07:00"Actions" Lookup Style<p> Touch UI was designed to be responsive and functional on a device with any screen size. Forms are presented in modal popups on large screens or in the fullscreen mode on smaller devices. Actions are automatically rendered in the system toolbar bar, in the form button bar, or as a floating button. There is the universal “more” menu providing users with access to all actions available in the current context. </p><p>Developers can download HTML templates of live forms and tinker with them by moving fields around and injecting custom actions in the desired position. Touch UI provides a simple method of injecting custom actions in the desired position without a custom form template. The screenshot below demonstrates two sets of actions mixed in the flow of the data fields in the form on the iPad-size screen.<br /><br /></p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEir2plF5iIq33H-6_2KTwRfIYPOjiJbXOXFzjcx8kPyUyZIAOmefpTqlCUGGpmm7oT-0GAGsyLlNHEvltkGa7ifyjCsLypcPTqM_xPEr05nMwN51FJ8gI6UZJLnpvzQYhNM_iH2ip0fV07l/s1081/01-actions-lookup-style.png"><img border="0" data-original-height="893" data-original-width="1081" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEir2plF5iIq33H-6_2KTwRfIYPOjiJbXOXFzjcx8kPyUyZIAOmefpTqlCUGGpmm7oT-0GAGsyLlNHEvltkGa7ifyjCsLypcPTqM_xPEr05nMwN51FJ8gI6UZJLnpvzQYhNM_iH2ip0fV07l/s16000/01-actions-lookup-style.png" /></a></div><br /><div>Here is another example of the same form in the Pixel phone preview mode in the app created with Code On Time.</div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihCdydBHJcXyOddVOaszRl49J2e185e7mS45xqoaY7ViB6DCtMXDgQBg7z1coKfPaTXH7Jsp01SO2sgTrR8Vrn_Ie-PB7EANV47Aou1rSUW1ws_yyeHpYhecdIy5Odbv-ZNPT9WJnLSDGn/s1081/02-actions-lookup-style.png"><img border="0" data-original-height="968" data-original-width="1081" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihCdydBHJcXyOddVOaszRl49J2e185e7mS45xqoaY7ViB6DCtMXDgQBg7z1coKfPaTXH7Jsp01SO2sgTrR8Vrn_Ie-PB7EANV47Aou1rSUW1ws_yyeHpYhecdIy5Odbv-ZNPT9WJnLSDGn/s16000/02-actions-lookup-style.png" /></a></div><div><br /></div><div>Begin by adding two action groups with the “Custom” scope to the Employees data controller. Place actions with the <i>Custom </i>command name and corresponding <i>Argument </i>and <i>Header Text </i>into each group. Make sure to specify the <i>When Last Command Name </i>property for the actions. Our example has this property set to <i>Any </i>to ensure that the actions are visible in any mode regardless of the last executed action.</div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinici08UVE0wDgQ1-vXUptCbl2zVN651FVPk8U0oMtimT0tE86U8v6M9lM-IHWSVThsfQ63E3P9aKOw3ObcKvqlVH4md6S2IxGtGI3L8Nq_glKijT6qXlcQgWxsRQe-h1FSRCQPUAquli1/s415/05-action-groups-with-custom-scope.png"><img border="0" data-original-height="415" data-original-width="358" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinici08UVE0wDgQ1-vXUptCbl2zVN651FVPk8U0oMtimT0tE86U8v6M9lM-IHWSVThsfQ63E3P9aKOw3ObcKvqlVH4md6S2IxGtGI3L8Nq_glKijT6qXlcQgWxsRQe-h1FSRCQPUAquli1/s16000/05-action-groups-with-custom-scope.png" /></a></div><br /><div>Action group IDs are set to <i>ag100</i> and <i>ag101 </i>by the Project Designer. Right-click an action group in the Project Explorer and choose <i>Rename </i>if you prefer the custom identifiers.</div><div><div><br /></div><div>Now create two fields in the same data controller with the matching fields names. Set their item <i>Style </i>to <i>Actions</i>. The framework will treat these fields as virtual and therefore they will not have any impact on the standard data manipulation actions or custom actions.</div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDVh4QC3V_3WwmJ4M9fv6O-FBd_rxT-Bf8JQd-NcQZDSuVPqNHGJG6qLXvtgSTSkpNb0GOJ3A2Mfz01K1a8fNraD-gp65XXNWIV57Vl9DVP1J69o0ZJppnqBiiqtNa21pkQCInuR9Sp-iE/s702/06-fields-with-actions-lookup-style.png"><img border="0" data-original-height="702" data-original-width="366" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDVh4QC3V_3WwmJ4M9fv6O-FBd_rxT-Bf8JQd-NcQZDSuVPqNHGJG6qLXvtgSTSkpNb0GOJ3A2Mfz01K1a8fNraD-gp65XXNWIV57Vl9DVP1J69o0ZJppnqBiiqtNa21pkQCInuR9Sp-iE/s16000/06-fields-with-actions-lookup-style.png" /></a></div><br /><div>Drag the fields into the desired position in the data field flow of the <i>editForm1 </i>view. </div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiP2lbI8LlBetExDrEfGSuesjLavrQY9rfaIPzffss6GScGwHtUQ-SpZM9D_sf-f-J7FKIZBOoplNLU9Bq_7vR-gi1DjixxF_Ge4Z1W-fG9yyf38_Rrmmpsju5AAaOdthafudl62WNz6cDI/s595/07-data-fields-with-actions-lookup-style.png"><img border="0" data-original-height="595" data-original-width="282" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiP2lbI8LlBetExDrEfGSuesjLavrQY9rfaIPzffss6GScGwHtUQ-SpZM9D_sf-f-J7FKIZBOoplNLU9Bq_7vR-gi1DjixxF_Ge4Z1W-fG9yyf38_Rrmmpsju5AAaOdthafudl62WNz6cDI/s16000/07-data-fields-with-actions-lookup-style.png" /></a></div><br /><div>The framework will render the actions as specified. These actions will be visible only if all conditions specified in their <i>“When …”</i> properties are met. If all actions are invisible, then an empty space will be in their place instead. Use the <i>Visible When </i>property of the data field to hide the empty space when such conditions do occur.</div><div><div><br /></div><div>We had attempted previously to come up with a way to mix the data fields and actions without having to build a custom template. Our last attempt succeeded when we were solving the problem of making it obvious to users that the <i>Get Verification Code</i> button in the <a href="https://codeontime.com/blog/2021/09/2-factor-authentication">2-Factor Authentication</a> form must be pressed in order to get the code via chosen delivery method.</div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEievJSKu8z5i4gypWnTN_hyphenhyphenqPotnweh7nZ6ChAsgiWyBQ8mzJcdr5G-pfRTr5ITkX65nb2WpLIxBEDQt8OnEofmd_ctgUX30Hz7blvvTkl9iQ2AjC6_jIypa4XQmrYInLJ7dQAxPwsnXPOP/s853/08-get-verification-code-challenge.png"><img border="0" data-original-height="824" data-original-width="853" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEievJSKu8z5i4gypWnTN_hyphenhyphenqPotnweh7nZ6ChAsgiWyBQ8mzJcdr5G-pfRTr5ITkX65nb2WpLIxBEDQt8OnEofmd_ctgUX30Hz7blvvTkl9iQ2AjC6_jIypa4XQmrYInLJ7dQAxPwsnXPOP/s16000/08-get-verification-code-challenge.png" /></a></div><br /><div>The data field with the <i>Actions </i>style in the form above is also tagged as merge-with-previous to eliminate the line separating the “Actions” lookup from the previous data field.</div><div><div><br /></div><div>If you were to move the actions from the <i>Custom </i>group <i>ag100 </i>to the <i>Form </i>group <i>ag2</i>, then the form would look like this. Custom actions <i>Meet</i>, <i>Promote</i>, and <i>Happy Birthday </i>are rendered in the form button bar. </div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMaPwk7s96y1s26CiznGkLHfgdvRVI_eJw9uokXUjBK_Yuv3HSU8hiv7D7SxfM8fcr9u30ToOqt2XPZPqZSqa-cjE20i9MqCFm4USNKcIEWbbtuPKisewVdCCxm_zm1NyS_9lqYYozlWns/s1081/09-forms-scope-for-custom-actions.png"><img border="0" data-original-height="968" data-original-width="1081" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMaPwk7s96y1s26CiznGkLHfgdvRVI_eJw9uokXUjBK_Yuv3HSU8hiv7D7SxfM8fcr9u30ToOqt2XPZPqZSqa-cjE20i9MqCFm4USNKcIEWbbtuPKisewVdCCxm_zm1NyS_9lqYYozlWns/s16000/09-forms-scope-for-custom-actions.png" /></a></div><br /><div>This is how the corresponding configuration of the data controller may look in the Project Explorer.</div></div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIBOaQKQNcPy8fXEBIzuPaqSWkOlr0VRldj5t9mja3zh01FF7ySxRVmGJVY-6wed8xeRaYlOfXovn9SMdyfG19cGfgqGy0jbsN62EVFcHtfuEPMwtOLIP5oZYNojJWPBZREPNAaoAt9Z1H/s578/10-custom-actions-in-form-scope.png"><img border="0" data-original-height="578" data-original-width="372" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIBOaQKQNcPy8fXEBIzuPaqSWkOlr0VRldj5t9mja3zh01FF7ySxRVmGJVY-6wed8xeRaYlOfXovn9SMdyfG19cGfgqGy0jbsN62EVFcHtfuEPMwtOLIP5oZYNojJWPBZREPNAaoAt9Z1H/s16000/10-custom-actions-in-form-scope.png" /></a></div><br /><div>Arguably keeping the <i>ag100 </i>data field in the form flow right next to the <i>Last Name</i>, <i>First Name</i>, <i>Hire Date</i>, and <i>Birth Date </i>is a better user experience than placing the actions into the form button bar.</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPU_cvN4yJapXnUp4LevUJ2rl8kq1pmT45XjJIvc8UG-5L1X1hDRt68qqGLVni4iaq60QsL9Tc1SZqLtP9cT1RWWqQRIDtA0zZxL2bOplNLkThYLBSaIjOW2zw5egMQlrcFcZ7Z2p8nzOW/s1081/11-original-design-with-actions-style.png"><img border="0" data-original-height="968" data-original-width="1081" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPU_cvN4yJapXnUp4LevUJ2rl8kq1pmT45XjJIvc8UG-5L1X1hDRt68qqGLVni4iaq60QsL9Tc1SZqLtP9cT1RWWqQRIDtA0zZxL2bOplNLkThYLBSaIjOW2zw5egMQlrcFcZ7Z2p8nzOW/s16000/11-original-design-with-actions-style.png" /></a></div><div><br /></div>Customer Servicehttp://www.blogger.com/profile/04471166550881539854noreply@blogger.com0tag:blogger.com,1999:blog-2297698770491701674.post-18197557251400011522021-09-30T10:30:00.360-07:002021-10-01T13:02:57.492-07:002-Factor Authentication<h2> Multi-factor authentication</h2><p>A combination of a username and password provides access to the personalized features of applications. Unfortunately both elements of the online identity are the primary source of the security breaches. Username and password are obtained by perpetrators through social engineering attacks, spy programs, and other nefarious means. The complexity of our lives forces us to share the passwords with loved ones and friends. The robust mechanisms of online identity protection are urgently needed in every application.</p><p>Many organizations adopt security systems that require the end users to enter a numeric time-based verification code generated by an authenticator app installed on the user’s mobile device. The unique secret key is associated with the user account in the application database. Authenticator app uses the same secret to generate a new verification code periodically and does not require a network interaction with the application. If the correct verification code is not provided at the time of sign in, then the access to the application is not granted even if the user is entering the correct username and password combination.</p><p>The username, the password, the text message or email with the verification code, the phone with the authenticator app with optional fingerprint scan or face recognition are the components of the multi-factor authentication.</p><h2>2-Factor Authentication Setup</h2><p>Applications created with Code On Time can force the end users to provide an additional piece of information to confirm their identity after the username and password were confirmed. By default, the 2-Factor Authentication is the opt-in feature. It can be enabled in the user context menu.</p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXlNYFih3ND93JbA3SFdwfwg49Cfd7NxeSWy9ur4YXEUtfR9rfsBFcmgVyldJRYwG7qgsEWX99LZy74Cm8xOR6b_-94gr3CK8VAe1T1_8875GhjZZJaL0oLutG8IIdw44ri84QGEaVmEtS/s921/01-enable-2fa.png"><img border="0" data-original-height="759" data-original-width="921" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXlNYFih3ND93JbA3SFdwfwg49Cfd7NxeSWy9ur4YXEUtfR9rfsBFcmgVyldJRYwG7qgsEWX99LZy74Cm8xOR6b_-94gr3CK8VAe1T1_8875GhjZZJaL0oLutG8IIdw44ri84QGEaVmEtS/s16000/01-enable-2fa.png" /></a></div><p> <br />The option “2-Factor Authentication” is available to the authenticated user. The 2FA setup is not available to the end user if the user identity is confirmed by an OAuth provider. Application will rely on the authentication verification methods of the provider instead. The initial activation of 2FA will require the user to confirm their password.</p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoTpmwfAIiBcrZov644NTd0s7-gKpH-gWcRp2Zg50HlnQFD_qNjZXvDkJ0m8c0IlgUkgksZJdlKY-ZVrOtaCmsrRZ1kvWJsoybC5sr7bHqIzc9hJUqSGywhDa3Qg6-4eepO6KLQk-DHDNm/s921/02-confirm-password.png"><img border="0" data-original-height="759" data-original-width="921" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoTpmwfAIiBcrZov644NTd0s7-gKpH-gWcRp2Zg50HlnQFD_qNjZXvDkJ0m8c0IlgUkgksZJdlKY-ZVrOtaCmsrRZ1kvWJsoybC5sr7bHqIzc9hJUqSGywhDa3Qg6-4eepO6KLQk-DHDNm/s16000/02-confirm-password.png" /></a></div><div><br /></div><div><div>Next the user is giving a consent to enter a verification code after the successful sign in. By default two verification methods are offered. Users may opt into getting a verification code via email and to use an authenticator app.</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-19WHfcmJ9YQr2kfxo23e5pbYYNdVG80KLACTw4BnysOqZpJ_dyKNlhuZwkOzNWl5nCKBSxpOr5DaG4mCQ4owq0Ryf8K0s7tcbM4IsIEj4ZYVsT6XJ5kSxnm28Y2Hdh_VWHIusa5eUv6h/s921/03-consent-and-verification-method.png"><img border="0" data-original-height="759" data-original-width="921" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-19WHfcmJ9YQr2kfxo23e5pbYYNdVG80KLACTw4BnysOqZpJ_dyKNlhuZwkOzNWl5nCKBSxpOr5DaG4mCQ4owq0Ryf8K0s7tcbM4IsIEj4ZYVsT6XJ5kSxnm28Y2Hdh_VWHIusa5eUv6h/s16000/03-consent-and-verification-method.png" /></a></div><div><br /></div><div><div>The verification code delivery via email will rely on the email address associated with the user account. This is a less secure method than using an authenticator app since there may be other individuals who can read the user’s emails.</div><div><br /></div><div>Choosing the more secure method of verification will present the user with the QR code that needs to be scanned in <i>Google Authenticator</i>, <i>Microsoft Authenticator</i>, or another similar app. The QR code includes the information about the secret associated with the user account, the name of the app, and the name of the user along with some additional configuration data.</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMSs7Ko8_gBheZPR7k0-QZQGv7_QO0fa2bOvIU9fjTykEfJg8_hu35hBdRMzoxU6Ebj3ceM-mo13a1cnt_FVAdsJ8370K5rG70U6C7ec9pezBxPfNRP3DTeWOu1gNe68z-AxeObXVCcGYG/s921/04-verify-with-authenticator-app.png"><img border="0" data-original-height="759" data-original-width="921" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMSs7Ko8_gBheZPR7k0-QZQGv7_QO0fa2bOvIU9fjTykEfJg8_hu35hBdRMzoxU6Ebj3ceM-mo13a1cnt_FVAdsJ8370K5rG70U6C7ec9pezBxPfNRP3DTeWOu1gNe68z-AxeObXVCcGYG/s16000/04-verify-with-authenticator-app.png" /></a></div><div><br /></div><div><div>Google Authenticator immediately begins showing the verification code after the scan of the QR code. The time code will change every 30 seconds. There is no need to write down the verification codes since they will not be usable in the future. Other authenticator apps have a similar user interface and may require fingerprint scan or face recognition to display the verification codes.</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcC16rD0WEu4ZlbctFbwrQHkSErMLJqdH6BSV43rFUbHm2EZMbE4uzepwuTlFT-nAdeBg47EOeObzWre0hpun2gWzRz5JSDIulX-LpoLrBXB4A-oyKgfmqgRJBOUfGEhqtjP-4Wm4rT0gd/s640/04-z-google-authenticator-2fa.png"><img border="0" data-original-height="640" data-original-width="324" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcC16rD0WEu4ZlbctFbwrQHkSErMLJqdH6BSV43rFUbHm2EZMbE4uzepwuTlFT-nAdeBg47EOeObzWre0hpun2gWzRz5JSDIulX-LpoLrBXB4A-oyKgfmqgRJBOUfGEhqtjP-4Wm4rT0gd/s16000/04-z-google-authenticator-2fa.png" /></a></div><br /><div><br /></div><div><br /></div><div><div>If the user is not able to scan the QR code then they may opt to enter the setup key manually directly in the authenticator app. </div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDO4ReE22xs5GBvZqF7wZfZNJbLfy91J_sKul3CIw8j2sgzj7z0_HdRBzmeq90QTOWVzyOr6tuyYD3fDGjWBB1qpo20w-iE6zaO0SdF_kQ-DP6FQqxp4yee2lHni-QfXUlB4w5jUqZEBiT/s921/05-cannot-scan-qr-code.png"><img border="0" data-original-height="759" data-original-width="921" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDO4ReE22xs5GBvZqF7wZfZNJbLfy91J_sKul3CIw8j2sgzj7z0_HdRBzmeq90QTOWVzyOr6tuyYD3fDGjWBB1qpo20w-iE6zaO0SdF_kQ-DP6FQqxp4yee2lHni-QfXUlB4w5jUqZEBiT/s16000/05-cannot-scan-qr-code.png" /></a></div><div><br /></div><div><div>Users may also indicate that they need help installing an authenticator app. Three apps are offered by default. Scanning of the QR code with the camera of the mobile device will direct the user to the corresponding app store. </div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5jn8kxpcoX2gTZ6a4RFqCCegoZq1Qv_ct6hIIJ2G7IE5VEpKgS431OboCLO6F0noAP6WuZUjMV1qrSIPe6AldfWyQz_pfEpOq8y6zCPunxlqa5B4NEz6l7QNoBcOhoX0CbIvujECwe5NM/s921/06-installing-authenticator.png"><img border="0" data-original-height="759" data-original-width="921" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5jn8kxpcoX2gTZ6a4RFqCCegoZq1Qv_ct6hIIJ2G7IE5VEpKgS431OboCLO6F0noAP6WuZUjMV1qrSIPe6AldfWyQz_pfEpOq8y6zCPunxlqa5B4NEz6l7QNoBcOhoX0CbIvujECwe5NM/s16000/06-installing-authenticator.png" /></a></div><div><br /></div><div><div>Users must press the <i>Next </i>button when their authenticator app is configured through the QR code scan or after the direct input of the setup key. </div><div><br /></div><div>The configuration screen will present the list of the one-time use backup codes The backup codes are also available for the other verification methods including email, text message, and call.</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHRrbcLykcsJZbFHXKpgOhfLIM1YVKBO17h1ufX_SiQW98Mom6FTHkIxA2xMMDwhL_nCaC2I3oMXbC3o-BAqKJrMe8fNVUuDq1O1Edv5h1rXRFpYM_6H30pr556o7M3eb5RxKsYzzSUeyV/s921/07-backup-codes.png"><img border="0" data-original-height="792" data-original-width="921" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHRrbcLykcsJZbFHXKpgOhfLIM1YVKBO17h1ufX_SiQW98Mom6FTHkIxA2xMMDwhL_nCaC2I3oMXbC3o-BAqKJrMe8fNVUuDq1O1Edv5h1rXRFpYM_6H30pr556o7M3eb5RxKsYzzSUeyV/s16000/07-backup-codes.png" /></a></div><div><br /></div><div><div>The backup codes are stored directly in the user account. Each backup code can be used one time only as an alternative to the verification code in the situations when the mobile device with the authenticator app is not available and there are no other means of getting a verification code. Button <i>Save </i>will create a file with the current set of backup codes. Button <i>Generate </i>will produce a new set of backup codes. It is recommended to print the backup codes and have them stored in the safe place.</div><div><br /></div><div>Users complete the configuration by pressing the <i>Enable </i>button. This will result in the request to enter a verification code. Type in the verification code displayed in the authenticator app or get the code via email. Successful input of the verification code will enable the 2-factor authentication for the user account. The backup codes are not accepted during the setup verification. The objective of the setup verification is to ensure that the user is able to get the verification codes with the selected methods of delivery</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1RJse2UhRhOhHyx7JIi1Qf6MQr1k2um0wEp4WJrc8P2A0QlpH4jrazcjAOWCKZQ97dP-ZRvbPfeKCh5mzj-gIJ21_zvuP0C9Huk5X_jTSEtLq1ENHxQNfC67bYkF31jLVNcjXo_h0kqJX/s921/08-confirm-setup.png"><img border="0" data-original-height="792" data-original-width="921" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1RJse2UhRhOhHyx7JIi1Qf6MQr1k2um0wEp4WJrc8P2A0QlpH4jrazcjAOWCKZQ97dP-ZRvbPfeKCh5mzj-gIJ21_zvuP0C9Huk5X_jTSEtLq1ENHxQNfC67bYkF31jLVNcjXo_h0kqJX/s16000/08-confirm-setup.png" /></a></div><div><br /></div><div><h2>Living With 2-Factor Authentication</h2><div>The application will still require the user to enter the username and password in the custom or standard <i>Login</i> form.</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihKTdKXSPUJhu1upVXYZ1ZWnv7e1Exy-wt2JBX4UtO39K3yLK757GX07ZR3QIPAwo-tCo1XETfau7FgW_DIVhVaDwj3SmgEmMtdioqHgBoM5wAgv5tf7IG6TxzEu9TWQhItB9S1yDLufV0/s921/09-standard-login.png"><img border="0" data-original-height="792" data-original-width="921" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihKTdKXSPUJhu1upVXYZ1ZWnv7e1Exy-wt2JBX4UtO39K3yLK757GX07ZR3QIPAwo-tCo1XETfau7FgW_DIVhVaDwj3SmgEmMtdioqHgBoM5wAgv5tf7IG6TxzEu9TWQhItB9S1yDLufV0/s16000/09-standard-login.png" /></a></div><div><br /></div><div><div>Successful identification of the user will present the request to input the verification code. The user may opt to enter a one-time use backup code as an alternative to the verification code. Input of the incorrect verification or backup code will count as a failed login attempt. Multiple failed attempts to verify the username and password will result in the locked user account.</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxoIbOiQHghqDr_NE8qNIj9bHZtWuLS2HmHFEcvNhnoitnUJ_hgGgApxwGQsLOeFU3amshuiOd444VSe22UF3ia1iVMcL8TkrYT0EUHdWTE37KybYuD0s2kngrfY0cWrnXN-oJ6tw8mcPc/s921/10-verification-code-inpu.png"><img border="0" data-original-height="792" data-original-width="921" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxoIbOiQHghqDr_NE8qNIj9bHZtWuLS2HmHFEcvNhnoitnUJ_hgGgApxwGQsLOeFU3amshuiOd444VSe22UF3ia1iVMcL8TkrYT0EUHdWTE37KybYuD0s2kngrfY0cWrnXN-oJ6tw8mcPc/s16000/10-verification-code-inpu.png" /></a></div><div><br /></div><div><div>If the device can be trusted then the further requests to input the verification code can be suppressed by selecting the “Trust this device” option. The encrypted cookie with a unique verification code associated with the user name will be created. The application will verify the code stored in the cookie after the successful sign in to confirm the user identity.</div><div><br /></div><div>Selection of the verification method may reveal the <i>Get Verification Code</i> button. The verification code is delivered when the button is pressed. </div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwQtVE5-PZJjttdwDcM-0sU1Ihmm0PCH_EAFtap5qXDpc0GBU5aUJtyAUFwPgbpG3Wok6TQ89JOaSKXXuINq3Hasfq25HWcHtWzkEXZ5YCyONj_GG5nWDjqPe2GioOsjBjFRgyzPgVjfy0/s921/11-alt-methods-of-getting-verification-code.png"><img border="0" data-original-height="792" data-original-width="921" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwQtVE5-PZJjttdwDcM-0sU1Ihmm0PCH_EAFtap5qXDpc0GBU5aUJtyAUFwPgbpG3Wok6TQ89JOaSKXXuINq3Hasfq25HWcHtWzkEXZ5YCyONj_GG5nWDjqPe2GioOsjBjFRgyzPgVjfy0/s16000/11-alt-methods-of-getting-verification-code.png" /></a></div><div><br /></div><div><div>The setup screen can be re-entered by choosing the same “2-Factor Authentication” option in the user context menu. Users will be greeted with the verification code input screen before the setup options are presented. Users may change the verification code delivery methods, download the backup codes, or generate a new set of backup codes. Changes will be saved after another successful verification code input.</div><h2>Disabling 2-Factor Authentication</h2><div>Users may disable the 2-factor authentication by withdrawing the consent to enter a verification code. The withdrawal of the consent in the setup screen will disable the 2FA for the user account when the <i>Save </i>button is pressed.</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiY6qSXpVhQuqNqZupdK0ntHsULjp4aVwhPuRt0GyInpoxn-bKbOGBKNofwryzHP7pMgF0sJmcD7QduP7l-EKLWoAPNoKS3I5cu8hwNJ7Q1ft7NP1OuA6F9X_XpTSpY3MeNHD6xEwEBCH7R/s921/12-disable-2fa.png"><img border="0" data-original-height="792" data-original-width="921" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiY6qSXpVhQuqNqZupdK0ntHsULjp4aVwhPuRt0GyInpoxn-bKbOGBKNofwryzHP7pMgF0sJmcD7QduP7l-EKLWoAPNoKS3I5cu8hwNJ7Q1ft7NP1OuA6F9X_XpTSpY3MeNHD6xEwEBCH7R/s16000/12-disable-2fa.png" /></a></div><div><br /></div><div><div>The multi-factor authentication can be permanently disabled in the application by setting the <i>server.2FA.enabled</i> option to <i>false </i>in the <i>~/app/touch-settings.json </i>configuration file. </div><h2>Prerequisites</h2><div>2FA requires the additional data to be stored in the user account in the application database. If you have enabled the standard membership feature in your Code On Time app, then there is no need to do anything else. The application will store the 2FA setup in the <i>Comment </i>field of the user membership account.</div><div><br /></div><div>The screenshot below shows the <i>Comment </i>field of the <i>admin </i>user configured for multi-factor authentication. </div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6uR8a9QC3wmA-aQuKRIVGVYRGzPSgVybWlDkBRHmcy4Yz0hKgxTpgDjcYLuQVb9LLDtURkXgWTYvkCHLeO1NwjR9RGZ7nswcBrYfsozoXU1_az-Vmd2MZsehv4WVkhxCfUArKwD-KAv-U/s1027/13-2FA-with-standard-user-manager.png"><img border="0" data-original-height="825" data-original-width="1027" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6uR8a9QC3wmA-aQuKRIVGVYRGzPSgVybWlDkBRHmcy4Yz0hKgxTpgDjcYLuQVb9LLDtURkXgWTYvkCHLeO1NwjR9RGZ7nswcBrYfsozoXU1_az-Vmd2MZsehv4WVkhxCfUArKwD-KAv-U/s16000/13-2FA-with-standard-user-manager.png" /></a></div><div><br /></div><div><div>If the custom membership manager is configured for the Code On Time application, then make sure to map the <i>Comment </i>logical field to the corresponding column in your own “Users” table.</div><div><br /></div><div>The application framework provides two methods in the <i>ApplicationServices </i>class to read and write the user authentication data. Developers may override the methods <i>ReadUserAuthenticationData </i>and <i>WriteUserAuthenticationData </i>to store the data elsewhere. </div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6_ERPXmlZj7Zfw9LcD7lMkQi0qvHcdtkS2rvxiz9mAbKlERS1BumxWU7DGYTL21U4KsvoMh_7KYkVMIVL4wd4Vr-rnpKfZUuw8L-rt9VWj1W-oSyMrmlgx-SWDhORXcD1FpbuF39BWNaS/s730/14-read-write-user-authentication-data.png"><img border="0" data-original-height="240" data-original-width="730" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6_ERPXmlZj7Zfw9LcD7lMkQi0qvHcdtkS2rvxiz9mAbKlERS1BumxWU7DGYTL21U4KsvoMh_7KYkVMIVL4wd4Vr-rnpKfZUuw8L-rt9VWj1W-oSyMrmlgx-SWDhORXcD1FpbuF39BWNaS/s16000/14-read-write-user-authentication-data.png" /></a></div><div><br /></div><div><h2>Verification Code with SMS and Call</h2><div>Developers may enable three additional methods of verification code delivery in the app. These include <i>sms</i>, <i>call</i>, and <i>dial</i>. Enter the following options in the<i> touch-settings.json </i>file of your application to enable these methods:</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQn7eD9hnhYoqR2pJbVBdVZ3L6gRi045aZpiZw6Sawn0IOnmwsfWjGTMB7tQOid5enqHUELb9kWvz6wHtmLBENV4SCveUDrUBkT4bhysBZWwaRzsXeVjhUoAVMG9EyOc2qpDFRaKboT2JG/s392/15-2fa-verify-methods-in-the-app.png"><img border="0" data-original-height="310" data-original-width="392" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQn7eD9hnhYoqR2pJbVBdVZ3L6gRi045aZpiZw6Sawn0IOnmwsfWjGTMB7tQOid5enqHUELb9kWvz6wHtmLBENV4SCveUDrUBkT4bhysBZWwaRzsXeVjhUoAVMG9EyOc2qpDFRaKboT2JG/s16000/15-2fa-verify-methods-in-the-app.png" /></a></div><div><br /></div><div><div>Re-enter the 2FA setup and enable the verification code delivery via text message and call. Save the setup.</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkv35zGy42LOwam3zLVMILjnRQICQDYQtFe57k3sQ5pmdnPtsIUhjg4BsRjOBJUZzHS2fVONiDDniC-XrjOgXRQwZOJ26hpG14tLs76cXCS_mRFf9JCxVv8dmhHBNI3D18Y6IWSUX4g8Cj/s932/16-text-messag-and-call.png"><img border="0" data-original-height="746" data-original-width="932" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkv35zGy42LOwam3zLVMILjnRQICQDYQtFe57k3sQ5pmdnPtsIUhjg4BsRjOBJUZzHS2fVONiDDniC-XrjOgXRQwZOJ26hpG14tLs76cXCS_mRFf9JCxVv8dmhHBNI3D18Y6IWSUX4g8Cj/s16000/16-text-messag-and-call.png" /></a></div><div><br /></div><div><div>Verification methods <i>app </i>and <i>email </i>are enabled by default and available on the 2FA setup screen. Delivery via <i>email </i>will require specifying the SMTP server parameters in <i>Settings | Features | Smtp Configuration</i> section of the project configuration. </div><div><br /></div><div>There is no built-in support for <i>sms </i>or voice <i>call </i>delivery of the verification code in the framework. Developers may sign up for the text and voice delivery services from their favorite messaging provider and override two methods in the <i>ApplicationServices </i>partial class.</div><div><br /></div><div>Method <i>OtpVerificationData </i>must provide the means of verification code delivery for the given username parameter. The implementation below uses the sample static values.</div><div><br /></div><div>Method <i>OptAuthenticationSendVerificationCode </i>implements the physical delivery of the verification code. The implementation must send the contents of the <i>message </i>parameter to the <i>contact </i>using the code specific to the messaging provider.</div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTIeCaRJ8luMrguIIl5htEgip3XIf7SPgHA6h88QsvyDKVmyPNrDLO2dorBYceCAHQXmC4SJDGhRFRhRg6-SO_S48-ZoQ_bgG4q8sJ9AEurkvc0i6ayREN9IMrTGbldbXxX6g6jJCOf0Hb/s965/17-sending-verification-code-via-sms.png"><img border="0" data-original-height="965" data-original-width="859" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTIeCaRJ8luMrguIIl5htEgip3XIf7SPgHA6h88QsvyDKVmyPNrDLO2dorBYceCAHQXmC4SJDGhRFRhRg6-SO_S48-ZoQ_bgG4q8sJ9AEurkvc0i6ayREN9IMrTGbldbXxX6g6jJCOf0Hb/s16000/17-sending-verification-code-via-sms.png" /></a></div><div><br /></div></div><div><div>Users will initiate the delivery by selecting the corresponding method and pressing the <i>Get Verification Code</i> button. The delivery confirmation message will be displayed at the bottom of the screen. The framework obfuscates the email addresses and phone numbers available in the list of methods.</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiC2KBbzu6zAOzYgVViuiPX4Kjrfroi0G46hRgOo_9gNVQq0zS1YFG8q_O1HIEreAMoiVhyphenhyphen7E5aMfRRhi4atzZ4DPfNjwpEddcYCZjRyGMN25eogBG69IAUnp2fcr1D5mr54Ik8Q0Ep8IvR/s853/18-result-of-sending-verification-code-via-sms.png"><img border="0" data-original-height="824" data-original-width="853" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiC2KBbzu6zAOzYgVViuiPX4Kjrfroi0G46hRgOo_9gNVQq0zS1YFG8q_O1HIEreAMoiVhyphenhyphen7E5aMfRRhi4atzZ4DPfNjwpEddcYCZjRyGMN25eogBG69IAUnp2fcr1D5mr54Ik8Q0Ep8IvR/s16000/18-result-of-sending-verification-code-via-sms.png" /></a></div><div><br /></div><div><div>The <i>dial </i>verification method entered in the <i>server.2FA.verify.dial </i>option in <i>touch-settings.json </i>file. It will provide the user with the phone number to call. Use this delivery method if the live operator will be available to the application users to assist with their identity verification. The operator may enter the one-time use backup code directly into the user account in the <i>Membership Manager </i>or in a custom form. This backup code may be a word or a number that the operator will communicate to the user after their identity is confirmed.</div><h2>Trust No One </h2><div>Developers may force the users to always enter the verification code when signing into the app.</div><div><br /></div><div>Parameter <i>server.2FA.trustThisDevice</i> must be set to <i>0 </i>in <i>touch-settings.json </i>to hide the “Trust this device” option on the verification code input screen.</div><div><br /></div><div>The default value of the parameter is 180. It specifies the number of days during which the user will be able to avoid entering the verification code when signing into the application after the initial verification with the “Trust this device” option. </div><div><br /></div><div>If the user has lost access to the “trusted” device then the 2-factor authentication must be disabled and enabled one more time on the user account to invalidate any previous trusts.</div><div><br /></div><h2>Verification Code Length and Period</h2><div>The default length of the verification code is set to 6 digits that are changing every 30 seconds. Application framework will compare the provided verification code with the codes produced in the 180 second window. </div><div><br /></div><div>The length of the verification code, the period of change, and the testing window can be changed like this:</div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgytDMiok6L0ObnN4VZxwbsSkNSAx-SbIwM4UBZvo5RMiWjStqE1Xl2rI2Ms6dhQr1W-RGNZ0e1ASt-ZXAnGWtNQKThKM90Byv9DH6ZWiMNk5adwjial1Z5ac0847AJzvhmAnJU-imalRjc/s918/19-custom-authenticators.png"><img border="0" data-original-height="512" data-original-width="918" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgytDMiok6L0ObnN4VZxwbsSkNSAx-SbIwM4UBZvo5RMiWjStqE1Xl2rI2Ms6dhQr1W-RGNZ0e1ASt-ZXAnGWtNQKThKM90Byv9DH6ZWiMNk5adwjial1Z5ac0847AJzvhmAnJU-imalRjc/s16000/19-custom-authenticators.png" /></a></div><div><br /></div></div><div><div>The longer testing window can be specified if the delivery of the verification codes is slower than 3 minutes.</div><div><br /></div><div>Parameter <i>server.2FA.code.window</i> is provided exclusively for the application. It will generate multiple verification codes in the specified time window to find the match to the verification code provided by the user. </div><div><br /></div><div>Do not change the <i>length </i>and <i>period </i>if you expect the end users to work with the authenticator apps from Google or Microsoft. These apps will ignore the parameters and generate the 6 digit code every 30 seconds.</div><div><br /></div><div><i>Salesforce Authenticator</i> will respect the length and period parameters. It will correctly generate the 4-digit verification code every 60 seconds as instructed by the app.</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgooPv13fAI3-P0OeDNmAWiD952SmpUO7GHG5lorixfrG4XNSZUUoiPuCmpTDzER9YwZOm5xJQzy0_VnzvLpV1XBGuB7lzi7BWTmf0d4gxx2TcJOOia3cS0r1WCm3SrDyxrP8tIzIGRt9P5/s640/20-salesforce-authenticator.png"><img border="0" data-original-height="640" data-original-width="322" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgooPv13fAI3-P0OeDNmAWiD952SmpUO7GHG5lorixfrG4XNSZUUoiPuCmpTDzER9YwZOm5xJQzy0_VnzvLpV1XBGuB7lzi7BWTmf0d4gxx2TcJOOia3cS0r1WCm3SrDyxrP8tIzIGRt9P5/s16000/20-salesforce-authenticator.png" /></a></div><br /><div><br /></div><div><br /></div><div><div>Developers can specify their own set of the authenticator apps to be available on the setup screen. Option <i>server.2FA.setup.authenticators</i> is an array of <i>name</i>/<i>url </i>pairs in <i>touch-settings.json</i>. This custom set is presented to the user asking for help with the installation of the authenticator app. Users are prompted to scan the QR code with the device camera, which will present the link leading to the app store directly on the device.</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8mv-D8QL_hxbqIIWoKXMfLAnZzdPDJY3E90OHh1tYEkijc24k4qdRIzMoRkJckdxJxKO0JrlFKLvppdISR_Y21i6hcDuq4kO3S6OLM3YyMDeT4N1bis7R9-CT3Nw67wNIM4sRZciYi1vc/s853/21-custom-authneticator-apps-in-setup.png"><img border="0" data-original-height="824" data-original-width="853" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8mv-D8QL_hxbqIIWoKXMfLAnZzdPDJY3E90OHh1tYEkijc24k4qdRIzMoRkJckdxJxKO0JrlFKLvppdISR_Y21i6hcDuq4kO3S6OLM3YyMDeT4N1bis7R9-CT3Nw67wNIM4sRZciYi1vc/s16000/21-custom-authneticator-apps-in-setup.png" /></a></div><div><h2>Backup Codes</h2><div>By default the 2FA setup will produce ten 8-digit backup codes. Developers may opt to configure their own set of backup codes.</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1YpPJ9FrefwSIjZ-NEhVL_lPnJ-7YBycvxZUJ0WbWXFXJSLF2DvPy5CYfrXFy75HnWgzJ6lDGRq0a7BXHsiEQeTs4z6KnJNT_GRG4hzolPMMMnPhDFkoy6MjI4EG4OI2AqcQ59TPUNrjF/s308/22-backup-codes-config.png"><img border="0" data-original-height="254" data-original-width="308" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1YpPJ9FrefwSIjZ-NEhVL_lPnJ-7YBycvxZUJ0WbWXFXJSLF2DvPy5CYfrXFy75HnWgzJ6lDGRq0a7BXHsiEQeTs4z6KnJNT_GRG4hzolPMMMnPhDFkoy6MjI4EG4OI2AqcQ59TPUNrjF/s16000/22-backup-codes-config.png" /></a></div><div><br /></div><div>This configuration will produce the set of five 3-digit backup codes.</div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQdJNEbwa633jIG1TLJ3rHtgwLxvxZx7OBwu0fuaYQrjv8-3WjEVh6oI7PcxObKbNFkLyqVAwRYYphMul8j2kNNzO9dnxtwQV-Xm3IZLXGF-SAlIQiFRpjugjnFhHNBm_Gg6irW89621cR/s853/23-custom-backup-code-config.png"><img border="0" data-original-height="788" data-original-width="853" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQdJNEbwa633jIG1TLJ3rHtgwLxvxZx7OBwu0fuaYQrjv8-3WjEVh6oI7PcxObKbNFkLyqVAwRYYphMul8j2kNNzO9dnxtwQV-Xm3IZLXGF-SAlIQiFRpjugjnFhHNBm_Gg6irW89621cR/s16000/23-custom-backup-code-config.png" /></a></div><div><br /></div><div><div>Users must print or save the backup codes and use them if the access to the verification methods selected during the setup is lost.</div><h2>Auto-Setup</h2><div>By default the 2-factor authentication requires the users to opt in. Developers have an option to automatically generate the 2FA setup for the user accounts at the moment when the user is singing in.</div></div><div><br /></div><div>For example, the following configuration in <i>touch-settings.json</i> will automatically create the 2FA setup with the email-based delivery of verification codes. </div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7KlFQDIhyv_WioJo5d4y0p0YQtCMvmcIIINm3AV8aAiClpyuuyIXNx_1Rg0nnhqNQozoqDmX0ZcMKi3LSSfhYJIaB9n-_qYT6o_NnMgRr2r53ugI3SXBs5nkwuc3DdcBOA8yPNPcdA8jB/s355/24-2FA-auto-setup-config.png"><img border="0" data-original-height="355" data-original-width="326" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7KlFQDIhyv_WioJo5d4y0p0YQtCMvmcIIINm3AV8aAiClpyuuyIXNx_1Rg0nnhqNQozoqDmX0ZcMKi3LSSfhYJIaB9n-_qYT6o_NnMgRr2r53ugI3SXBs5nkwuc3DdcBOA8yPNPcdA8jB/s320/24-2FA-auto-setup-config.png" width="294" /></a></div><div><br /></div><div><div>Users will enter the username and password and press login. The framework will create the 2FA setup if it does not exist. Users will be immediately presented with the request to enter the verification code. The only option to get the verification code is the email. </div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcajU16g9W9Skpbcl7naTgrVLzZZ8Nw8tqRpGhRiHAbpKbUGMuJ9clCm8tSfNx342-xSfiXd6N7p7MmPS6TRKcsUbN4r3w2y5XqLlJJSQNQy8RAAyFtTwkHJZbZWjHexWN0whNQIYH5z4b/s853/25-auto-setup-in-action.png"><img border="0" data-original-height="788" data-original-width="853" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcajU16g9W9Skpbcl7naTgrVLzZZ8Nw8tqRpGhRiHAbpKbUGMuJ9clCm8tSfNx342-xSfiXd6N7p7MmPS6TRKcsUbN4r3w2y5XqLlJJSQNQy8RAAyFtTwkHJZbZWjHexWN0whNQIYH5z4b/s16000/25-auto-setup-in-action.png" /></a></div><div><br /></div><div><br /></div><div><div>Make sure to set up the <i>SMTP Configuration</i> in the <i>Settings | Features </i>of the application. Otherwise users will not be able to access the application.</div><div><br /></div><div>Applications may support the other methods of verification that can be configured in <i>server.2FA.verify </i>section of <i>touch-settings.json</i> as explained above. Users will need to enter the setup mode through the user context menu to change their verification preferences. </div><div><br /></div><div>If a user withdraws the consent to enter the verification code, then the application will perform the automatic setup during the next sign in to keep the user accounts protected.</div><h2>Login Without Password</h2><div>Automatic setup makes it possible to disable the requirement to enter the password during the setup. Set the <i>server.2FA.disableLoginPassword</i> to <i>true </i>and <i>server.2FA.setup.mode </i>to <i>auto </i>in <i>touch-settings.json</i>. Optionally specify the automatic setup methods. The default setup method of verification code delivery is email.</div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhG1tstVrqiGYAkiuVbwnC6SzKbMa2bTXDqqO6huHrO9hpAvDn5hqz4Zk76rNI0VZCS5WW_VjM7zFeAoJggHNynAAqe9bD0fLXSUDczJwdhAuC1uPKUFjyQoTfpQE5PcXhH_nlrgTUT4Lp_/s419/28-disable-login-password.png"><img border="0" data-original-height="275" data-original-width="419" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhG1tstVrqiGYAkiuVbwnC6SzKbMa2bTXDqqO6huHrO9hpAvDn5hqz4Zk76rNI0VZCS5WW_VjM7zFeAoJggHNynAAqe9bD0fLXSUDczJwdhAuC1uPKUFjyQoTfpQE5PcXhH_nlrgTUT4Lp_/s16000/28-disable-login-password.png" /></a></div><div><br /></div></div><div><div>The built-in login form will not ask the user to enter the password.</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgt9kSKwDlxJ0tsEHnHldTqJrxjosLZcDeC0NFFPoEldURoHSKFWNJ9IOPWRdtZQ6qqw8VBWgMpEl1NB_G5HtOt2IFByzZC4Z9nulWVWwEtFIZJ8gZ97ZsOcjgIRMAgkUhXAa8un2GN-sxG/s853/29-password-field-disabled.png"><img border="0" data-original-height="610" data-original-width="853" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgt9kSKwDlxJ0tsEHnHldTqJrxjosLZcDeC0NFFPoEldURoHSKFWNJ9IOPWRdtZQ6qqw8VBWgMpEl1NB_G5HtOt2IFByzZC4Z9nulWVWwEtFIZJ8gZ97ZsOcjgIRMAgkUhXAa8un2GN-sxG/s16000/29-password-field-disabled.png" /></a></div><div><br /></div><div>The framework will locate the user account by name. If the user is found, then the automatic 2FA setup is performed when needed. The user will be asked to enter a verification code to sign in. </div><div><br /></div><div>The initial verification is done via email. Users may opt to enable the authenticator app verification in the setup. We recommend also setting the <i>server.2FA.trustThisDevice </i>option to <i>0 </i>to ensure that the verification code is always requested.</div>Customer Servicehttp://www.blogger.com/profile/04471166550881539854noreply@blogger.com0tag:blogger.com,1999:blog-2297698770491701674.post-67142299707277637882021-08-20T15:30:00.001-07:002021-08-21T03:33:29.147-07:00August/September 2021 Roadmap<p>We are very pleased to announce the host of new features that are becoming available in the next few weeks. 2-Factor Authentication, new REST API v2, and barcode scanning with the device camera, are just some of the features that are coming at the end of the summer.</p><h2>2-Factor Authentication</h2><p>The next release 8.9.23.0 will introduce 2-Factor Authentication that will be enabled by default in apps created with the Unlimited Edition of Code On Time.</p><p>End users will have an option to strengthen their username and password with the one-time verification codes that are delivered via email, text message, or “authenticator” apps such as <a href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&hl=en_US&gl=US">Google Authenticator</a> or <a href="https://apps.apple.com/us/app/microsoft-authenticator/id983156458">Microsoft Authenticator</a>.</p><p>User context menu provides a new option that helps the authenticated user to set up the 2-factor authentication. If the user has the “authenticator” app on their mobile device, then a simple scan of the QR code on the setup screen will configure that app to generate the verification codes to confirm to sign in.<br /> </p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhD6h9tGuGwF_8d11CWQMdsRl3WDfoDwfpJDU1bSatESuFLiu3gwmz07dlY55CuNSNv-6FND9Ru5d5Vcd00jBGBlha3TojnDRW2Rk4J0g6s81kNriEIUvr3GbPNYow2Q7UznYJDOkWDnmCX/s1138/01-enable-2fa.png"><img border="0" data-original-height="922" data-original-width="1138" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhD6h9tGuGwF_8d11CWQMdsRl3WDfoDwfpJDU1bSatESuFLiu3gwmz07dlY55CuNSNv-6FND9Ru5d5Vcd00jBGBlha3TojnDRW2Rk4J0g6s81kNriEIUvr3GbPNYow2Q7UznYJDOkWDnmCX/s16000/01-enable-2fa.png" /></a></div><div><span id="docs-internal-guid-8956d4b2-7fff-e7dc-19df-80bf962b272f"><p><span> <br />Authenticator app does not have a physical connection to your application. The scan of the QR code during the setup allows the app to retrieve the secret stored in the user record. The app generates a new verification code frequently. There is no need to remember the code. You will be able to sign in as long as you have access to your phone.</span></p><p><span>You will be required to enter the username and password.<br /> </span></p><p></p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7l2bO9KbLFtE10El9AGKPhRPpccMo_qZo3yIA1dTk2I-O_Ho-QAK02XEdsAaPvBNf3B5OLDIPIHDaN4g49xg5xQMKcLKZOrY1TDOQoJweFHwt9iAAy_HBTREqmJ4ZQgB_kRQtnWJ2rF7G/s1138/02-user-login.png"><img border="0" data-original-height="922" data-original-width="1138" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7l2bO9KbLFtE10El9AGKPhRPpccMo_qZo3yIA1dTk2I-O_Ho-QAK02XEdsAaPvBNf3B5OLDIPIHDaN4g49xg5xQMKcLKZOrY1TDOQoJweFHwt9iAAy_HBTREqmJ4ZQgB_kRQtnWJ2rF7G/s16000/02-user-login.png" /></a></div><div> </div><div><div>The successful sign in will result in the request to enter the verification code if the 2-factor authentication was set up for the account previously. </div><div> </div></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzwaW8447pCETeFbZ56jltuEk1z5Ut7cgf60xQmyHZfezZUkgqZNsjoUrYl88Say29ensOnAL0yPY-9tlKqWVdbTVzipUfWat2w9Y2pzxBGicPeSCQ_jEmcwBcl3KVStXXIcA-2hTkbatD/s1138/03-verification-code-input.png"><img border="0" data-original-height="922" data-original-width="1138" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzwaW8447pCETeFbZ56jltuEk1z5Ut7cgf60xQmyHZfezZUkgqZNsjoUrYl88Say29ensOnAL0yPY-9tlKqWVdbTVzipUfWat2w9Y2pzxBGicPeSCQ_jEmcwBcl3KVStXXIcA-2hTkbatD/s16000/03-verification-code-input.png" /></a></div><p> <br />Another default option is to receive an email with the verification code that expires in a few minutes. Developers also have an option to instruct the app to send a text message or call the user with the verification code. </p><p>If the correct time-based verification code is entered, then the user is signed in. Incorrect input of verification code will count as a failed login attempt with the eventual lockout of the user account.</p><p>“Authenticator App” is a very secure option since there is no communication with the 3rd party systems. The default “Email me at...” option can be disabled in the application if required.</p><p>Users can also enter the single use backup codes provided to the user during the setup process.</p><h2>REST API v2 / App Middleware</h2><p>We are pleased to announce the new REST API v2 available in the apps created with the Unlimited Edition. </p><p>The server-side framework automatically responds to the requests to read and write data by creating JSON or YAML based output. <i>Hypertext Application Language </i>links are automatically included in the responses to enable the API discovery.<br /> </p><div><span><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOwLcviDAUN2OKwcAEf3cUFXPM14O4FqWbdOAR-h3ZiKbagJDC_RrGpBfN1i0UdOCDvyHybYjLeAIdcITHR0sNfznlzU7hOHiOLPDhOR-KF0gkjt9dbS2mvcykZqnhHwZAN3U6oWm8QvmY/s1138/04-rest-api.png"><img border="0" data-original-height="1014" data-original-width="1138" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOwLcviDAUN2OKwcAEf3cUFXPM14O4FqWbdOAR-h3ZiKbagJDC_RrGpBfN1i0UdOCDvyHybYjLeAIdcITHR0sNfznlzU7hOHiOLPDhOR-KF0gkjt9dbS2mvcykZqnhHwZAN3U6oWm8QvmY/s16000/04-rest-api.png" /></a></span></div><div><br /></div><div><div>The new REST API is the automatic reflection of your data controllers, lookups, and dataview fields. The root entry point of the API serves as the introspection end-point that helps to learn what’s possible.</div><div><br /></div><div>API Keys and access tokens help authenticating the request. The new API can be used internally and also as a middleware for the projects that require database access. Developers can even enable the “middleware” mode when no user interface options are available and only the API requests are being handled. </div><h2>Camera-Based Barcode Scanning</h2><div>Your apps will finally have an option to scan the barcodes and QR codes without relying on the external scanners. The powerful <a href="https://codeontime.com/blog/2020/05/tutorial-barcodes-qr-codes-and-rfid-tags">UI Automation and Kiosk UI</a> already available to the app developers are getting a boost! The QR code icon on the toolbar activates the camera-based scanner powered by the <a href="https://opensource.google/projects/zxing">Zxing </a>(zebra crossing) library. </div><div><br /></div><div>The camera scanner icon is available when barcode support is enabled. Developers will also have an option to automatically activate the scanner when a particular form is displayed or a field is focused. The scanned barcodes and QR codes are placed in the barcode processing queue, which is also populated by the external scanners and readers.</div><div><br /></div><div>The simple and powerful <i>IfThisThenThat </i>API allows creating complex rules that force the UI of the app to perform various actions in response to the contents of the barcode queue.</div><h2>V9 and Integrated Community</h2><div>We have made great progress in delivering the new browser-based development environment for your apps. The screenshots above show the live preview mode of upcoming v9. It will become the default mode for Code On Time developers and provide property grids and toolbars with drag & drop configuration and point-and-click inspection of live apps.</div><div><br /></div><div>The community forum is integrated into the new development environment and will allow discussing and documenting various features right from the property grid. The news feed will also be readily available along with the place to see the latest discussions, tickets, and blog posts.</div><div><br /></div></div></span></div>Customer Servicehttp://www.blogger.com/profile/04471166550881539854noreply@blogger.com0tag:blogger.com,1999:blog-2297698770491701674.post-50368993037648547262021-08-11T13:42:00.078-07:002021-08-12T01:57:58.498-07:00Real Time User Interface Customization<p>Touch UI apps offer rich user experience courtesy of Code On Time app generator. By default, a data model configured by the developer will enable the data presentation as grid, list, and cards. Foreign key fields are presented as a versatile lookup input with auto-complete, search, and an option to create new items in-place. Foreign key fields will also enable automatic data charts. </p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3SxLRKvc8GvSRocRYoAMODIW8Sf2ig0difjVD99QcjOBTH9Rv-4BS7shC-sB_0cDB3LndPoldpZ14AAAi7jTUfGItrHfr9UYv6rKBbAAeHWuA4O3nDZAE5Yt9h9MEH4Vm3_BFfXPnNtsZ/s1345/01-rich-touch-ui-by-default.png"><img border="0" data-original-height="1135" data-original-width="1345" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3SxLRKvc8GvSRocRYoAMODIW8Sf2ig0difjVD99QcjOBTH9Rv-4BS7shC-sB_0cDB3LndPoldpZ14AAAi7jTUfGItrHfr9UYv6rKBbAAeHWuA4O3nDZAE5Yt9h9MEH4Vm3_BFfXPnNtsZ/s16000/01-rich-touch-ui-by-default.png" /></a></div><p> <br />These and many other user interface features will make the life of the end users very comfortable.</p><div><div>Sometimes the end-user comfort is not the ultimate goal. The simplicity of the UI will be driving user satisfaction. Developers may quickly customize the features of the app in the Project Designer. There is also an option to perform the real time user interface customization with code. This option is especially relevant for large applications.</div><div><br /></div><div>Let’s limit the view style of the Products in the Northwind sample to Grid and convert the lookups to drop down lists without the ability to create new items.</div><h2>Method 1 - Project Designer</h2><div>Select the <i>Products / views / grid1 </i>view in the Project Designer and tag it as:<br /> </div><div><blockquote>view-style-grid view-style-list-disabled view-style-cards-disabled view-style-charts-disabled</blockquote></div><div>This will limit the view styles available to the end user and set the default style of data presentation.</div><div><br /></div><div>Next select the <i>Products / fields / SupplierID </i>lookup field and change the view style to <i>Drop Down List</i>. Also clear the value <i>createForm1 </i>from the <i>New Data View </i>property. </div><div><br /></div><div>Re-generate the app and observe the simpler user interface in action.</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiX9u0LKsTmJFx0YnBqz3BmKIVe907oxwm2QeotxjqVpJHYF1rKVdlHg4fySXWRbjjdeVd6BxfBMNUBTYyu3gRhaiKenSp96FPwZvl1tYMPqfRrYNmoe6tt6KRDeSW3zjBieVNXmmnVkVP8/s1064/02-simple-touch-ui-with-customization.png"><img border="0" data-original-height="946" data-original-width="1064" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiX9u0LKsTmJFx0YnBqz3BmKIVe907oxwm2QeotxjqVpJHYF1rKVdlHg4fySXWRbjjdeVd6BxfBMNUBTYyu3gRhaiKenSp96FPwZvl1tYMPqfRrYNmoe6tt6KRDeSW3zjBieVNXmmnVkVP8/s16000/02-simple-touch-ui-with-customization.png" /></a></div><br /><div>Please note that the view style buttons are not visible on the sidebar since the Grid is the only option.</div><div><h2>Method 2 - Data Controller Virtualization</h2><div>Data Aquarium Framework is the foundation of apps built with Touch UI. The server-side code makes it possible to transform the design of the data controller at runtime. </div><div><br /></div><div>Select your project on the start page of the app generator and choose <i>Settings | Data Model & Business Logic</i>, activate <i>Shared Business Rules </i>tab, and enable the <i>Shared Business Rules</i>. Press <i>Finish </i>to generate your application. </div><div><br /></div><div>Select the project again and choose Develop. Locate the file <i>~/app/App_Code/custom/rules/SharedBusinessRules.cs </i>in the Visual Studio and replace its contents with the following:</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3agosflf-VFneHgVJ_bDCWi5aYga-ZBFZtjXhZSThdvbwvxHJdO300QShygZnKQPxYLGjq4l3Eua09A5k5Ku3EWzYzlgKsIjUrDhpUP5bT0-Z4FBZzn9DVrrMn8e7JucEF2u4mC0VgRVp/s832/05-virtualize-controller-example.png"><img border="0" data-original-height="832" data-original-width="794" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3agosflf-VFneHgVJ_bDCWi5aYga-ZBFZtjXhZSThdvbwvxHJdO300QShygZnKQPxYLGjq4l3Eua09A5k5Ku3EWzYzlgKsIjUrDhpUP5bT0-Z4FBZzn9DVrrMn8e7JucEF2u4mC0VgRVp/s16000/05-virtualize-controller-example.png" /></a></div><br /><div>Make sure to change the namespace <i>MyCompany </i>to the one that matches your application.</div><div><div><br /></div><div>The instance of the <i>SharedBusinessRules </i>class is created by the server-side code when processing the requests for any data controller. Your existing business rules must inherit from this class to acquire the shared functionality. Any new “code” business rules created in the future will automatically inherit from it. The framework “consults” the business rules about various aspects of data processing.</div><div><br /></div><div>The first method <i>SupportsVirtualization </i>is invoked when the XML definition of the data controller has been loaded to process the request. If the method returns true, then the framework will proceed to invoke the customization methods.</div><div><br /></div><div>The second method <i>VirtualizeController </i>is given a chance to make changes. The code above is reproducing the same steps that were described in<i> Method 1 </i>if the current user does not belong to the Administrators role. The customization of view styles is done with <i>SelectView </i>and <i>SetTag </i>methods of the <i>NodeSet </i>API. There are numerous specialized methods that take the guesswork out of the customization process. Auto-completion in Visual Studio will provide a full list of available methods with the relevant descriptions of their purpose. The configuration of the lookups is performed with the generic <i>Select </i>and <i>Attr </i>methods of the <i>NodeSet </i>API. The former uses XPath expression to locate the elements in XML. The latter selects one particular attribute.</div><div><br /></div><div>Our customization does not discriminate over field names and will convert all lookup fields into dropdowns without the ability to create new items. This screenshot shows the <i>SupplierID </i>dropdown aliased as <i>Supplier Company Name</i> and <i>CategoryID </i>aliased as <i>Category Name </i>with the list of items visible.</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgziDRTcKRr-KScd-JgSgTWIkvUlpzhNsd_i9Zz_Xew5qqoS8vqAZupPpR8ZHmKmmUun7O4RO6q4xdWigYHe7z2QKnUS8mZcf1O2hmSj0a4uIVJrC4m06ga8PvUEwS_vnTWPQV3VFcUkVtf/s1064/03-vritualized-controllers-touch-ui.png"><img border="0" data-original-height="946" data-original-width="1064" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgziDRTcKRr-KScd-JgSgTWIkvUlpzhNsd_i9Zz_Xew5qqoS8vqAZupPpR8ZHmKmmUun7O4RO6q4xdWigYHe7z2QKnUS8mZcf1O2hmSj0a4uIVJrC4m06ga8PvUEwS_vnTWPQV3VFcUkVtf/s16000/03-vritualized-controllers-touch-ui.png" /></a></div><br /><div>The nature of the real time changes in the XML definition of the data controller is shown below. Please note that the virtualization will change the in-memory copy of the data controller. The physical data controller file remains the same as it was arranged by the app developer.</div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFEJMTfrFTLtuOlBm-VyF4FaqA7zYRKdt_YzZQgURjwv_HryfYda8bJfqcim6IQHZ43tYp89XU17u6y6Eyr33yZhIzx41mpm4xhKkYkR0IynCl6BkynOtFcqny6PuHcAzNfuQ29ojztyM4/s1169/04-customized-data-controller.jpg"><img border="0" data-original-height="716" data-original-width="1169" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFEJMTfrFTLtuOlBm-VyF4FaqA7zYRKdt_YzZQgURjwv_HryfYda8bJfqcim6IQHZ43tYp89XU17u6y6Eyr33yZhIzx41mpm4xhKkYkR0IynCl6BkynOtFcqny6PuHcAzNfuQ29ojztyM4/s16000/04-customized-data-controller.jpg" /></a></div><br /><div>Our code will work whether your app has 3 data controllers or 1000. Only the Administrators will have the rich user interface capabilities while the rest of the users are offered a more streamlined experience.</div>Customer Servicehttp://www.blogger.com/profile/04471166550881539854noreply@blogger.com0tag:blogger.com,1999:blog-2297698770491701674.post-22272601974992443282021-08-05T17:30:00.099-07:002021-08-06T05:28:42.787-07:00Auto Highlight/Select, QR Codes, and Custom Input Enhancements<p> Release 8.9.22.0 introduces new features and multiple bug fixes. Now developers can configure their master-detail “data view” fields to always highlight or select the first record on any level of the dependencies. Any input field on the form can be enhanced with QR code representing its value. The ability to display QR codes is implemented with the help of the <i>Custom Input Enhancements </i>feature of <i>the Universal Input</i>.</p><h2>Auto Highlight and Auto Select</h2><p>Code On Time allows configuring the <i>Auto Highlight </i>or <i>Auto Select </i>of the first row in the dataview, which is performed when the page loads. These properties can be set up on the “data view” fields, which makes possible the cascade selection of the first row in the master-detail hierarchies in the forms. The framework resets the auto highlighting and selection to avoid the excessive loading of child data views when the master on higher level is changed.</p><p>Now you can force the application to always perform the automatic highlighting or selection. For example, the <i>Order Management Dashboard</i> from the <a href="https://codeontime.com/blog/2021/07/drag-cut-copy-and-paste-your-data">Drag & Drop example</a> can be enhanced with the tag <i>auto-highlight-first-row-always</i> applied to the <i>OrderDetails </i>“data view” field. This will result in the first detail to be always highlighted when a new order is selected.<br /> </p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWj1GynUL5ck-wsYl7oaGap12AdxxMJ8PfqKiRU38SKJICUodl9bToUL052j_h8LK764WWqRiYygGrfXbQbivNe13pJk9u8eAvjafh3-oq3yoG5YEgk7wEz7lZbTvDqB7c79uCB2aqmTaJ/s1250/01-touch-ui-auto-highlight-always.png"><img border="0" data-original-height="893" data-original-width="1250" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWj1GynUL5ck-wsYl7oaGap12AdxxMJ8PfqKiRU38SKJICUodl9bToUL052j_h8LK764WWqRiYygGrfXbQbivNe13pJk9u8eAvjafh3-oq3yoG5YEgk7wEz7lZbTvDqB7c79uCB2aqmTaJ/s16000/01-touch-ui-auto-highlight-always.png" /></a></div><br /><p>Tags <i>auto-highlight-first-row-once</i> and <i>auto-highlight-first-row-always </i>are used to control the frequency of automatic highlighting.</p><p>Tags <i>auto-select-first-row-once</i> and <i>auto-select-first-row-always </i>are used to control the frequency of the automatic “Select” action applied to the first row/item in the data view. For example, the tag auto-select-first-row-always will cause the dashboard to display the first item of the <i>OrderDetails </i>data view in the form. <br /> </p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSDtf3iT54kGVmoQgaaNslOOj50WMEz6kLACUQmh2FQOZA0LazqECF_watsztg87jZQawyEPBr0GmwYEImRz8TwYKPuZnhaeHF9k8lAGlxm71mbuEusouhJqgsM57Qx2WcdUNl5dftroh3/s1250/02-touch-ui-auto-select-always.png"><img border="0" data-original-height="893" data-original-width="1250" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSDtf3iT54kGVmoQgaaNslOOj50WMEz6kLACUQmh2FQOZA0LazqECF_watsztg87jZQawyEPBr0GmwYEImRz8TwYKPuZnhaeHF9k8lAGlxm71mbuEusouhJqgsM57Qx2WcdUNl5dftroh3/s16000/02-touch-ui-auto-select-always.png" /></a></div><p><br />Please note that the automatic highlighting/select will not be performed if the new record was created or an existing record was changed. Only the simple refresh/synchronization will result in the highlight or select action.</p><h2>QR Codes</h2><p>The majority of the population has been forced to learn and use the QR codes in their daily lives in 2021. You can enhance any field in the form of your app to display a QR code representing the field value.<br /> </p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGwyFy_-0xKzyXOyukgJkHRsiyYvf9neUYv5gmDFgVYumHBssC-Nvf3o9PWB3Jt2KamLJZbNB5mOz1PtclbpgzIjnWSlKIvFUjd5hIhiWiE6wog52FkJBEejVuRNApZTQRY5JZaNJGHDEb/s992/03-qr-code-in-touch-ui-app.png"><img border="0" data-original-height="914" data-original-width="992" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGwyFy_-0xKzyXOyukgJkHRsiyYvf9neUYv5gmDFgVYumHBssC-Nvf3o9PWB3Jt2KamLJZbNB5mOz1PtclbpgzIjnWSlKIvFUjd5hIhiWiE6wog52FkJBEejVuRNApZTQRY5JZaNJGHDEb/s16000/03-qr-code-in-touch-ui-app.png" /></a></div><br /><p>Try out this feature at <a href="https://demo.codeontime.com">https://demo.codeontime.com</a> now! Select a supplier, press Edit and enter any value in the <i>Home Page </i>field. Press <i>Ctrl+Enter </i>on the keyboard or blur the field to see the QR code displayed right next to it.</p><p>Tag any data field in the form view as <i>input-qrcode-128x128 </i>and the QR code enhancement with the specified dimensions will be visible just below the field value. </p><p>Touch UI recognizes the following tags that will impact the QR Code presentation:</p><p></p><ul><li>Tag <i>input-qrcode-WxH</i> (enables QR code enhancement)</li><li>Tag <i>input-qrcode-color-light-HTML_COLOR </i>- specifies the “light” color</li><li>Tag <i>input-qrcode-color-dark-HTML_COLOR </i>- specifies the “dark” color</li><li>Tag <i>input-qrcode-correct-level-(L|M|Q|H)</i> - specifies the correction level.</li><li>Tag <i>input-qrcode-value-hidden </i>- hides the field value and displays the QR code instead.</li></ul><p></p><h2>Custom Input Enhancements</h2><p>Custom input enhancement can be activated on any data field with the help of the <i>input-NAME </i>tag. The framework will load the custom script from <i>~/app/js/daf/input-NAME.min.js</i> or <i>~/app/js/daf/input-NAME.js</i>. Next it will invoke the method <i>$app.input.methods.NAME._init(field, value, text, placeholder)</i> and pass to it the reference to the data field, its value, text, and the placeholder element positioned below the data field value. Tag <i>input-NAME-WxH </i>will assign the width and height specified in <b>W</b> and <b>H</b> to the placeholder.</p><p>Another related tag <i>input-NAME-value-hidden </i>will produce the hidden data value. Only the enhancement will remain visible.</p><p>The support for QR codes is implemented as an enhancement that can be activated on any data field by tagging the field as <i>input-qrcode </i>or <i>input-qrcode-128x128</i>. The QR code is visible if the field has the value. The parameter NAME referenced above is represented by <i>qrcode</i>. The implementation can be found at <i>~/app/js/daf/input-qrcode.js</i>.</p><h2>Release Details</h2><p>The following features, bug fixes, and enhancements, are included in the release:</p><p></p><ul><li>QR Code data input enhancement can be added to any data field with the tag <i>input-qrcode-128x128 </i>with the numbers representing the width and the height of the QR code in the form.</li><li>(Blob) Changes in the image will cause the app to fetch the child dataviews if the views suddenly become visible due to the change of the form layout in response to the image loading.</li><li>(Touch UI) Method <i>$app.touch.summary('fetch') </i>will cause the summary views to fetch data. This method is useful when the layout of the page is suddenly changed and previously invisible dataviews come into focus. If no scrolling has occurred then the data may remain "unfetched" and the fetching can be forced by calling this method.</li><li>(Touch UI) Custom Input Enhancements and QR Code enhancement are now included in the framework.</li><li>(Touch UI) Fixed the migration issues that caused exceptions in the "Search On Start" in summary views.</li><li>(Touch UI) Hiding of the <i>simple </i>or <i>collapsible </i>container without the visible content will not be performed if the container's visibility is controlled by the <i>Visible When </i>property of the category or if this container belongs to the tab page or wizard step.</li><li>(Touch UI) Notifications are not displayed during the page transition to avoid the effect of the shifting page that was visible upon certain conditions.</li><li>(Touch UI) Summary view synchronizes itself with the form placeholder instantly for a better user experience. Previously the visual synching was delayed if the page transitions were detected, which has caused a displaced presentation visible to the user for a short period of time.</li><li>(Framework) Tags <i>auto-(highlight|select)-first-row-(once|always) </i>allows performing auto select or highlight of the first row upon the review of the view data with an option for this to be performed once or always.</li><li>(Client Library) Method <i>dataView.survey() </i>correctly collects the files in the BLOB fields. This resolves the problem with import file uploading and multi-file upload.</li></ul><p></p>Customer Servicehttp://www.blogger.com/profile/04471166550881539854noreply@blogger.com0tag:blogger.com,1999:blog-2297698770491701674.post-153813014413628352021-07-31T04:02:00.208-07:002021-08-01T04:39:18.083-07:00Clipboard, Drag & Drop, Auto-Refresh, Alt Master-Detail, and Property Grid<p>Code On Time release 8.9.21.0 introduces the clipboard and data drag & drop support in Touch UI. Dashboard data controllers can be enhanced to perform automatic refresh of the DataView fields according to the specified interval. DataView fields can also be connected into master-detail relationships even if there are no natural foreign key relationships. The <i>Property Grid</i> is the new exciting feature of the framework - keep reading to learn more!<br /> </p><div><h2>Clipboard & Drag & Drop</h2><div>In a matter of minutes developers can configure the app to allow <a href="https://codeontime.com/blog/2021/07/drag-cut-copy-and-paste-your-data">Cut/Copy/Paste and dragging of items</a> from one data view to another. A simple programming model makes it easy to implement processing for the system commands <i>CutPaste</i>, <i>CopyPaste</i>, and <i>DragDrop</i>. The persistent clipboard allows moving data from a data view on one page of the app to another. </div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6cZ2ktqPR7QO6xHkncwfpqLrnkd7QGwhU_JZOwL-RQfiRtOMxFhzqQvDBbHzVBA2zEi7gKaGmOcXKhRVkgr7fL1_DanzS-oCWjAndqEIDFsaUO4xLLldifFVBm7kQKxwlrPq3-EkBF18z/s928/08-touch-ui-item-drag-to-move-end.jpg"><img border="0" data-original-height="700" data-original-width="928" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6cZ2ktqPR7QO6xHkncwfpqLrnkd7QGwhU_JZOwL-RQfiRtOMxFhzqQvDBbHzVBA2zEi7gKaGmOcXKhRVkgr7fL1_DanzS-oCWjAndqEIDFsaUO4xLLldifFVBm7kQKxwlrPq3-EkBF18z/s16000/08-touch-ui-item-drag-to-move-end.jpg" /></a><br /></div><div><br /></div><div><h2>Auto-Refresh in DataView Fields</h2><div>DataView fields of a data controller can now be configured to refresh after a specified interval. Specify the <i>Refresh Interval p</i>roperty in the Data View section of the data field in the “form” view. The interval is expressed in seconds.</div><div><br /></div><div>This feature can be useful when implementing the monitoring dashboards. The framework will ensure that the app is not busy and the dataview is interactive and visible to the user when performing the synchronization of the view data with the server.</div><div><br /></div><h2>Alternative Master-Detail Linking in Forms</h2><div>DataView fields can have a master-detail relationship with the other DataView fields in the form even if there is no natural foreign key relationship between them. The <a href="https://codeontime.com/blog/2021/07/drag-cut-copy-and-paste-your-data">Clipboard and Drag & Drop</a> tutorial demonstrates this in action by setting the link between the orders and the menu of products. The property<i> Filter Source</i> of the products is pointing to the orders and no filter fields are specified. If the order selection is changed then the products are refreshed. The server-side code can perform custom filtering based on the arbitrary condition.</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhh1atDLqrP7kd51eO1mHRILkjvsbuKsK8DjwOzBS4Ycl-I9nqKVPeUUMQ7xuSkNcs5DPsumb1jyIB0Fk0mOX4-LeMW06f4QNZCBSitJtxUI1M7gkeyRcp2butgvEwb1I-2esumDH3fo8eB/s1328/05-touch-ui-item-paste.jpg"><img border="0" data-original-height="876" data-original-width="1328" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhh1atDLqrP7kd51eO1mHRILkjvsbuKsK8DjwOzBS4Ycl-I9nqKVPeUUMQ7xuSkNcs5DPsumb1jyIB0Fk0mOX4-LeMW06f4QNZCBSitJtxUI1M7gkeyRcp2butgvEwb1I-2esumDH3fo8eB/s16000/05-touch-ui-item-paste.jpg" /></a></div><div><br /></div><div><h2>Announcing Property Grid</h2><div>We are pleased to announce that the new feature called <i>Property Grid</i> is now included in the framework. The screenshot shows the property grid displayed in response to the inspection of the display object on the page, that was constructed with the <i>Content Hub Add-on</i> and <i>Display Flow</i>. </div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEf2kqF5Y50tvt37FfPQ8yn9i8ZTX14P1ihmsbiaLqFD4MPD3Ugwsr0-8ejfagC2RCq-JQ6qTybsmiRZJ6KHqXfciu47bcBV7iO2RZq9v0bTqH73Y26F_wcI5tx-9TBxmIA_IadiMKKrUg/s1124/25-touch-ui-prop-grid.png"><img border="0" data-original-height="977" data-original-width="1124" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEf2kqF5Y50tvt37FfPQ8yn9i8ZTX14P1ihmsbiaLqFD4MPD3Ugwsr0-8ejfagC2RCq-JQ6qTybsmiRZJ6KHqXfciu47bcBV7iO2RZq9v0bTqH73Y26F_wcI5tx-9TBxmIA_IadiMKKrUg/s16000/25-touch-ui-prop-grid.png" /></a></div><div> </div><div><div>Soon you will see the <i>Property Grid </i>in the development mode of your own apps when configuring the <i>~/app/touch-setting.json </i>or the project properties. The same component will be sliding out from the side of the screen when editing the content in the upcoming community site and when building the data-driven surveys at runtime.</div><div><br /></div><div><i>Property Grid</i> is the Touch UI form driven by the metadata. The developer-friendly data input mode with the comprehensive keyboard support makes the grid suitable for various configuration tasks when building apps and content. It will be also possible to tag a form view as a property grid. The form view configuration will be converted into the <i>Property Grid </i>metadata by the framework at runtime and the end user will be presented with a sliding panel to edit the data.</div><div><br /></div><h2>Release Details</h2><div>The following features, enhancements, and bug fixes are included in the release:</div></div></div><div><ul style="text-align: left;"><li>Data Clipboard with support for Cut/Copy/Paste and Drag & Drop</li><li>(Inline Editor) Focus frame is not visible when the grid with a large number of columns is scrolled and the focused field is out of view.</li><li>(Blob) <a href="https://codeontime.com/blog/2021/06/drawing-pad">Default blog image</a> is triggered on the existing record. Previously this happened only if the existing blob was cleared.</li><li>(Touch UI) Removed the delay context scope reset when the panel action is executed on close. This eliminates the problem with the incorrect set of actions in the form views.</li><li>(Clipboard) If the data view is tagged as <i>view-paste-Controller </i>or <i>view-drop-Controller </i>then the current row or target row is ignored. Only the master values are supplied for the row representing the target of Paste or Drop.</li><li>(Cloud On Time) The app will not raise an exception when processing requests without the <i>UserAgent </i>header received from <i>Cloud On Time</i> during the custom app installation.</li><li>(Touch UI) Externalized the CSS rule that controls the visibility of the child dataview to improve performance.</li><li>(Touch UI) Child dataview field will behave as a dependent even the <i>Filter Fields </i>are not specified. The property <i>Context Fields </i>will be set to the value of the filter and is passed to the server for custom filtering with the access control rules.</li><li>(Touch UI) If the dependent data view of the master-detail relationship is not visible and there are no other visible elements in the simple or collapsible container then the container is also hidden until a data item the master data view is selected.</li><li>(Client Library) Method <i>dataView.syncOnce() </i>will synchronize the dataview when it stops being busy and is on the active page and ready for interaction. The first argument of the method specifies the name of the child DataView field. The corresponding dataview will be synced when the argument is specified. The second argument will force the immediate attempt to sync if set to true. </li><li>(Touch UI) Property <i>Refresh Interval</i> of the DataView field on the form will cause the data to refresh after the period of time expressed in seconds.</li><li>(Classic UI) Method <i>dataView.data()</i> returns an object with correctly assigned "unmodified" properties. Previously the "null" value was assigned to the property that was not changed.</li><li>(Classic UI) Method <i>dataView.data() </i>returns an object with correctly assigned "unmodified" properties. Previously the value "null" was assigned to the property that was not changed.</li><li>(Client Library) Simplified the <i>dataView.survey() </i>method by removing the legacy processing of Classic UI.</li><li>(Client Library) Data objects returned by the method <i>dataView.data() </i>invoked on an instance of the data view will not have the "_modified" property with the properties of the original row instance. Invoke the method with the 'modified' parameter if you require the "changes" included.</li><li>(Clipboard) Method <i>$app.clipboard.paste() </i>will raise the client-side CopyPaste|CutPaste|DragDrop in the "Before" and "After" phases. The former may return a "promise" object to delay the command until resolved or false to prevent the command. The latter allows executed the custom in JavaScript upon completion.</li><li>(Framework) DataView fields with have access to the other DataView fields in the same master form if their names are listed in the Context Fields property. For example, <i>MyOrderID=Orders</i> will result in the primary key of the selected order in the Orders field to be available to be used in custom access control rules.</li><li>(Touch UI) Descriptions of items in the context menus have a unified 12px font size and are limited in width.</li><li>(Touch UI) Event <i>keyboardpreview.app</i> is triggered in the scrollable element of the virtual page.</li><li>(Touch UI) Event <i>datainputfocus.app </i>is triggered when the data input is styled to indicate the "focused" state.</li><li>(Touch UI) Notifications are displayed as centered when the docked virtual page is active.</li><li>(Touch UI) Event <i>scrollablepageready.app </i>is triggered on the scrollable wrapper of the virtual page. This event is triggered prior to the page transition and can be used to change the initial vertical scroll position in the form.</li><li>(Touch UI) Event <i>pageautofocus.app </i>is triggered on the active page.</li><li>(Touch UI) Event datainputmove.app is triggered on the current data input instead of the document.</li><li>(Touch UI) Event <i>keyboardnavigation.app </i>is triggered in the scrollable element of the page. Previously this event was triggered on the document.</li><li>(Inline Editor) The handler for <i>keyboardnavigation.app</i> event does not attempt to move the focus if there is no active focus frame of the inline editor.</li><li>(Touch UI) $app.touch.hasFocus() method removes focus from any other focused elements if the element specifed in the argument is focused.</li><li>(Touch UI) Event pageautofocus.app is triggered on the document. If the default is prevented then no attempt to set the focus is performed.</li><li>(Touch UI) Method <i>$app.touch.scrollIntoView() </i>will ensure the visibility of the element specified in the argument.</li><li>(Touch UI) REMOVED. Event beforefocus.app is not triggered anymore.</li><li>(Touch UI) Event <i>datainputlabel.app </i>is triggered on the data input label. If the default is prevented then no attempt to focus the corresponding input is performed. Property Grid of v9 designer uses this event to set the visual focus on the label.</li><li>(Touch UI) Enhanced the app-has-focus removal from the labels/values.</li><li>(Touch UI) Double click/tap on the label of the field in the form will trigger the <i>vdblclick</i> event on the label element.</li><li>(Touch UI) Method <i>$app.touch.layout() </i>will perform the layout of the form. Method must be called if the initially invisible regions of the form layout become visible. <i> Property Grid </i>uses this method when collapsed complex properties and categories are expanded.</li><li>(Touch UI) Method <i>$app.dblClick(elem)</i> will return true if the elements was clicked or tapped twice in the past 500 milliseconds.</li><li>(Touch UI) Double click on the <i>Drop Down List </i>label will cycle the input value.</li><li>(Touch U) The drop down list button has a non-transparent background for improved presentation of input with the long lookup values.</li><li>(Touch UI) Delayed focus removal eliminates blinking of the focus indicators when the value of the input has changed after the focus loss and recovery.</li><li>(AppGen) Application generator creates a valid Visual Studio project when the word "Global" is included in the project name.</li><li>(Touch UI) Data view tagged as <i>class-name-CSS_CLASS_NAME </i>will assign the specified CSS class name to the "div" element of the virtual page.</li><li>(Client Library) Method <i>$app.prettyText(text, capitalize) </i>will capitalize the leading character if the second argument is set to true.</li><li>(Client Library) Method <i>$app.prettyText </i>now detects the national Unicode upper-case characters and treats as words the sequences of numbers. For example, the following calls will return the arguments with 3 spaces placed in front of the upper-case letter and the first digit:<br /> x1 = $app.prettyText('NextNewYear2021');<br /> x2 = $app.prettyText('PróximoAñoNuevo2021');<br /> x3 = $app.prettyText('ΕπόμενοΝέοΈτος2021'),</li><li>(Touch UI) Fixed issued with the incorrectly migrated labels when input-blob.js was extracted from touch.js.</li><li>(REST) Robust processing of REST API request to <i>~/_invoke/auth </i>for authentication to obtain and renew the tokens.</li><li>(REST) Server-side framework implements the _invoke/auth API to allow obtaining and refreshing the access tokens.</li><li>(Framework) Refactored application services to support handlers with custom parsing of arguments to support the REST 2.0 and the upcoming Graph QL engine.</li><li>(AppGen) Fixed incorrect references to the ReportViewer DLLs v14 and v15.</li><li>(AppGen) Projects based on the class library will correctly copy the runtime-loaded minified *.js files to the <i>~/app/js </i>folder of the solution. That includes touch-draw, daf-search, daf-import, and daf-flow.</li><li>(Touch UI) Last input focus is restored on mouse-driven devices if the dragged away modal form restores its position in response to the user's click on the background.</li><li>(Touch UI) Windows focus will not cause an exception when the core framework is still being constructed.</li><li>(Classic UI) Fixed the problem with uploading of images in BLOB fields.</li><li>(Classic UI) Font preloading instruction is not included in the HTML pages.</li><li>(Framework) Nielsen Batista has contributed the pt-BR localization. Submit your own files with the support and we will have them included in the future releases of the product.</li></ul></div>Customer Servicehttp://www.blogger.com/profile/04471166550881539854noreply@blogger.com0tag:blogger.com,1999:blog-2297698770491701674.post-60640840807589198492021-07-30T14:35:00.340-07:002021-08-01T23:29:09.085-07:00Drag, Cut, Copy, and Paste Your Data<p>Clipboard is an indispensable tool if you are composing an email, creating a document, or writing code. “Cut and paste” helps us to rearrange our thoughts. “Copy and paste” comes handy when we are out of ideas.</p><p>An input field in a custom business app provides instant access to the system clipboard when editing a value. A selected fragment of text can be dragged and dropped into a new position. App users work with the collections of data items. A data item represents a group of related fields. Wouldn't it be great to take advantage of the clipboard and drag & drop to copy or move the items between or within the data collections?</p><h2>Clipboard and Drag & Drop With Structured Data</h2><p>The clipboard commands and drag & drop can benefit a business app when applied to the structured data. Consider the <i>Order Management Dashboard </i>presented below. </p><p>You can see the end user dragging the product from the menu and dropping it directly on the list of details of the selected order. The product <i>Boston Crab Meat </i>is semi-transparent in the menu of 77 products while it is being dragged. The “drop” frame outlines the <i>Order Details </i>as a target accepting the product. The mouse pointer is displayed as the “copy” arrow. The tooltip with the name of the dragged item is shown next to the pointer.</p><p> </p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIxOiC5TbFMTtsSA-UVKsWCrc32Myx8ZA6xEBEuG6JbFSHV1N1ncYCO98cw1lqIJUv7HqXq1k0uW5znXBBJ2otUFnxFtE_CZW0nYtYuL8q1IOPi2WPZIWfftPP8kjs2TmcdzY2WnzB4Chk/s1328/01-touch-ui-item-dragging.jpg"><img border="0" data-original-height="876" data-original-width="1328" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIxOiC5TbFMTtsSA-UVKsWCrc32Myx8ZA6xEBEuG6JbFSHV1N1ncYCO98cw1lqIJUv7HqXq1k0uW5znXBBJ2otUFnxFtE_CZW0nYtYuL8q1IOPi2WPZIWfftPP8kjs2TmcdzY2WnzB4Chk/s16000/01-touch-ui-item-dragging.jpg" /></a></div><p>The result of the product “drop” is shown next. The product is no longer visible in the menu of 76 products presented on the right-hand side of the dashboard. The dropped product is now linked to the selected order. It is visible in the list of details. The “drop” frame has disappeared.</p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6blTyecmC8w3Rc00wdBX0l7T5zoSxIehLd54xCx5sPXzQJ2fjwCB9UTfjFVqZHApPEPvjGa_MgBfqoKDgp-zzve0aDg4lfQdTy8yQdQM4tBuFP9xQ_snQGaZgpGJ-KhTGJfDUrDGxOuRV/s1328/02-touch-ui-item-dropped.jpg"><img border="0" data-original-height="876" data-original-width="1328" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6blTyecmC8w3Rc00wdBX0l7T5zoSxIehLd54xCx5sPXzQJ2fjwCB9UTfjFVqZHApPEPvjGa_MgBfqoKDgp-zzve0aDg4lfQdTy8yQdQM4tBuFP9xQ_snQGaZgpGJ-KhTGJfDUrDGxOuRV/s16000/02-touch-ui-item-dropped.jpg" /></a></div><p>The following screenshot shows the state of the dashboard just moments after the user has started dragging the product. The list of details is still empty. The mouse pointer is a no-drop icon indicating that the drop is not accepted in the current position. The “drop” frame will appear when the pointer is over the list of details.</p><p> </p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6wM7VhEFK90TedK-vp0l7U6TWCU0IQdMQVnrU7xbQLgLPOxELT5xe1ryulDnKssyDm4X-eOOV7JO2aiu2TDGg8LwrgOkQTjjPKHz4R6v0VyGhLKprQFydwCDoM0EvByv_z7AnATW_ZmBE/s1328/03-touch-ui-item-no-drop.jpg"><img border="0" data-original-height="876" data-original-width="1328" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6wM7VhEFK90TedK-vp0l7U6TWCU0IQdMQVnrU7xbQLgLPOxELT5xe1ryulDnKssyDm4X-eOOV7JO2aiu2TDGg8LwrgOkQTjjPKHz4R6v0VyGhLKprQFydwCDoM0EvByv_z7AnATW_ZmBE/s16000/03-touch-ui-item-no-drop.jpg" /></a></div><div><div> <br />The end user can select the <i>Copy </i>command from the context menu of a product. The “drag indicator” doubles as the “more” menu when tapped or clicked. The command is also visible on the toolbar of the <i>Products </i>grid.</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyU3_cyIdbMybjO9gn-H7NaZhsGE-t3ZFcO5OjRNhTexk7ri84lvD1C41ALCVz8EeeeCMepm6N2FbnVXJLTAMAImWzeuoqd82mTyINzbUVgqOV06rpfKZGeGe12KM43e6wNWF1cYCWTZ3_/s1328/04-touch-ui-item-copy.jpg"><img border="0" data-original-height="876" data-original-width="1328" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyU3_cyIdbMybjO9gn-H7NaZhsGE-t3ZFcO5OjRNhTexk7ri84lvD1C41ALCVz8EeeeCMepm6N2FbnVXJLTAMAImWzeuoqd82mTyINzbUVgqOV06rpfKZGeGe12KM43e6wNWF1cYCWTZ3_/s16000/04-touch-ui-item-copy.jpg" /></a></div><div> <br />Here is the result of the <i>Paste </i>command executed three times on the <i>Order Details</i>. The product <i>Aniseed Syrup </i>has disappeared from the menu of products, which is now reduced to 75 items. The product is visible in the list of order details with the quantity set to 3. The <i>Paste </i>command on the toolbar of the details shows the tooltip with the description of the copied item and its source.</div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHEkvNBC6VCPDBCKUkx0StVcOC0YanFkYV0lZ2NuFjfncldEVDEYiwhHjyHproE1tQjUgDo-3zAJMDn9QGUoCESNVGHYyZXHEUifEXzau7zwaRkqz7Z7Mi2k5DP-0ZhfgEzVIzSKeA52c9/s1328/05-touch-ui-item-paste.jpg"><img border="0" data-original-height="876" data-original-width="1328" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHEkvNBC6VCPDBCKUkx0StVcOC0YanFkYV0lZ2NuFjfncldEVDEYiwhHjyHproE1tQjUgDo-3zAJMDn9QGUoCESNVGHYyZXHEUifEXzau7zwaRkqz7Z7Mi2k5DP-0ZhfgEzVIzSKeA52c9/s16000/05-touch-ui-item-paste.jpg" /></a></div> <br /><div><div>This application also enables the drag & drop capabilities for the <i>Shippers</i>. It may be useful when implementing the rearranging of items. </div><div><br /></div><div>The “drag indicator” icon is shown in each row next to the values in the first column of the grid. It replaces the standard “more” icon. The mouse pointer switches to the “grab” style when hovering over the icon. It prompts the end user that the corresponding item can be dragged.</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0VfTjxCg2HK5exR_w7SZVqyEGmZe45J0VIuNDIexyHF1yS2Nix-M6sKpc2fkK9FfO8J31Wf2oIQAYkTn18cW2hoWo_AArhm52DHxnfzNK9SElt8s1_-NCA8t3K8bRAlnS4byXB90MhZd0/s928/06-touch-ui-item-drag-to-move-start.jpg"><img border="0" data-original-height="700" data-original-width="928" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0VfTjxCg2HK5exR_w7SZVqyEGmZe45J0VIuNDIexyHF1yS2Nix-M6sKpc2fkK9FfO8J31Wf2oIQAYkTn18cW2hoWo_AArhm52DHxnfzNK9SElt8s1_-NCA8t3K8bRAlnS4byXB90MhZd0/s16000/06-touch-ui-item-drag-to-move-start.jpg" /></a></div><div><br /></div><div>Dragging of the item will switch the pointer to “no-drop” when dragging over the targets that do not accept the drop. The dragged item is semi-transparent and the tooltip next to the system pointer explains what is being dragged.</div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYcFvGF73ONq8e1USVgupa1Bh6muWetzYfu8g-gBXNbThpdVJ_b_XJMCjD5q3YW9DTPq4ozizz6IEAdd68zTYV5MjlxRqVtDMloCxlIfhGBWvs2oEMRcQfauznvLmSDGDbo6aie-d9AGwx/s928/07-touch-ui-item-dragging.jpg"><img border="0" data-original-height="700" data-original-width="928" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYcFvGF73ONq8e1USVgupa1Bh6muWetzYfu8g-gBXNbThpdVJ_b_XJMCjD5q3YW9DTPq4ozizz6IEAdd68zTYV5MjlxRqVtDMloCxlIfhGBWvs2oEMRcQfauznvLmSDGDbo6aie-d9AGwx/s16000/07-touch-ui-item-dragging.jpg" /></a></div><br /><div><div>The list of shippers is configured to accept the drop of its own items. The mouse pointer style is “move” when hovering over the items in the same list. </div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3VHlSMEQ43U63vZaVChGNju9vatt2dhKFjZr0Sm5dwDJ-15Xkrn_x2QYyKdAvN1uS2gVkuvUahZmLjPee4gxoNuvO3XglajMPFJayBEHwkNSR5RnWSMdGnIoWcRsUTDJf5m5jgmxuNP-f/s928/08-touch-ui-item-drag-to-move-end.jpg"><img border="0" data-original-height="700" data-original-width="928" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3VHlSMEQ43U63vZaVChGNju9vatt2dhKFjZr0Sm5dwDJ-15Xkrn_x2QYyKdAvN1uS2gVkuvUahZmLjPee4gxoNuvO3XglajMPFJayBEHwkNSR5RnWSMdGnIoWcRsUTDJf5m5jgmxuNP-f/s16000/08-touch-ui-item-drag-to-move-end.jpg" /></a></div><br /><div><div>Dragging to the other user interface elements of the Shippers grid will cause the entire list to become the “drop” target.</div></div><div><br /></div><div><span id="docs-internal-guid-dc094dc2-7fff-6279-65a6-a4dc4a8752db"><div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFxNyby8bnLB1VT6YT0jwn2hpPcEQbrKI9cNMpMK74YMKgbQnA_V5tQpvEWyQNW_owbC-p-5W-SLopWe8zQzs3H0yjq60BTRfyoPoG1r59QK4o6pK8IL4FMV09laMYYeDLMh1aTxudHF3t/s928/09-touch-ui-item-drag-over-list.jpg"><img border="0" data-original-height="700" data-original-width="928" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFxNyby8bnLB1VT6YT0jwn2hpPcEQbrKI9cNMpMK74YMKgbQnA_V5tQpvEWyQNW_owbC-p-5W-SLopWe8zQzs3H0yjq60BTRfyoPoG1r59QK4o6pK8IL4FMV09laMYYeDLMh1aTxudHF3t/s16000/09-touch-ui-item-drag-over-list.jpg" /></a></div></div><div><div> </div><h2><span><span>Cut/Copy/Paste and Drag & Drop in Touch UI</span></span></h2><span><span>Touch UI provides the built-in data clipboard with the persistent state. System actions Cut/Copy/Paste and item dragging is enabled in the app with the simple tagging of the corresponding data views. Commands <i>CutPaste</i>, <i>CopyPaste</i>, and <i>DragDrop</i> are automatically executed by the framework in response to the user actions. Developers can create custom JavaScript, SQL, and Code business rules responding to the commands. The command argument indicates the name of the source data controller. Developers have access to the target row of the command and the row that was cut, copied, or dragged. The source row fields are prefixed with the name of the source data controller. There is no built-in processing for the commands and their interpretation and security is left up to the application developers.
If multiple items were copied, cut, or dropped, then the corresponding command is executed for each item in the context of the transaction. The successful execution of the command for all items will result in the automatic commit. An error will rollback the effect of <i>CutPaste</i>, <i>CopyPaste</i>, and <i>DragDrop </i>for all items.
Clipboard objects created with <i>Cut </i>and <i>Copy </i>commands are available to all pages of the application. This makes it possible to offer a comprehensive clipboard experience with the structured data. The clipboard contents remain persisted until the next Cut/Copy is executed by the user. This enables pasting the same data multiple times. Developers may opt to clear the clipboard after each <i>CutPaste </i>or <i>CopyPaste </i>command when needed.
The unique unified data processing of Touch UI allows creating a consistent clipboard and drag & drop experience for the structured data.
Let’s learn how to build this <i>Order Management Dashboard</i>.</span></span></div><div> <br /><span><span></span></span><h2><span><span>Dashboard Configuration</span></span></h2><span><span>Begin by creating a new project with Code On Time. Connect to the instance of the Northwind database. Create the following models with the default settings: <i>Orders</i>, <i>Customers</i>, <i>Employees</i>, <i>Shippers</i>, <i>OrderDetails</i>, <i>Categories</i>, <i>Products</i>, and <i>Suppliers</i>.
Optionally configure the orders to sort by dates with the most recent ones at the top.
Activate the project designer and create the new custom data controller with the name <i>Dashboard1</i>. This controller is not based on any data model. Select <i>Orders</i>, <i>OrderDetails</i>, and <i>Products </i>controllers with Ctrl+click and choose Copy in the context menu of either one of them.
Right-click the Dashboard1 controller and choose Paste. This will create the corresponding DataView fields.
Set the <i>Filter Source </i>of <i>OrderDetails</i> field to <i>Orders</i> and <i>Filter Field #1</i> to <i>Order ID</i>. This will enable the master-detail relationship between the <i>Orders</i> and the <i>Details </i>in the dashboard. If the order is selected, then the details will be filtered to show the linked items.
Set the <i>Filter Source </i>property of the <i>Products </i>field to <i>Orders </i>but do not select any filter fields. The product menu will behave as any other detail in the master-detail relationship. It will hide if there is no order selected in the dashboard. It will show up and refresh when the order selection has changed. The server-side code will also have access to the primary key of the order.
Create the view <i>form1</i>, set its type to <i>Form</i>, the label to <i>Order Manager</i>, and tag it as <i>material-icon-category</i>.
Create two categories in the <i>form1</i>. Set the flow of both categories to <i>New Column</i>. Rename the categories by selecting the corresponding command in the context menu to <i>orders </i>and <i>products</i>.
Drag the <i>Orders </i>and <i>OrderDetails </i>fields to the first category. Set the <i>Page Size </i>of the <i>Orders </i>data field to 3. Also set its <i>Auto Highlight First Row</i> to <i>Yes</i>. This will ensure that only the three most recent orders are visible with the first one selected when the dashboard is loaded. Next set the <i>Page Size </i>of the <i>OrderDetails </i>data field to 25.
Drag the <i>Products </i>field to the second category and set the <i>Page Size </i>of the created data field to 7.
The <i>Dashboard1 </i>data controller will look like this in the Project Designer on the Controllers tab.</span></span></div><div><span><span> </span></span></div><div><span><span><br /></span></span></div><div><span><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCrdC8Ovf8m3EMUaUmtP-JmCu5XQrKgwAFFToQohZX4ni482HMRw41oe3X8B1eNYflZ3e5oLfe3vReeYBhj-diFlPwEGasmmvGs9cERwezMXJ-EnwGU4I8shcjST_zzJgyUjXyE7apKT5S/s463/12-order-management-dashboard.png"><img border="0" data-original-height="463" data-original-width="211" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCrdC8Ovf8m3EMUaUmtP-JmCu5XQrKgwAFFToQohZX4ni482HMRw41oe3X8B1eNYflZ3e5oLfe3vReeYBhj-diFlPwEGasmmvGs9cERwezMXJ-EnwGU4I8shcjST_zzJgyUjXyE7apKT5S/s16000/12-order-management-dashboard.png" /></a></div><span><br /></span></span></div><div><span><span>Now it is time to configure the Cut/Copy/Paste and Drag & Drop.
Tag the <i>Dashboard1 / views / form1 / orders / OrderDetails </i>data field as shown below to enable the pasting and dropping of <i>Products </i>into <i>Order Details</i></span></span></div><div><i><br /></i><span><span><blockquote>item-paste-Products item-drop-Products</blockquote></span></span></div><div><span><span>
Tag the <i>Dashboard1 / views / form1 / products / Products </i>data field with the following tags to enable Cut, Copy, and dragging of <i>Products:</i></span></span></div><div><i><br /></i><span><span><blockquote>item-cut item-copy item-drag myapp-product-menu
</blockquote></span></span></div><div><span><span>The custom tag <i>myapp-product-menu </i>will be used later when filtering the product menu.
Create the page called <i>Dashboard </i>and drag it after the <i>Home </i>page. Copy and paste the data controller <i>Dashboard1 </i>onto the page. Set its property <i>Show Action Buttons </i>to <i>None</i>. Enter <i>Wide </i>in the <i>Icon / Custom Style </i>property to remove the sidebar on the page.
The visual configuration of the dashboard is now complete!</span></span></div><div> <br /><span><span></span></span><h2><span><span>Implementing Paste and Drop</span></span></h2><span><span>Commands <i>CopyPaste</i>, <i>CutPaste</i>, and <i>DragDrop </i>are executed on the <i>OrderDetails </i>data controller when the user pastes the previously cut or copied product or drags and drops one from the product menu onto the view.
We will create a single SQL business rule to handle all of these situations. Our objective is to insert or update a record in the Order Details table.</span></span></div><div><span><span><br /></span></span></div><div><span><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYRQOrltCPRo6oM79D9KsbILxDLE5mrKdCuNSagSUulB1oMn7lPK272XYtHduBWyY5tk6o1H-1D2EumwwsFfNCeGYs07jKu_JJPUY6R1QEssjI3qiZJi0d1oX4Rnn_wMEnOLn1n0wKei0n/s646/19-database-diagram.png"><img border="0" data-original-height="442" data-original-width="646" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYRQOrltCPRo6oM79D9KsbILxDLE5mrKdCuNSagSUulB1oMn7lPK272XYtHduBWyY5tk6o1H-1D2EumwwsFfNCeGYs07jKu_JJPUY6R1QEssjI3qiZJi0d1oX4Rnn_wMEnOLn1n0wKei0n/s16000/19-database-diagram.png" /></a></div></span></div><div><span><br /></span></div><div><span> </span></div>Create a new SQL business rule in the <i>OrderDetails </i>data controller. Set its phase to <i>Execute </i>and its <i>Command Name </i>to <i>CutPaste|CopyPaste|DragDrop </i>regular expression. Enter the following script:</span></div><div><span> </span></div><div><span><br /></span></div><div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXUa_HPS3KJfX4POiu8HEeJFC8TO50rssQionR17cPjyG4zQSdWhU5aBpLjfkgQdC-5pAAN5svUKkGT-MI6qqvt8rjgOpgYxaEz6wb9Gq9HIdWcmv9rHuLmFwaF0SBh1zDlbyHPt9BP_Ft/s574/18-order-details-sql-business-rule.png"><img border="0" data-original-height="166" data-original-width="574" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXUa_HPS3KJfX4POiu8HEeJFC8TO50rssQionR17cPjyG4zQSdWhU5aBpLjfkgQdC-5pAAN5svUKkGT-MI6qqvt8rjgOpgYxaEz6wb9Gq9HIdWcmv9rHuLmFwaF0SBh1zDlbyHPt9BP_Ft/s16000/18-order-details-sql-business-rule.png" /></a></div><div><br /></div>The business rule is triggered when the command with the name matching the regular expression is detected by the app framework on the server. </div><div><div><br /></div><div>The SQL script will attempt to increment the <i>Quantity </i>column of the existing<i> [Order Details] </i>row with the product ID matching the parameter <i>@Products_ProductID</i>. This parameter is supplied by Touch UI and its value is set to the dragged, cut, or copied <i>ProductID</i>. Note that it is possible to access any other property of the product by specifying the name of the data controller as a prefix separated with the underscore character from the field name.</div><div><br /></div><div>Touch UI also supplies the value of the parameter <i>@OrderID</i>. It is set to the value of the <i>OrderDetails.OrderID </i>field in the “drop” or “paste” target item. If the target is the entire <i>Order Details </i>view then the field values are set to NULL with the exception of the fields specified in the <i>Filter Fields </i>property. The values of these fields are borrowed from the selected master row. The business rule has the value of the selected <i>OrderID </i>regardless of the drop or paste target.</div><div><br /></div><div>If no rows have changed after UPDATE then the SQL business rule will INSERT an order detail with the same product and order identifiers with the quantity of 1.</div><h2>Filtering Items in the Product Menu </h2><div>Let’s make it so that the product menu in the dashboard is empty unless an order is selected. </div><div><br /></div><div>Choose the <i>Products </i>data controller in the Project Designer and set its <i>Handler </i>property to <i>ProductsBusinessRules. </i>Browse the app to generate the placeholder file <i>~/app/App_Code/custom/Rules/Products/ProductBusinessRules.cs</i>. Right-click the controller and choose <i>Edit Handler in Visual Studio</i>.</div><div><br /></div><div>Enter the following code:</div><div> </div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVh5jTOv71ZaGY5Q34YtK7Xl2ARUiZaO4kfcdd2Of1bOZ0ULT3X5Ts-y8WAJxV8eoVLjKFvzm1iM003KdtY1z9yOFNOSlfSluIdLOhfl7daWVswj3lfLUUvmTR5foBe9dIwLKPUz8QDGlV/s922/13-proudct-menu-business-rule.png"><img border="0" data-original-height="599" data-original-width="922" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVh5jTOv71ZaGY5Q34YtK7Xl2ARUiZaO4kfcdd2Of1bOZ0ULT3X5Ts-y8WAJxV8eoVLjKFvzm1iM003KdtY1z9yOFNOSlfSluIdLOhfl7daWVswj3lfLUUvmTR5foBe9dIwLKPUz8QDGlV/s16000/13-proudct-menu-business-rule.png" /></a></div><br /><div> </div><div>Method <i>EnumerateDynamicAccessControlRules </i>will impose the access control restrictions when the app is retrieving the data for <i>grid1 </i>view of the <i>Products </i>tagged as <i>myapp-product-menu</i>. This is exactly how the product menu is configured in the dashboard. The name <i>Orders </i>specified in the <i>Filter Source </i>property of the data view field <i>Products </i>is ensuring that the order ID selected in the dashboard is available under the “Orders” alias to the business rules.</div><div><div><br /></div><div>If the order ID is not available, then our list of products will be limited to those with the primary key set to -1. Such products do not exist and therefore the user will see the empty list of products.</div><div><br /></div><div>Otherwise we will deny access to the products that are already linked to the details of the selected order. Such products will not be visible in the product menu.</div><h2>Trying It Out</h2><div>Run the app and try populating order details with Cut/Copy/Paste and Drag & Drop. You will notice that the product menu gets shorter as more details are created in the selected order. The framework automatically syncs the details and the product menu with the server after each successful <i>CutPaste</i>, <i>CopyPaste</i>, or <i>DragDrop</i> command.</div><div><br /></div><div>If you insert a new detail with the help of the New command or delete a few details from the order then the product menu will become out of sync. The selected order is not changed if you perform these operations. The menu will have to be refreshed manually. </div><div><br /></div><div>Copy and Cut commands move data to the app clipboard. The data remains there even when you refresh the page or restart the browser and sign in with the user identity. You may want to clear the clipboard after each Paste. </div><div><br /></div><div>Paste and Drop do not display a confirmation message and execute instantly. There may be circumstances when the user assent is required.</div><h2>JavaScript Business Rules</h2><div>Let’s perfect the syncing of the product menu and provide some pre and post processing when products are pasted or dropped onto the order details.</div><div><br /></div><div>Create the file<i> ~/app/js/dragdrop.js </i>with the following code. It declares the <i>syncProductMenu()</i> function and the custom client-side business rules for <i>OrderDetails</i>.</div></div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgciz6OEe0hT1653klrqltr_jXGizLRdGmqgZSXdm-X3OAK-pJi9uIWSzg6UNSSyx1XedX8lx4ICBfAG_T54OQrDqY1JhosbdFTiUvWY7BWNEMlgT067APpY3ksO4z93RapqqlO3OL9A8oV/s769/17-dashboard-javascript-business-rules.png"><img border="0" data-original-height="641" data-original-width="769" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgciz6OEe0hT1653klrqltr_jXGizLRdGmqgZSXdm-X3OAK-pJi9uIWSzg6UNSSyx1XedX8lx4ICBfAG_T54OQrDqY1JhosbdFTiUvWY7BWNEMlgT067APpY3ksO4z93RapqqlO3OL9A8oV/s16000/17-dashboard-javascript-business-rules.png" /></a></div><br /><div>The function <i>syncProductMenu() </i> will locate the product menu on the dashboard and request it to sync once. The default ID of the <i>Dashboard1 </i>data controller instance is view1. The name of the dataview field <i>Products </i>is specified as the argument of <i>syncOnce </i>method. This method will wait for the user interface to stop being busy and sync the data. Subsequent calls to <i>syncOnce </i>will cancel the previous requests to avoid redundant calls. Use this method whenever a dataview on the page requires a data refresh.</div><div><div><br /></div><div>The business rule responding to the <i>CopyPaste </i>command will interrupt the execution and display a confirmation. The method <i>$app.confirm </i>returns a promise to the framework. Touch UI will proceed to execute the command if the promise is resolved, which happens when the user agrees to proceed by pressing the OK button in the confirmation prompt. </div><div><br /></div><div>The post-processing will sync the product menu after the details are inserted or deleted.</div><div><br /></div><div>If the copy <i>CopyPaste </i>command has completed successfully, then a custom confirmation with the text describing the clipboard contents is displayed.</div><div><br /></div><div>The command <i>CutPaste </i>is followed by the clearing of the clipboard.</div><div><br /></div><div><h2>Advanced Techniques</h2><div>The default scope of the app clipboard is “global”. Data placed in the clipboard is available on all pages of the app to Paste. You can limit the scope of the clipboard to the current page by setting the option <i>clipboard.scope</i> to “local” in <i>~/app/touch-settings.json</i> file.</div><div><br /></div><div>Tags<i> item-paste-Controller</i> and <i>item-drop-Controller </i>make it possible for the user to target individual items in the data view. End users can also paste and drop data by targeting the entire view. There will be situations where the items shall not become the target. Tag <i>view-paste-Controller </i>will make it possible to paste only through the context menu of the dataview. Tag <i>view-drop-Controller </i>will cause the drop target to extend to the entire view when its item is target. </div><div><br /></div><div>Cut/Copy/Paste and Drag & Drop are relying on the clipboard to accumulate and perform execution of the <i>CutPaste</i>, <i>CopyPaste</i>, and <i>DragDrop</i> commands. There is no default interpretation for these commands. If your app is relying on the Offline Data Processor to allow transaction input of master-detail records, then the server-side execution of these commands makes little sense. The master-detail data is accumulated and staged by the ODP directly in the WebView. Only the saving of the master record will cause the transaction to be executed on the client. If you want to support the data clipboard and drag & drop with ODP then you will need to write a custom interpretation of the commands in JavaScript.</div><div><br /></div><div>The live app <a href="https://demo.codeontime.com">https://demo.codeontime.com</a> allows cutting and pasting products between supplier and category masters. ODP is enabled on the Categories and Products pages, since their <i>Offline</i> property is set to <i>yes</i>. ODP is enabled in the "offline" pages loaded in the web browser and also in the disconnected mode when the app is hosted in Cloud On Time. following script implements a custom <i>CutPaste</i> and <i>CopyPaste</i>, which will replace the category or the supplier of the pasted product.</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkuPYMmTyr_dxzzn8Bej-mC-viZ1AYgSNJYvJyQa8VSdROUXKw-JpW7nc7ClISUMtvUxSfuz72gxGi1Av9Doa7XllVPyCyrpFV79NeYz9J-dNO73VtdR3G1rE4cb1Qk71z6X0TXcQ29zoa/s1169/20-advanced-odp-based-paste.png"><img border="0" data-original-height="1169" data-original-width="930" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkuPYMmTyr_dxzzn8Bej-mC-viZ1AYgSNJYvJyQa8VSdROUXKw-JpW7nc7ClISUMtvUxSfuz72gxGi1Av9Doa7XllVPyCyrpFV79NeYz9J-dNO73VtdR3G1rE4cb1Qk71z6X0TXcQ29zoa/s16000/20-advanced-odp-based-paste.png" /></a></div><div><br /></div><h2>Conclusion</h2><div>The dashboard can be further enhanced to allow dragging and dropping the order details onto the product menu to provide an alternative method to delete the details.</div><div><br /></div><div>If the order detail is dropped onto another order, then the detail product can be moved between orders.</div><div><br /></div><div>The dedicated Products page can provide the Copy and Cut commands. The pasting of the products into Order Details will automatically work on the dashboard page since the clipboard contents are persisted.</div><div><br /></div><div>If the items in the dataview have a sequential order, then tagging the dataview as <i>item-drag item-drop-Controller </i>will enable the drag & drop movement of items. Use the physical name of the data controller instead of “Controller” in the tag. Implement the business rule to change the item indexes in the response to the DragDrop command.</div><div><br /></div><div>The consistent user interface of Touch UI makes it possible to create amazing apps with spectacular results that are impossible to achieve with any other tool.</div></div><div><br /></div>Customer Servicehttp://www.blogger.com/profile/04471166550881539854noreply@blogger.com0tag:blogger.com,1999:blog-2297698770491701674.post-31052924485629072362021-06-27T02:13:00.067-07:002021-06-28T09:38:04.612-07:00Modal Form Dragging<p> Release 8.9.20.0 makes your apps even better!</p><p>The responsive forms of Touch UI framework may render in fullscreen mode or as modal popups. Modal forms can now be dragged into arbitrary positions with a touch or mouse pointer. Simply grab the title and move the form to the new position.</p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnnHCO5Q87VPODE7kwsQ0K3jJ6_TZQ0p8DOxpiA1fX9uHpj8EIJPADspx-1f_rvDOji_XBjGEg94ggBVLvi1ysJNYo_9O5tQe1EPcSqrS0uQepmpL46hKBiMlwCCk7zYH4DHGE9cfRG26N/s1008/01-modal-form-dragging.png"><img border="0" data-original-height="870" data-original-width="1008" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnnHCO5Q87VPODE7kwsQ0K3jJ6_TZQ0p8DOxpiA1fX9uHpj8EIJPADspx-1f_rvDOji_XBjGEg94ggBVLvi1ysJNYo_9O5tQe1EPcSqrS0uQepmpL46hKBiMlwCCk7zYH4DHGE9cfRG26N/s16000/01-modal-form-dragging.png" /></a></div>
<p><br /></p><p>Keep dragging the form by the title to reveal more of what is hidden beneath. The forms can be dragged almost entirely offscreen. </p><p><br /></p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXnIE93v3Nc6IadoXzuaZv0UD2sc-5aRdCCPWHJL33LAVome3SdTLXsmg9Z0Unzds0r2MRKWpiNk2b-rF3I1HSk1HeuRq_UeZklC4RPpPI98qQl8igxy0Vgbhm60moEQ3bfORZWBhXut0P/s1009/02-modal-form-drag-offscreen.png"><img border="0" data-original-height="870" data-original-width="1009" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXnIE93v3Nc6IadoXzuaZv0UD2sc-5aRdCCPWHJL33LAVome3SdTLXsmg9Z0Unzds0r2MRKWpiNk2b-rF3I1HSk1HeuRq_UeZklC4RPpPI98qQl8igxy0Vgbhm60moEQ3bfORZWBhXut0P/s16000/02-modal-form-drag-offscreen.png" /></a></div><div><br /></div>Tap on the background to instantly return to the original position. Setting focus on any field in the form will also restore the position. The resizing of the WebView will have the same effect.<br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKrdO4zReU1NNfzHpcL4busR6zAhQVUToltulVGF_gX3bW1hipRDt2dIAYH5BXPdtu1vxdh9Azry2FkJYSKhxuPO-nyrvt99ITGZKHSEd6EfLf1QAINWTHYG4ptpJ-eaxEBmYUmZm3uauM/s1009/03-restored-modal-form-position.png"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKrdO4zReU1NNfzHpcL4busR6zAhQVUToltulVGF_gX3bW1hipRDt2dIAYH5BXPdtu1vxdh9Azry2FkJYSKhxuPO-nyrvt99ITGZKHSEd6EfLf1QAINWTHYG4ptpJ-eaxEBmYUmZm3uauM/s16000/03-restored-modal-form-position.png" /></a><br /><br />Touch UI has a built-in Drag Manager that works with the scrollbars, column dividers, panels, etc. The most recent use case for the drag manager was the <a href="https://codeontime.com/blog/2021/06/drawing-pad">Drawing Pad</a>. Now we have found a new application for this powerful mechanism - modal forms. The following bug fixes are also included in the release:<div> <br /><ul><li>(Touch UI) Modal forms support dragging of the form title.</li><li>(Touch UI) Fixed the issue with the missing function that was not migrated from the touch.js to daf-search.js.</li><li>(Touch UI) Fixed broken background and column width caused by the scrolling of the grid with the data fields that have "column-width-" tag applied to them. <a href="https://codeontime.com/blog/2021/06/responsive-width-of-grid-columns">Use the tag to control the precise width of columns in the grids</a>.</li><li>(Touch UI) Promo button has a pronounced background color change on hover with the mouse pointer.</li><li>(Touch UI) Fixed the broken Lacquer accent rendered in Dark theme.</li></ul><br /></div>Customer Servicehttp://www.blogger.com/profile/04471166550881539854noreply@blogger.com0tag:blogger.com,1999:blog-2297698770491701674.post-21025986717095592752021-06-25T05:38:00.257-07:002021-06-25T16:12:59.222-07:00Drawing Pad, Responsive Grids, Faster Framework<p>Code On Time release 8.9.19.0 introduces the Drawing Pad and Responsive Grid features along with the significantly improved performance of apps based on Touch UI. </p><h2>Performance Enhancements</h2><p>Touch UI is a very compact framework. As of today the total script library payload stands at 405 kB compressed while the only CSS resource is $49.7 kB compressed. The upcoming new feature <i>Content Hub Add-on</i> will transform the framework into the first rate publishing platform. We are remaking our website, this blog, the help desk, and the new community forum as the Code On Time apps. This imposes various <a href="https://web.dev/vitals/" target="_blank">Core Web Vitals</a> requirements and many new features in this release are related to this effort. The framework now performs the pre-loading of web fonts and externalizes the search and import features. As a result all applications re-generated with this release are faster and smaller.</p><p>Images in the list items, cards, and forms are not retrieved unless visible. This feature reduces the number of the requests handled by your applications and also benefits the <i>Content Hub </i>pages with the images.</p><p>Radio Button List lookup instantly triggers the event to inform the app about the value change and then starts playing the button status change animation. Previously the change event would not trigger until the animation has completed. If your forms have the conditional dependencies on the radio button lists, then the new release will make your app appear more responsive.</p><p>Forms with the categories of data fields configured as <a href="https://codeontime.com/blog/2016/09/wizards-in-touch-ui" target="_blank">Wizard </a>steps will appear more responsive if the “steps” include the child DataView fields. The new framework will cause the child data views to fetch values as soon as the “step” contents become visible.</p><p><a href="https://codeontime.com/blog/2020/05/tutorial-barcodes-qr-codes-and-rfid-tags" target="_blank">Kiosk UI and UI Automation</a> are significantly faster. The next update will bring about the Camera-based scanner directly in the application.</p><h2>Drawing Pad</h2><p>If the image is uploaded as the BLOB field, then the <a href="https://codeontime.com/blog/2021/06/drawing-pad" target="_blank">Drawing Pad</a> becomes available.</p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYMZAmRsfGF4wtrDjJUKfFZ0XhyCoEl9HUkcJyvSmxP25VGG9BkhnUfon7_O62J9XP5QlOrtNCLououiJoYUrZIYMC63jVBdvdN-LA4KcpJHjfBFtj8eCgI0QtCCT4nQgOLN7ctyu1TAeT/s726/01-drawing-pad-tools.png"><img border="0" data-original-height="726" data-original-width="669" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYMZAmRsfGF4wtrDjJUKfFZ0XhyCoEl9HUkcJyvSmxP25VGG9BkhnUfon7_O62J9XP5QlOrtNCLououiJoYUrZIYMC63jVBdvdN-LA4KcpJHjfBFtj8eCgI0QtCCT4nQgOLN7ctyu1TAeT/s16000/01-drawing-pad-tools.png" /></a></div><br /><p>Default blob field values can now be provided as icons or external image URLs. The former provides a simple way to create the image placeholders as large colorful material icons.The latter introduces the foundation for sketching in your application. </p><p>The upcoming Content Hub will allow drawing on the user-submitted images and screenshots taken directly from the live application when submitting the help desk tickets or creating the community forum posts.</p><h2>Responsive Grid</h2><p>The new tag <a href="https://codeontime.com/blog/2021/06/responsive-width-of-grid-columns" target="_blank">column-width-(tn|xxs|xs|sm|md|lg|xxl)-NNN</a> makes it possible to specify the default and responsive width for individual columns expressed in pixels.</p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-VBBeUQvr-wOMIcO_iSu-PoWmoMCkUVQ3X2ksj7CHZKxSiOsu_E1E6cgXMYic2PI733Y-Pc8LG0uswalPcB0VT_x_9TIJZ2LVEy1kPaSJNDD4v_KvxffuVzkuYrrAYPDu-0qPWf3iZoaP/s1118/02-sample-grid-column-width.png"><img border="0" data-original-height="929" data-original-width="1118" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-VBBeUQvr-wOMIcO_iSu-PoWmoMCkUVQ3X2ksj7CHZKxSiOsu_E1E6cgXMYic2PI733Y-Pc8LG0uswalPcB0VT_x_9TIJZ2LVEy1kPaSJNDD4v_KvxffuVzkuYrrAYPDu-0qPWf3iZoaP/s16000/02-sample-grid-column-width.png" /></a></div><br /><div><h2>Advanced Search</h2><div>We are hoping that the subtle change to the Advanced Search will increase its usability. The data fields with the “required” and “suggested” search mode are always included in each “Match” group of fields even if some of the suggestions were not used in the previous search. The end user can progressively engage the suggested fields to refine their search.</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6HPGyxxqrlF4NrsIjCeMptc1O4qYvGuEojhOzlnbGhkwMrwijoF4_11r5yhUcmNewFlxrTiPfCqqZx4QP94uHQh74O6alVkHQJBmd7trupKVCP0WEOX20Ru9-t8wDFKD9I16UUccw5vNY/s1119/03-advanced-search.png"><img border="0" data-original-height="932" data-original-width="1119" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6HPGyxxqrlF4NrsIjCeMptc1O4qYvGuEojhOzlnbGhkwMrwijoF4_11r5yhUcmNewFlxrTiPfCqqZx4QP94uHQh74O6alVkHQJBmd7trupKVCP0WEOX20Ru9-t8wDFKD9I16UUccw5vNY/s16000/03-advanced-search.png" /></a></div><div><br /></div><div><br /></div><p>The following features, bug fixes, and performance improvements are included:</p><p></p><ul><li>(Touch UI) Enhanced font preloading and eliminating the transparent/missing icons at 90%, 110% and other irregular zoom values in the Chrome, Edge, and Safari.</li><li>(Touch UI) Clicking anywhere outside of the inline editor will cause auto-post of the row unless initiated with the <i>Escape </i>key<i> </i>or the explicitly selected Cancel command.</li><li>(Touch UI) New tag <i>modal-title-minimal</i> will force the modal form to display a minimal modal title permanently. Typically the minimal title is displayed in the minimal state only if the modal form content is scrolled down.</li><li>(Touch UI) Advanced Search will always display the default suggested and required fields in every match group. Previously the suggestions were not visible and only the previous search conditions were retained. The new behavior makes it easier for the end user to refine their search if the previous search has not yielded the desired result.</li><li>(Universal Input) Enhanced the speed of response of the radio button list. The "click" processing happens before the animation has been completed for a more responsive GUI.</li><li>(Universal Input) Lookup data field tagged as <i>lookup-auto-advance</i> will migrate to the next input in the form.</li><li>(Universal Input) Lookup data field tagged as <i>lookup-auto-advance-row </i>will migrate to the next input in the same row container.</li><li>(Universal Input) Radio button list uses the styling that does not create an empty dot in the middle of the selected radio button list on some monitors. If lookup-auto-advance tag is applied then the "focus" frame is not displayed during the transition from the radio button list to the next input.</li><li>(Blob) <a href="https://codeontime.com/blog/2021/06/drawing-pad">Drawing Pad</a> is available to markup the images directly in the app.</li><li>(Touch UI) Option <i>ui.menu.position</i> controls the position of the navigation menu in the sidebar. The default is <i>top</i>. The second supported value is <i>bottom</i>. Requires <i>ui.menu.location</i> to be set to <i>sidebar </i>in <i>touch-settings.json</i>. Previously the sidebar menu always displayed at the bottom of the sidebar by default.</li><li>(Model Builder) Enhanced serialization of the database metadata uses a simple loop instead of the recursive calls and improves ability to handle huge databases faster. Previously a database with more that 1500 tables has failed to serialize due to the stack overflow.</li><li>(Touch UI) The default dedicated login page created by the app generator is now programmed to allow the app to decide the landing page after the successful login. The URL returned by the method <i>ApplicationServices.UserHomePageUrl()</i> will determine the landing page. The default landing page is <i>~/pages/home</i>. Override the method the partial class implementation to introduce your own landing pages.</li><li>(Touch UI) Wizard form buttons are correctly refreshed when the form is opened in the reading pane.</li><li>(Framework) Logout will not cause the exception in the server-side code when vi-VN culture is set.</li><li>(Touch UI) New tag <a href="https://codeontime.com/blog/2021/06/responsive-width-of-grid-columns" target="_blank">column-width-(tn|xxs|xs|sm|md|lg|xl)-NNN</a> will define the precise width of the grid column for a particular page width.</li><li>(Touch UI) Modal form with fitted height ignores the <a href="(Touch UI) Font preloading instruction is included in the pages automatically.">virtual keyboard </a>stub when calculating the height.</li><li>(Touch UI) Font preloading instruction is included in the pages automatically.</li><li>(Touch UI) Externalized import API into <i>~/js/daf/daf-search.js</i> to reduce the required footprint of Touch UI.</li><li>(Touch UI) Externalized implementation of import into <i>~/js/daf/daf-import.js </i>to reduce the size of the core framework.</li><li>(Framework) Method $app.saveFile(name, text, type) will cause the WebView to display a prompt to save a file with the given name text in UTF-8 encoding with the option type, which defaults to text/plain.</li><li>(Import) Import handles the child data view lookup fields that have their names not matched with the master table field name.</li><li>(Touch UI) Collapsible menu in the sidebar will not be visible when expanding/collapsing transition is intersecting with the sidebar mini calendar.</li><li>(Touch UI) Blob thumbnail will open a "save file" prompt when clicked. Previously the internal preview popup was displayed.</li><li>(Touch UI) Blob thumbnail will open a "save file" prompt when clicked. Previously the internal preview popup was displayed.</li><li>(Blob) If the blob field is tagged as <i>image-user-defined-none</i> then tap on the image will activate the drawing pad. Otherwise the file selection window is presented.</li><li>(Touch UI) Numerous core classes from the legacy jQuery Mobile have been removed for improved performance.</li><li>(Touch UI) Item in the panels do not trigger <i>taphold</i>.</li><li>(Multifile Upload) Drawing pad is available if only one file is selected for upload.</li><li>(Multifile Upload) The names of the files are automatically trimmed if they exceed the length of the "name" field. Previously the upload was rejected due to inability to insert the placeholder record into the database.</li><li>(Framework) The external filter of the parent is passed when actions are executed on the child data view when there is not direct master-detail relationship between the two.</li><li>(Framework) The external filter of the child data view is included with the Execute requests in its forms.</li><li>(Framework) Multi-file upload will pass the external filter of the data view with the Insert requests.</li><li>(Blob) Field tagged as <i>image-editor-none </i>will not allow manipulation of the image on the client.</li><li>(Blob) Clearing of the blob in the form will trigger <i>getdefaultblob.app</i> event on the document to allow the default value to be supplied.</li><li>(Blob) Event <i>getdefaultblob.app</i> will cause the drawing of default image as a material icon if <i>e.blob.icon </i>property is specified. The optional color can be specified in<i> e.blob.color</i> property. The default image based on the icon is drawn only if the blob field is tagged as <i>image-size-WxH </i>where W and H are the width and the height of the default image.</li><li>(Framework) New method $app.intersect returns true if the two objects specified in the augments are intersecting. Objects may represent the ( x,y) point, the rectangle, or the DOM element.</li><li>(Universal Input) New "slider" input is now a part of the framework.</li><li>(Touch UI) The alert popup displays the message as a note to ensure that the entire text is visible.</li><li>(Framework) Html detection also includes the search for encoded characters and symbols.</li><li>(Survey) Enhanced error reporting when loading survey definition from the server.</li><li>(Kiosk UI) Modal background and glass pane are invisible if the Kiosk UI is displayed above the app.</li><li>(Touch UI) Fullscreen pages without gap with the buttons will take into account the safe area at the bottom on iOS devices.</li><li>(Barcodes) Significantly improved performance of the barcode processing during UI Automation. Automation processor uses a fast check for the first <i>IfThisThenThat </i>condition to trigger in response to the barcodes triggered. App pages of the app are ansible while the Kiosk UI is active.</li><li>(Touch UI) Eliminated the double divider at the bottom of the list of items in the sidebar.</li><li>(Touch UI) Tooltips of the buttons in the fullscreen form without gaps are displayed above the parent toolbar.</li><li>(Blob) Image preview is not draggable in the desktop browsers.</li><li>(Touch UI) Image loading observer will keep track of resolved/observed URLs for enhanced performance.</li><li>(Touch UI) Method $app.touch.observe(url) will return the observed URL if the URL has been observed already on the page.</li><li>(Touch UI) Method $app.touch.observe(enable, container) will start observing the element visibility.</li><li>(Upload) Dropping the non-file content on the drop target will not cause the field to clear.</li><li>(Touch UI) Field footer text of empty values is NOT displayed in "lower-case". </li><li>(Touch UI) Method <i>$app.touch.show({headerText: 'Text 1', controller: 'c1', startCommand: 'New', startArgument:'createForm1'})</i> will correctly assign the value of the <i>headerText</i> option to the page header of the form when the command option is set to <i>New</i>.</li><li>(Touch UI) Method $app.touch.pointrer('pen') returns true if the last touch was with the "pen" pointer.</li><li>(Virtual Keyboard) Virtual keyboard is not activated if the input is touched with the "pen" pointer. It allows the user to write on top of the input without interruption.</li><li>(Universal Input) The numeric input type is not set to "number" on mobile devices if the input was touched with the "pen" pointer.</li><li>(Touch UI) Click the blob drop area will cause the BLOB field to become focused.</li><li>(Blob) Drawing survey is displayed when "draw" icon is tapped.</li><li>(Touch U) If the "fullscreen" button is hidden with the <i>modal-buttons-fullscreen-none</i> then the button on the left side of it is shifted to the right to fill the gap.</li><li>(Display Flow Designer) Arrow keys Up/Left/Down/Right with Shift and Control modifiers will select / deselect display objects in the flow if the there is no active text input.</li><li>(Data Aquarium) Command <i>Search </i>will activate the confirmation controller specified as <i>_controller=Name</i> variable in the Confirmation property of the action. It will restore the previous search values. The search is cleared when the filter is canceled by the user.</li><li>(Touch UI) Custom search is activated when the controller with <i>Search</i> action in <i>Action Bar </i>scope is specified as the lookup of another controller.</li><li>(Data Aquarium) Action with command name Search will not cause the <i>SyncKey </i>data conversion error on the server.</li><li>(Display Flow) Ctrl|Shift + Up|Left|Down|Right will make the first/last selected display object visible in the WebView.</li><li>(Touch UI) <a href="https://codeontime.com/blog/2021/06/drawing-pad">Default values for BLOB</a> fields are now supported. The <i>getdefaultblob.app</i> event handler will specify the default blob file for the field. The specified file is automatically downloaded and selected as the blob value.</li><li>(Framework) $app.getScript loads the dynamic dependencies and executes the callback when the resources and their dependencies are available.</li><li>(Display Flow) "Code" blocks render with the Code Mirror in IE11.</li><li>(Display Flow Designer) All resources of Code Mirror are loaded on demand when the "code" display objects are included in the display flow.</li><li>(Display Flow) "Code" display blocks are provided with a caption showing the code type and the optional description.</li><li>(Data Aquarium) Files codemirror.min.js and codemirror.min.css are included in ~/js/lib folder when the app is generated. This library is automatically loaded in Display Flow pages with the code blocks (sample C#, HTML, JavaScript, etc.)</li><li>(Touch UI) Multiple keyboard shortcuts for the same char code are now supported. For example, <i>Ctrl+V</i> and <i>Ctrl+Shift+V</i> will paste the content in Display Flow page before and after the selected block of display objects.</li><li>(Display Flow Designer) Copy and Cut work with the internal buffer to allow easy manipulation of the content.</li><li>(Touch UI) Typography of H1-H6 tags in two different variations and the jumbo version. The second large font size starts on "large" screens (>= 992px)</li><li>(Touch UI) Method <i>$app.elementAt(p) </i>returns the jQuery element at the specified point in the page. If there is no argument, then the element at the last touch/click point is returned.</li><li>(Touch UI) Optimized the code base to use $app.clientRect and $app.elementAt methods.</li><li>(Touch UI) Reduced the right margin of material icons to 1/20 of the element in Bootstrap and Display Flow content pages. </li><li>(Bootstrap) Removed the leading spaces after the material icons in the Bootstrap content templates.</li><li>(Touch UI) Material icons have the fixed width of 1em in the <i>Bootstap </i>and <i>Display Flow </i>pages to avoid the horizontal shifting while the stylesheets are loading.</li><li>(Data Aquarium) Method $app.getScript(url, callback) will load the script from the app and invoke the callback. It enables dynamic loading of client library files with support for debugging in Visual Studio.</li><li>(Touch UI) New dynamic BLOB image loading will delay the loading of image thumbnails until the image is in the view of the end user.</li><li>(Framework) Meta tag <i><meta http-equiv="X-UA-COMPATIBLE" content="IE=Edge" /> </i>is added to the page on the server if IE 11 client is detected.</li><li>(Framework) Content Type header of combined CSS and JavaScript is provided with the <i>chartset=utf-8 </i>instruction.</li><li>(Framework) Meta definition of the character set is the first element of the page head element.</li><li>(Framework) Meta tags of the page are not closed.</li></ul>Customer Servicehttp://www.blogger.com/profile/04471166550881539854noreply@blogger.com0tag:blogger.com,1999:blog-2297698770491701674.post-85723570219299524842021-06-24T13:04:00.106-07:002021-06-25T13:23:08.781-07:00Responsive Width of Grid Columns<p>The new exciting feature of Touch UI is the ability to express the width of the responsive grid columns in pixels. The new tag <i>column-width-(tn|xxs|xs|sm|md\lg\xl|xxl)_NNN</i> makes it possible to provide the multiple values for the grid column width that will be applied conditionally in the visual containers of the specific size. We have developed this new mechanism for grid column sizing while working on the Live Designer for applications built with Code On Time. </p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizVE9IWaY57yI1AFornoJkfYLel2O1yUVn5rkZ2jf1yXkPcr82e3h38skw66oAlHlSSGTOTktvANxNWTz9nOxV_8sSoP0vPSBptskuo-loGqVB7gTfqEvwRXK70jzRj-9yAhoL2rf6hDUF/s1151/00-grid-column-width-in-pixels.png"><img border="0" data-original-height="944" data-original-width="1151" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizVE9IWaY57yI1AFornoJkfYLel2O1yUVn5rkZ2jf1yXkPcr82e3h38skw66oAlHlSSGTOTktvANxNWTz9nOxV_8sSoP0vPSBptskuo-loGqVB7gTfqEvwRXK70jzRj-9yAhoL2rf6hDUF/s16000/00-grid-column-width-in-pixels.png" /></a></div><p><br /></p><h2>The Sizing Problem</h2><p>HTML tables are commonly used to present data in the grid format. The browsers will automatically evaluate the text in the table cells and set the width of each table column for the best fit. This works great for the standalone tables with the known number of rows. </p><p>If your grids are designed for infinite scrolling or consistent paging of a large number of rows, then a different mechanism must be put in place. Only the small subset of rows is rendered initially and therefore it is not possible to figure the best column width based on the text in the cells of the leading rows. Touch UI framework takes advantage of the Columns property of the data fields in the Grid views. Column values of the fields in the data controller views are derived from the size of the database table columns. The framework figures the total width of the columns by iterating through the visible data fields in the view. This allows us to determine the relative width of each individual column in the grid. Next the framework calculates the width of the grid column in pixels by multiplying the physical width of the visual container by the relative width of the column. The framework also applies constraints to ensure that the columns are never too narrow and remain usable.</p><p>The screenshot demonstrates the grid of orders and the selected order in the reading pane wizard form. The latter shows the grid of the order details.</p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK0dw6ZvJHExaTPainxTjYfepLGA7KqzQsfwGM9Qamf6TgfW0ZyYKfoZBvz-qihskjQy7US-gVCxUBzjr44-nG9bOsc7yQrz154QMHqfdSu8hKB-6cMWJf1qXitqihdHy6HVkcSDWIIwju/s1460/01-grid-column-auto-sizing.png"><img border="0" data-original-height="1223" data-original-width="1460" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK0dw6ZvJHExaTPainxTjYfepLGA7KqzQsfwGM9Qamf6TgfW0ZyYKfoZBvz-qihskjQy7US-gVCxUBzjr44-nG9bOsc7yQrz154QMHqfdSu8hKB-6cMWJf1qXitqihdHy6HVkcSDWIIwju/s16000/01-grid-column-auto-sizing.png" /></a></div><br /><p>The framework has calculated the width of individual columns to provide the best fit for the data. Scrolling, filtering, and sorting will not change the column width in both grids to ensure a consistent presentation. </p><p>Developers can increase the value of the Columns property of individual data fields to provide them with the larger possible real estate. Unfortunately it makes it difficult to achieve the desired width without much trial and error.</p><h2>The Sizing Solution</h2><p>The app in the screenshot above is running in the live preview mode and matches the size of the iPad Pro. The framework has assigned the logical width md (medium) to the master list and xs (extra small) to the reading pane.</p><p>The individual logical width abbreviations supported in Touch UI are matched with the physical width of the visual containers as follows:</p>
<table><tbody>
<tr><td>tn</td><td>0 - 319</td></tr>
<tr><td>xxs</td><td>320 - 479</td></tr>
<tr><td>xs</td><td>480 - 575</td></tr>
<tr><td>sm</td><td>576 - 767</td></tr>
<tr><td>md</td><td>768 - 991</td></tr>
<tr><td>lg</td><td>992-1199</td></tr>
<tr><td>xl</td><td>1200-1365</td></tr>
<tr><td>xxl</td><td>1366 - . . .</td></tr>
</tbody></table>
<p>The second column in the master grid of Orders is <i>Customer Company Name</i>. It represents the alias of the <i>CustomerID</i>. Add explicitly the “alias” data field to grid1 and tag it as </p><p></p><blockquote>column-width-tn-200 column-width-md-400</blockquote><p></p><p>This will instruct the framework to set the column width to be 200 pixels if the visual container of the grid is at least <i>tn </i>(tiny). The “tiny” range starts from 0 and therefore the first tag will set the width of <i>Customer Company Name </i>to be always equal to 200 pixels. The second tag instructs the framework to set the width of the grid column to 400 pixels in the visual containers that are at least 768 pixels wide.</p><p>This is the effect of the tags on the presentation. The customer name is now 400 pixels wide since the visual container size is <i>md</i>.</p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiJd7coBXkQEy4WAN6j6j_AqmteQs6QhORJHSFYSbo-lpWlED8zsBWbt8819okOTKVVcMazteo7CDEcIb0oZPcS2SjTtgLefl6uLzO9qIVVaapRxqRYXIkOefjQzttzBgj4KmIXoA1p58r/s1366/02-grid-column-width-400.png"><img border="0" data-original-height="1026" data-original-width="1366" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiJd7coBXkQEy4WAN6j6j_AqmteQs6QhORJHSFYSbo-lpWlED8zsBWbt8819okOTKVVcMazteo7CDEcIb0oZPcS2SjTtgLefl6uLzO9qIVVaapRxqRYXIkOefjQzttzBgj4KmIXoA1p58r/s16000/02-grid-column-width-400.png" /></a></div><p><br /></p><p>Tap the hamburger menu in the top left corner to expand the sidebar. The visual container of the master grid will reduce to <i>sm </i>(small) size. This will also reduce the width of the Customer Company Name to 200 pixels.</p><div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzPlrHFKUP9hoyzkf5XYZuoyM4bAyZ3d02CG2iI706_kxnGRZxoSJyIK31pUBzyknINEZek7I-3cr9oG8OePxSIVmnBo2GzzhzHTUrcnz0q1IJnDHH-oiHGMgHImvqjGRzSvVbIu4xBYk4/s1369/03-grid-column-width-200.png"><img border="0" data-original-height="1027" data-original-width="1369" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzPlrHFKUP9hoyzkf5XYZuoyM4bAyZ3d02CG2iI706_kxnGRZxoSJyIK31pUBzyknINEZek7I-3cr9oG8OePxSIVmnBo2GzzhzHTUrcnz0q1IJnDHH-oiHGMgHImvqjGRzSvVbIu4xBYk4/s16000/03-grid-column-width-200.png" /></a></div><br /></div><div><div>Apply the tag <i>column-width-tn-NNN</i> to each data field in the grid to set the pixel-perfect presentation whatever the size of the visual container. </div><div><br /></div><div>You can selectively apply the tag to the specific columns to ensure the predictability and responsiveness of the presentation. The “fit to width'' mechanism of Touch UI will take care of the remaining columns in the grid. Alternatively apply the <i>column-width- </i>tag to every data field in the <i>grid1 </i>view of the data controller to override the grid column width decisions made by the framework.</div></div><div><h2>Visual Designer and Grids</h2><div>End users can resize the grid columns by dragging the divider in the grid header. The new width is memorized in the user storage of the browser</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhv9w3Rr8h1k_eQDDgIqEhuxfD0xrE_nZP-fFKfg4K7ox8KxU2T06Yz1W4tNpdOgImwh_L1tkIjjnY7_2cDo5Ij33xCGSIOL5oV4_uh2xTyvE3H4lDYQhI4BqDeZOgrBnc2RY0dXZZiq6fj/s994/05-column-resizing.png"><img border="0" data-original-height="627" data-original-width="994" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhv9w3Rr8h1k_eQDDgIqEhuxfD0xrE_nZP-fFKfg4K7ox8KxU2T06Yz1W4tNpdOgImwh_L1tkIjjnY7_2cDo5Ij33xCGSIOL5oV4_uh2xTyvE3H4lDYQhI4BqDeZOgrBnc2RY0dXZZiq6fj/s16000/05-column-resizing.png" /></a></div><br /><div>Dragging of the grid columns in the “preview” mode by the developer will cause the data fields to be automatically tagged accordingly with the <i>column-width-tn-</i> tags and will make it simple the task of grid configuration. The designer will automatically add the “aliased” fields of the lookup data fields to the grid views when the “alias” column is resized. </div><div><br /></div>Customer Servicehttp://www.blogger.com/profile/04471166550881539854noreply@blogger.com0tag:blogger.com,1999:blog-2297698770491701674.post-14841136400284356922021-06-20T02:24:00.003-07:002021-06-20T02:25:42.146-07:00Drawing Pad<p>Taking photos in business apps often requires the visual annotation of the image. Another common scenario is sketching on the pre-defined template. Touch UI provides a built-in drawing pad that works seamlessly with the BLOB fields of your app. The feature is enabled by default and can be activated with a tap on the “Draw” button.</p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZY8juaJadOz8fAhEqb8HhGzHT6n5y7XV2efjJnqZlndd8iH6MzenqkRk9d53zrBTbCWOLdHX3eFcvKyNlztkVV1qqDjVLjAQWj6mgs8sBD5aQi3BvHQ7S0GrwSf3ha0pw7k4s-caF-dqK/s854/01-drawing-pad.png"><img border="0" data-original-height="845" data-original-width="854" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZY8juaJadOz8fAhEqb8HhGzHT6n5y7XV2efjJnqZlndd8iH6MzenqkRk9d53zrBTbCWOLdHX3eFcvKyNlztkVV1qqDjVLjAQWj6mgs8sBD5aQi3BvHQ7S0GrwSf3ha0pw7k4s-caF-dqK/s16000/01-drawing-pad.png" /></a></div><br /><p>The drawing pad will be immediately displayed in fullscreen mode in response to the tap. It offers several tools: pen, highlighter, blur, and eraser with multiple levels of undo and redo. You can draw with a finger or a stylus compatible with the touch-screen device. Mouse pointers will also work. </p><p>The “pen” and “highlighter” will impact the image as one would expect. The “blur” tool will blur the image contents. The “eraser” will remove the effect of the other tools.</p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTQK2yWWKgExigjf5vFPzc55BoXlKY7sS0sB7_B_l5hqIpEcuRLJXkueEXgnoyKrMYeWq1qWVuJcVgkzLeCgoDeyAnjjbEMZF0Dijpn-HZGb9mIcurnpjFbOJw1Qjp_HB8uGW0Oc_FwMxi/s854/02-drawing-on-image.png"><img border="0" data-original-height="845" data-original-width="854" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTQK2yWWKgExigjf5vFPzc55BoXlKY7sS0sB7_B_l5hqIpEcuRLJXkueEXgnoyKrMYeWq1qWVuJcVgkzLeCgoDeyAnjjbEMZF0Dijpn-HZGb9mIcurnpjFbOJw1Qjp_HB8uGW0Oc_FwMxi/s16000/02-drawing-on-image.png" /></a></div><br /><div><div>Developers can handle the<i> blobdrawtoolbox.app</i> event triggered on the document and override the available tools and their properties such as the width of the stroke and the color choices. The toolbox property of the event provides access to the default tool configuration.</div><div><br /></div><div>The drawing is composed of multiple layers. Saving of the drawing will compose the final image that will be submitted to the server when the data record is saved. The end user can perform multiple sessions of drawing prior to the submission since the layers remain preserved until the record has been saved.</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDNnjQHMnPusNeGl4xx0LXkgnGATFIgAmOkPBESdKsxAAg_pPPpW6JjDRtsfzGxuZKX9mWuW9wNHbz-EyBKQJZ7_hQjrBtNEGCN9Hdvui38OoEHKOZxlPsvroEJJoLqMVhfOEvseYu-sQD/s854/03-drawing-saved.png"><img border="0" data-original-height="845" data-original-width="854" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDNnjQHMnPusNeGl4xx0LXkgnGATFIgAmOkPBESdKsxAAg_pPPpW6JjDRtsfzGxuZKX9mWuW9wNHbz-EyBKQJZ7_hQjrBtNEGCN9Hdvui38OoEHKOZxlPsvroEJJoLqMVhfOEvseYu-sQD/s16000/03-drawing-saved.png" /></a></div><br /><div><div>Sketching on the template will require a default image to be provided. Create a custom script to handle the <i>getdefaultblob.app</i> event. The field property will indicate the name of the blob field that does not have a value. If <i>e.blob.url</i> or <i>e.blob.icon </i>properties are assigned in the event handler, then the corresponding image will be downloaded or a material icon will be drawn.</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjAZ2xA-xoCGKlyn5Gs6ZnNMrLAg-Ed8zwqTR2Po27wzaVSVBBXIuAAVHMjciQb-TscSS55ThenbUATgI8ez-Se7uPSnLPMlfF4a1kzlkAnD5AZcapcUcU7ud7hRLHzLn_IxwJHEhqDN9O/s664/04-default-blob-image.png"><img border="0" data-original-height="350" data-original-width="664" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjAZ2xA-xoCGKlyn5Gs6ZnNMrLAg-Ed8zwqTR2Po27wzaVSVBBXIuAAVHMjciQb-TscSS55ThenbUATgI8ez-Se7uPSnLPMlfF4a1kzlkAnD5AZcapcUcU7ud7hRLHzLn_IxwJHEhqDN9O/s16000/04-default-blob-image.png" /></a></div><br /><div>For example, the following handler will cause the framework to create a blue material icon for the category picture in the application.</div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVx8uVqtOtXhEQVTllmhfE9Iuhcy1lq9vgiAc-_-tQsQ3vcWgtEJrP_JsHB_ZGReuZFJnJ12Sm9vURtygDX4iPaIjfORP1_W0o41YVKEmsXemXg8uWDk9D8CJ3sdDYF2JpDM_3kPOayFnc/s454/04-default-blob-script.png"><img border="0" data-original-height="131" data-original-width="454" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVx8uVqtOtXhEQVTllmhfE9Iuhcy1lq9vgiAc-_-tQsQ3vcWgtEJrP_JsHB_ZGReuZFJnJ12Sm9vURtygDX4iPaIjfORP1_W0o41YVKEmsXemXg8uWDk9D8CJ3sdDYF2JpDM_3kPOayFnc/s16000/04-default-blob-script.png" /></a></div><br /><div>The default image based on an icon may serve as a blob stub whenever the optional image is required. The end user may tap on the image and have it replaced with their by either taking a photo on the device or choosing a previously created image.</div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhr6szCjXLrINzdkVlcnm8OrAB_UGa4RCd4kNZt140uFAQUTGi-_p3mL0-6TJcD5gAJNnS9EGxxGJirRhhmG__bH7o35IS08FDkV0layMIDU5ZwGQJfYnln9B4-pXoO5UyFhMsQoK0MkP81/s926/04-default-blob-icon.png"><img border="0" data-original-height="926" data-original-width="689" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhr6szCjXLrINzdkVlcnm8OrAB_UGa4RCd4kNZt140uFAQUTGi-_p3mL0-6TJcD5gAJNnS9EGxxGJirRhhmG__bH7o35IS08FDkV0layMIDU5ZwGQJfYnln9B4-pXoO5UyFhMsQoK0MkP81/s16000/04-default-blob-icon.png" /></a></div><br /><div><br /></div><div><div>Tapping on the default blob image will always activate the drawing pad if the BLOB data field is tagged as <i>image-user-defined-none</i>. The end user will not be able to replace the template image.</div><div><br /></div><div>The end users may take real-world photos and provide the visual comments with the drawing pad tools. Keep in mind that the huge photographs taken by modern day cameras will likely be redundant for business purposes. Make sure to specify the<i> image-size-WxH</i> tag to engage the <a href="https://codeontime.com/blog/2021/04/image-preprocessing">image preprocessor</a> to enforce the pre-defined image photo size and graphical annotations. </div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJcmOBh67lGB7jNwfDWA1KYxmpE_UbjHXXEd7OL2GUqZSa7n5gHWwOW7gYro4JnhsgAfLeKc5xxoe2mWFuKVQqqwCF-R4fmfpjR6y6zRQVWGD_JFf0aOpZijlYl4jhdARLnQxFvQdp24dh/s926/05-draw-on-photo.png"><img border="0" data-original-height="926" data-original-width="689" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJcmOBh67lGB7jNwfDWA1KYxmpE_UbjHXXEd7OL2GUqZSa7n5gHWwOW7gYro4JnhsgAfLeKc5xxoe2mWFuKVQqqwCF-R4fmfpjR6y6zRQVWGD_JFf0aOpZijlYl4jhdARLnQxFvQdp24dh/s16000/05-draw-on-photo.png" /></a></div><div><br /></div><div><div>Drawing pad provides a powerful tool for the line-of-business apps. Naturally it may not always be desirable to allow image alteration. Tag the blob data field as <i>image-editor-none</i> to disable the drawing pad.</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiAQN7yH9mtyqyEiGsXw9DvEoVOD-ZxNkhxWtKZM77EuntqXhWCwOgzOeX0ls_WQEuQPPpX5Wn1oPWS9H8aKcM4cTmollJZjzrPfIbuPcqcVjhRQ0c4zBzrQ2hnMLH3ABM-9jR3G9G8S6H/s726/06-drawing-pad-tools.png"><img border="0" data-original-height="726" data-original-width="669" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiAQN7yH9mtyqyEiGsXw9DvEoVOD-ZxNkhxWtKZM77EuntqXhWCwOgzOeX0ls_WQEuQPPpX5Wn1oPWS9H8aKcM4cTmollJZjzrPfIbuPcqcVjhRQ0c4zBzrQ2hnMLH3ABM-9jR3G9G8S6H/s16000/06-drawing-pad-tools.png" /></a></div><br /><div>By default the blob images are rendered as thumbnails. Tag the data fields as <i>image-original-always </i>if the original image must be displayed both when the users are viewing and editing the data. The field with the tag <i>image-original-editing </i>will show the original image if the blob is presented in the “edit” mode. End users may still download the original image when viewing the record.</div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXDrFj1DR3V2KMqHnLL2WWUir-3PNXcrFN1Y8pVdNi2jVb8N6vuIhhor9drrJOsRSYAVASIHqxC1kbgiIxYlluEqjFkRjpVV_z6Kktkvs-DfDswtGGxVNCM8dR-iTLKsrBHOmbGbHojPrF/s1055/07-image-original.png"><img border="0" data-original-height="913" data-original-width="1055" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXDrFj1DR3V2KMqHnLL2WWUir-3PNXcrFN1Y8pVdNi2jVb8N6vuIhhor9drrJOsRSYAVASIHqxC1kbgiIxYlluEqjFkRjpVV_z6Kktkvs-DfDswtGGxVNCM8dR-iTLKsrBHOmbGbHojPrF/s16000/07-image-original.png" /></a></div><div><br /></div><div>The drawing pad will work on the small devices, tablets, and huge desktop monitors.</div>Customer Servicehttp://www.blogger.com/profile/04471166550881539854noreply@blogger.com0tag:blogger.com,1999:blog-2297698770491701674.post-73883075144133754872021-04-19T10:28:00.096-07:002021-04-20T03:19:44.196-07:00BLOB Image Preprocessing and Glyphicons<p>Release 8.9.18.0 brings about the client-side <a href="https://codeontime.com/blog/2021/04/image-preprocessing">Image Preprocessing</a> and gets rid of the glyphicons. Your apps will work faster than ever.</p><p></p><blockquote>The new framework may require a few minor changes to your app if you do have the bootstrap-based content pages. <a href="https://codeontime.com/blog/2021/04/say-goodbye-to-glyphicons">Switch to the Material Icons or keep the Glyphicons </a>when you rebuild your app with the new release.</blockquote><p></p><p>The new major features makes possible the <a href="https://codeontime.com/blog/2021/04/image-preprocessing">preprocessing of submitted images</a> directly on the client device. Developer can now force a particular size for the BLOB, the file format, and the image scaling method without writing a single line of code.</p><div><a href="https://codeontime.com/blog/2021/04/image-preprocessing"><img border="0" data-original-height="733" data-original-width="502" src="https://codeontime.com/blog/2021/04/image-preprocessing/image03.png" /></a></div><p> <br />This release introduces the following features and bug fixes:</p><p></p><ul><li>(Universal Input) Keyboard navigation between the fields presented in multiple columns of the <a href="https://www.youtube.com/watch?v=AUFT6fZaeoo&list=PLy2g3SjvDe2bSRoxLwYgxLMTARNXmPpm3&index=1" target="_blank">category with the floating</a> has been greatly improved to take into account uneven field distribution, visibility, and read-only state of inputs.</li><li>(Touch UI) Rapid clicking on the drop down icon of lookups will not cause the content selection</li><li>(Touch UI) Dragging the file into the Blob upload area will set the focus on the blob field.</li><li>(Blob) <a href="https://codeontime.com/blog/2021/04/image-preprocessing">Image Preprocessing</a> is now supported on the BLOB data fields.</li><li>(Touch UI) Zoom animation of forms is not relying on the <i>transitionend </i>event for processing, since this event may not fire at all times. The framework is using the timer instead to reset the "ready" state of the app.</li><li>(Touch UI) The most up-to-date backup <i>True Type </i>font for <a href="https://fonts.google.com/icons?selected=Material+Icons" target="_blank">Material Icons</a> is included. The release date is August 31, 2020. Modern browsers use the "woff2" fonts presented in regular, outlined, rounded, and sharp styles when specified in <i>ui.theme.icons</i> option in <i>~/touch-settings.json</i>. The default icon style is "regular" (filled).</li><li>(Touch UI) The latest release of the Material Icons is included.</li><li>(Display Flow) Simplified the styling of icons in the H1-H6 tags.</li><li>(Bootstrap) All page templates available in the app generator are now using <i><i class="material-icon">name</i> </i>icons instead of the legacy glyphicons.</li><li>(Client Library) Removed legacy glyphicons from the framework. If your app uses the bootstrap pages with the glyphicons, then make sure to follow the migration instructions.</li><li>(App Gen) The version of the app generator is written to the <i>DataAqurium.Project.xml </i>file to ensure automatic loading of new scripts when the app is rebuild with the new release of the generator.</li><li>(App Builder) Display flow designer is added to the projects.</li><li>(Framework) Method <i>$app.jsExt()</i> returns the "js" extension with the application version suffix</li><li>(Display Flow) Calling <i>$app.display('designer')</i> will activate the display flow designer in the current page.</li><li>(Display Flow) Method <i>$app.clientRect() </i>will return the bounding client rectangle of a jQuery object or DOM element.</li><li>(Display Flow) If the virtual page is enhanced with the <i>data-content-framework="display-flow" </i>and <i>data-editable="true"</i> attribute, then the <i>Display Flow </i>live designer is loaded. Content Hub uses this technique to load the designer in live pages.</li></ul><p></p>Customer Servicehttp://www.blogger.com/profile/04471166550881539854noreply@blogger.com0tag:blogger.com,1999:blog-2297698770491701674.post-66899310963939399682021-04-17T12:42:00.005-07:002021-06-20T01:21:18.240-07:00Image Preprocessing<p>The primary focus of every mobile device maker is to deliver a camera that beats the competition. Year after year the consumers are getting better photos with an unbelievable level of detail. Large high resolution images have huge implications for the business app developers since the files need to be transmitted, stored, and processed at an increasing cost and often without a significant benefit. </p><p>Touch UI introduces a simple and powerful set of image preprocessing capabilities that help enforce the image size, format, and compression quality for any BLOB field. The processing is performed entirely on the client and works both in online and offline modes.</p><h2>Image Size</h2><p>Apply the tag <i>image-size-WxH</i> to a blob field in a view to ensure that the submitted images will have a fixed size. For example, entering <i>image-size-640x480 </i>in the tag property of a BLOB field in the data controller views <i>createForm1 </i>and <i>editForm1 </i>will ensure 640x480 images. Also only the image files will be accepted and any other types of files will be rejected. </p><p>Mobile browsers and web views provide an option to take a photo with the camera. Photos taken with the device camera will also undergo the pre-processing if the <i>image-size-WxH </i>tag is specified.</p><p>The original 4032 x 3024 image in the screenshot below was taken with the Pixel 4XL and occupies 3.43MB of storage. The preprocessing has reduced the image to 640 x 480 pixels and will require 768 KB on the hard drive.</p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBTBz_dV7p1A3-6fQ2V0Kk3S8SB1msU-lJZEHoa13h9KST9H6wChViiZjqmjFcyUc0gdiNhyUaubWtxLWRtM3AZBuuawVxbEoJelGv7lptJDXnJ61kxCZdsuwjlScGc6fFODgabb3N0mG-/s768/01-image-processing.png"><img border="0" data-original-height="768" data-original-width="562" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBTBz_dV7p1A3-6fQ2V0Kk3S8SB1msU-lJZEHoa13h9KST9H6wChViiZjqmjFcyUc0gdiNhyUaubWtxLWRtM3AZBuuawVxbEoJelGv7lptJDXnJ61kxCZdsuwjlScGc6fFODgabb3N0mG-/s16000/01-image-processing.png" /></a></div><h2>Fit vs Cover</h2><p>If the large image does not perfectly scale down to the specified size, then the image will be reduced to fit in the specified boundaries with the horizontal or vertical bars (gaps) around it. Developers can change the default image background color from white to yellow by tagging the blob field as <i>image-background-yellow</i>.</p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjn52mNug-eKhc__W-YTQaYxeGrHALCk8SvvlMCpg9xXTiGOBlwhkiLc7yrw-yqtmHTf02OmPzHlyR7pUpGawo2PakzKrjOiDtDtbqIVtUs7NdgP4ludYUDWHACV3njBmpHuxmZWaSRdce/s733/02-image-fitted.png"><img border="0" data-original-height="733" data-original-width="502" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjn52mNug-eKhc__W-YTQaYxeGrHALCk8SvvlMCpg9xXTiGOBlwhkiLc7yrw-yqtmHTf02OmPzHlyR7pUpGawo2PakzKrjOiDtDtbqIVtUs7NdgP4ludYUDWHACV3njBmpHuxmZWaSRdce/s16000/02-image-fitted.png" /></a></div><div><div><br /></div><div>Use <i>image-background-transparent</i> tag to have the transparent bars instead. The standard color names </div><div>and the hexadecimal values are allowed when specifying the background.</div><div><br /></div><div>Tag <i>image-large-cover </i>will prompt the framework to scale the large image down to cover the entire area without gaps.</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAfzar_piUWweW1PxcjiSo8G3b-O4BVpi-ttCV5WSrYNqV3oIKCsvkDubQD4SVk7_ZLiCQntnJRdsxnTg5Yte4Swiqs48Imwx54xvjlD0zifc1mG-GhJm9Ek512nNsBsQp_n7OodGeXCf8/s730/03-image-cover.png"><img border="0" data-original-height="730" data-original-width="502" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAfzar_piUWweW1PxcjiSo8G3b-O4BVpi-ttCV5WSrYNqV3oIKCsvkDubQD4SVk7_ZLiCQntnJRdsxnTg5Yte4Swiqs48Imwx54xvjlD0zifc1mG-GhJm9Ek512nNsBsQp_n7OodGeXCf8/s16000/03-image-cover.png" /></a></div><div><br /></div><div>If the smaller image is provided, then it will be centered on a solid background.</div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcuAWG2EqrL1_VV79gUQpgvtlhNi931QCQA8qz1ksQXRgAoKZXotS-9l9VA8d3zZJkKT4BaFEZ44nDkWNTLR58WFDjVwVRAk-gf-E7RSBpUEd0Zo7wIQAOpTI3GQ6K21ItincJ828raifu/s730/04-image-small-center.png"><img border="0" data-original-height="730" data-original-width="502" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcuAWG2EqrL1_VV79gUQpgvtlhNi931QCQA8qz1ksQXRgAoKZXotS-9l9VA8d3zZJkKT4BaFEZ44nDkWNTLR58WFDjVwVRAk-gf-E7RSBpUEd0Zo7wIQAOpTI3GQ6K21ItincJ828raifu/s16000/04-image-small-center.png" /></a></div><div><br /></div><div><h2>Clipping Large Images</h2><div>A large image can be reduced to the requested size without the “filler” bars. Tag the blob field as <i>image-large-clip </i>to ensure that no file is larger than the specification. Large images will be reduced and clipped. The smaller images are accepted as-is by default. </div><h2>Image Quality and Format</h2><div>Preprocessing will draw the original image on the DOM canvas. The default binary serialization format of the canvas is PNG with the 92% compression. The latter cannot be changed. Apply the tags <i>image-format-jpeg</i> and <i>image-quality-50 </i>to the BLOB data field and ensure the standard JPEG image format with the 50% compression. </div><h2>Rejecting Image Upload</h2><div>Image size specification can also serve as a client-side image filter. Tag <i>image-small-reject </i>will reject any image that is smaller than the specified size. Tag <i>image-large-reject </i>will reject the larger images instead.</div><div><br /></div><div>If you want to enforce a specific image size 320 x 320, then apply these tags to the BLOB field in the data controller views:</div><div><br /></div><div></div><blockquote><div>image-size-320x320 image-small-reject image-large-reject.</div><div></div></blockquote><div><br /></div><div>The following combination of tags will ensure that all images are uniformly confirming to a particular size requirement and do not have the gaps:</div><div><br /></div><div><blockquote>image-size-640x480 image-large-cover image-small-reject</blockquote></div></div>Customer Servicehttp://www.blogger.com/profile/04471166550881539854noreply@blogger.com0tag:blogger.com,1999:blog-2297698770491701674.post-23091195085388814852021-04-16T14:48:00.094-07:002021-04-19T03:07:02.664-07:00Say Goodbye to Glyphicons<p> Touch UI has a long history. The framework was introduced in <a href="https://codeontime.com/blog/2013/12/mobile-database-apps-for">December of 2013</a>. It was built on top of <a href="https://jquerymobile.com/" target="_blank">jQuery Mobile</a> and represented our attempt to provide a “mobile” presentation style for apps created with Code On Time.</p><p>Here is the sample screenshot from that time:</p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRKMF2GYXmJWdCa6d-ArDWCcjB5zTQmK_s4ZwmXLMoR083iDsNMnPHKZJJkJxp7f3_DwRqyET5DGwRku8naDND5SAzehTwP2fxPu3NAeSgOmE1R7KHYmq4CwXDTzZKcnIdYuFtdI-apcoQ/s768/02-Touch-ui-10.png"><img border="0" data-original-height="768" data-original-width="576" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRKMF2GYXmJWdCa6d-ArDWCcjB5zTQmK_s4ZwmXLMoR083iDsNMnPHKZJJkJxp7f3_DwRqyET5DGwRku8naDND5SAzehTwP2fxPu3NAeSgOmE1R7KHYmq4CwXDTzZKcnIdYuFtdI-apcoQ/s16000/02-Touch-ui-10.png" /></a></div><p><br />The graphics of<i> jQuery Mobile</i> were based on a small subset of <i>Glyphicons </i>that was contributed by the namesake company in the SVG format. The extended set of 250 icons found their way into Bootstrap 3.0. We have integrated <a href="https://codeontime.com/blog/2014/10/bootstrap-integration-touch-ui-gets">Bootstrap </a>to provide the means of creating the content pages in Touch UI and promptly upgraded the framework to use the corresponding web font.</p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihSm5WG6W8unrlXo_VLnG3G4PuzTCyqtPPr5L_z-BbmVdbMq_2wLMl7vHvRD2b4Cbq4bC0uZwQtLzRj8FU28FM9ROR7eYXmE7H5m9mfZERPOQIJpQ5nxsgcQ7mMFTP61l_Rfevpk5hRJE3/s948/03-bootstrap-and-touchui.png"><img border="0" data-original-height="768" data-original-width="948" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihSm5WG6W8unrlXo_VLnG3G4PuzTCyqtPPr5L_z-BbmVdbMq_2wLMl7vHvRD2b4Cbq4bC0uZwQtLzRj8FU28FM9ROR7eYXmE7H5m9mfZERPOQIJpQ5nxsgcQ7mMFTP61l_Rfevpk5hRJE3/s16000/03-bootstrap-and-touchui.png" /></a></div><div><br /></div><p>Glyphicons continued to be a part of Touch UI framework up until now.</p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4wVpHTn5cPofQ5IwDCJmIOF0V8AqHBaHH48bFu2mjoj-5UGPq3EiyoGo-c7-BBsicEWFEJjmFSP2E288GFGGEVi-Q2vNuZK2Z4TUr19Y-ExkSnzzyyfxOZBaPn9neRAJypw-jcJ7KusBt/s743/01-Glyphicons.png"><img border="0" data-original-height="233" data-original-width="743" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4wVpHTn5cPofQ5IwDCJmIOF0V8AqHBaHH48bFu2mjoj-5UGPq3EiyoGo-c7-BBsicEWFEJjmFSP2E288GFGGEVi-Q2vNuZK2Z4TUr19Y-ExkSnzzyyfxOZBaPn9neRAJypw-jcJ7KusBt/s16000/01-Glyphicons.png" /></a></div><p><br />Touch UI of today gets its looks from the <a href="https://fonts.google.com/icons?selected=Material+Icons" target="_blank">Material Icons</a> library and can be extended with an <a href="https://codeontime.com/blog/2021/03/icons-icons-icons">additional icon set</a> when needed. The new framework works equally well on the devices driven by mouse and touch. It supports modern web browsers on any screen size. It can operate in native mode and as a part of a Progressive Web App.<br /><br /></p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRJp3kWaaU6TmItaaMftg8v8VG4ROvpzwnWM2H2IyS12q19j1bLXOpE9rRbntFH7rdDeEldvrZKMxW10c3A5jaRGMvk5vIksbSPS7XCKcmnlfBjoggJYROs7UxTrmxSY9HhTUTZPvc2ZgR/s1294/04-touch-ui-2021.png"><img border="0" data-original-height="1090" data-original-width="1294" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRJp3kWaaU6TmItaaMftg8v8VG4ROvpzwnWM2H2IyS12q19j1bLXOpE9rRbntFH7rdDeEldvrZKMxW10c3A5jaRGMvk5vIksbSPS7XCKcmnlfBjoggJYROs7UxTrmxSY9HhTUTZPvc2ZgR/s16000/04-touch-ui-2021.png" /></a></div><p><br />Starting with the release 8.9.18.0 the glyphicons are not the standard component of Touch UI. New projects will not have these icons included. The legacy apps will retain the font in the <i>~/app/fonts</i> folder but will require one of the following after being re-generated with the new release:</p><p></p><ul><li>Replacing the references to the glyphicons with their counterparts found in the Material Icons library.</li><li>Copying of the single CSS file from the code generation library into your own project.</li></ul><p></p><p>The replacement of icons is simple. Here is how we did that for a few icons found in the current iteration of <a href="https://my.codeontime.com" target="_blank">https://my.codeontime.com</a>.<br /></p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiAcQvpupesfCLG0V8fFVayqCZR-j-q2dXr6GpT9ckss3xCiUFxpwvPSwWZiEUscotTpiVkWa-q530vv5RZh598NeHloClVTvkSg9GiKLreViWbt8rej8tR16nBav84P59I09G-I8HUKo-/s1143/05-replacing-glyphicons-with-material-icons.png"><img border="0" data-original-height="131" data-original-width="1143" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiAcQvpupesfCLG0V8fFVayqCZR-j-q2dXr6GpT9ckss3xCiUFxpwvPSwWZiEUscotTpiVkWa-q530vv5RZh598NeHloClVTvkSg9GiKLreViWbt8rej8tR16nBav84P59I09G-I8HUKo-/s16000/05-replacing-glyphicons-with-material-icons.png" /></a></div><p><br />Either keep the <i>span </i>element of the icon definition or have it replaced with<i> i</i> tag. Replace the CSS classes in the icon definition with a single class <i>material-icon</i>. Enter the icon name between the opening and closing tag.</p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxI9c_M8bNKbJmnl6hi_l8ZWmdh8OecXl3DJ0PZqfZkGTwOQwvlt779nPNPDu6dmxc95mvbzk1aMjodD3YA8qnXoo-W4b-8oZm3mpmtKA6jsf8lT63uWHW5n9DShlIgpg8tfXkmdXcCgR_/s428/05a+-+material+icons+in+bootstrap+pages..png"><img border="0" data-original-height="91" data-original-width="428" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxI9c_M8bNKbJmnl6hi_l8ZWmdh8OecXl3DJ0PZqfZkGTwOQwvlt779nPNPDu6dmxc95mvbzk1aMjodD3YA8qnXoo-W4b-8oZm3mpmtKA6jsf8lT63uWHW5n9DShlIgpg8tfXkmdXcCgR_/s16000/05a+-+material+icons+in+bootstrap+pages..png" /></a></div><p><br />If you prefer to continue using the glyphicons, then copy and paste the <i>glyphicons.css</i> file from the code generation library in <i>[Code OnTime]/Library/Legacy/glyphicons </i>folder into <i>~/app/css </i>folder of your application. Run the app generator and click the “Locate” link below the list of projects to go straight to the library folder.</p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg54ob5sIYxj2MAjJttHL_ad1NKLylCsicy8q7a5SFxPN0nHDMOlEP-JerAUXSXk-ZUWHyHE_IHnEDjmPkIpFkKmOB7PneCBfLYjlCUHEzGT_rddDTNF09yPMyra9ht-9j_1Mpc5usXsyDC/s682/06-keep-using-glyphicons.png"><img border="0" data-original-height="226" data-original-width="682" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg54ob5sIYxj2MAjJttHL_ad1NKLylCsicy8q7a5SFxPN0nHDMOlEP-JerAUXSXk-ZUWHyHE_IHnEDjmPkIpFkKmOB7PneCBfLYjlCUHEzGT_rddDTNF09yPMyra9ht-9j_1Mpc5usXsyDC/s16000/06-keep-using-glyphicons.png" /></a></div><p>If you want to start using the glyphicons in the new projects then copy the other two files in the same folder and paste into the<i> ~/app/fonts</i> folder of your application.</p><p>Glyphicons are not widely used in the apps created with Code On Time. You may find the references to the icons in the dedicated login page of the app or in the content pages based on the bootstrap. The new code generation library is now referencing the material icons instead. This reduces significantly the size of the framework CSS files and provides a faster first paint in the browsers and web views.</p><p>The content pages of the near future will be based on <i>Display Flow </i>technology. The new presentation technology is shared with the <a href="https://codeontime.com/blog/2020/05/tutorial-barcodes-qr-codes-and-rfid-tags">Kiosk UI </a>and will have its own Live Visual Designer. You will see it in action in the new community forum and in the support help desk. Materials Icons are integrated in the <i>Display Flow </i>and provide an excellent replacement for the Glyphicons.</p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiR7toNNi4yEyhADLvsGGnZDXkKLAnB53o99VZWs-EQcjZc008kQuB91_aQ-GMvv-rdBPoIcbn7ZQuijCNheHobxSQrO4eqhBHmdRVt6p98DOViql-4ec8JBZghzzmM8I5qofTIk_CKCCEy/s653/07-material-icons.png"><img border="0" data-original-height="429" data-original-width="653" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiR7toNNi4yEyhADLvsGGnZDXkKLAnB53o99VZWs-EQcjZc008kQuB91_aQ-GMvv-rdBPoIcbn7ZQuijCNheHobxSQrO4eqhBHmdRVt6p98DOViql-4ec8JBZghzzmM8I5qofTIk_CKCCEy/s16000/07-material-icons.png" /></a></div>Customer Servicehttp://www.blogger.com/profile/04471166550881539854noreply@blogger.com0tag:blogger.com,1999:blog-2297698770491701674.post-80629540921956273212021-04-08T12:53:00.344-07:002021-04-09T02:14:58.070-07:00UI State and Logout URL<p>Code On Time release 8.9.17.0 introduces new controls over the user interface state and make a slight but significant change to the logout process. There are various performance improvements and changes to the <i>Display Flow</i> of the upcoming <i>Content Hub Add-on, </i>that serves as the foundation of the new <i>Community Forum</i>. Continue reading to learn more.</p><h2>UI State Storage</h2><p>Touch UI application in the screenshot is running as the <i>Progressive Web App </i>(coming soon) and behaves just like the app in the web browser. It retains the minimized sidebar, the data filter, and the reading pane mode when restarted by the end user. The new <a href="https://codeontime.com/blog/2021/04/ui-state-storage-cleanup" target="_blank">UI State Storage and Cleanup</a> options <i>ui.state.storage </i>and <i>ui.state.clear </i>can be specified in the application configuration file <i>~/touch-settings.json</i> to control where exactly the user interface state is being preserved and when it is cleared.</p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjleoZh329jZ6hbcAUW0c6KXMc7pmPrCRdeaXTM5ViiQeDoiEZGP0gBnE76xGB-jGet3vAzKW7Fq5SZpwAJANcJIYamfsOGrfoZgiKFg_BxB8Mkq2w9D4gzpF9RzBZ2ouDZz1ZoZdaF4pKv/s1099/2021-04-09+%25281%2529.png"><img border="0" data-original-height="651" data-original-width="1099" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjleoZh329jZ6hbcAUW0c6KXMc7pmPrCRdeaXTM5ViiQeDoiEZGP0gBnE76xGB-jGet3vAzKW7Fq5SZpwAJANcJIYamfsOGrfoZgiKFg_BxB8Mkq2w9D4gzpF9RzBZ2ouDZz1ZoZdaF4pKv/s16000/2021-04-09+%25281%2529.png" /></a></div><h2>Logout URL</h2><p>Starting with this release the default logout behavior of the apps built with Code On Time is changing. Previously the successful logout request to the server was followed by reloading of the current URL visible in the address bar of the browser. The server-side code would redirect the user to the login page and return to the same location if the user has opted to sign in again. </p><p>The new framework will redirect the user to the root of your app instead and this will cause the <i>ApplicationServices.UserHomePage() </i>method to be invoked giving the developer a chance to redirect the anonymous user to the desired start location on the first visit after the logout. The default location is <i>~/pages/home</i>.</p><p>New Configuration option <i>membership.logoutUrl </i>specifies what happens when the user signs out. The default value is <i>root</i>, which will cause the web view to redirect to the root of the app. Value <i>current</i> will reload the current page and force the user to confirm their identity. This is the framework behavior prior to this release. Any other URL will cause the app to redirect upon the successful logout. For example, <i>https://codeontime.com</i> specified in <i>membership.logoutUrl </i>option of <i>~/touch-settings.json </i>app configuration file will navigate to the corresponding web resource. The relative path <i>~/forum/topics </i>will redirect the app to the page <i>/forum/topics</i>.</p><h2>Content Hub, Display Flow, and Community Forum</h2><p>The content presentation framework <i>Display Flow</i> was first introduced as the part of <a href="https://codeontime.com/blog/2020/05/tutorial-barcodes-qr-codes-and-rfid-tags" target="_blank">Kiosk UI</a>. Here at Code On Time we are trying to do a lot with as little effort as possible to keep things efficient and tidy. We are using the <i>Display Flow</i> in the <i>Content Hub Add-on</i> to bring the powerful interactive live content designer and content publishing capabilities in the apps created with Code On Time generator. The new <i>Community Forum </i>is coming to <a href="https://my.codeontime.com" target="_blank">https://my.codeontime.com</a> and will demonstrate this exciting technology. It will power our interactions with the customers and will also be available as an add-on for your apps.</p><p>The live content designer shares the <i>Object Inspector (Properties Window)</i> with v9 to allow the visual configuration of the <i>Display Flow </i>objects. We will bring the v9 design capabilities in your apps as early as next month. The live project designer of v9 will first enable the full visual editing of all available properties of <i>~/touch-settings.json. </i>Finally the guesswork will be over. Gradually we will increase the scope of Project Configuration capabilities with every incremental release of 8.9.x.x app generator. The version number will shift to 9.0.0.0 when the scope of configuration meets the level of current Project Designer implemented with Windows Forms. The migration to v9 will be subtle and pain-free. Eventually you will be building your apps entirely in your favorite web browser (Chrome, Edge, Firefox, Opera) with the app generator running in the icon tray.</p><h2>Release Summary</h2><p>The following new features and fixes are included:</p><p></p><ul><li>(Touch UI) Form buttons will appear centered when the full-screen or non-modal view has the "md" width or larger. Otherwise the buttons are aligned to the right.</li><li>(Installer) MSI file is marked with the correct version number of the app generator release.</li><li>(Touch UI) Configuration option <i>membership.logoutUrl </i>controls what happens when the user signs out. The default option is <i>root</i>, which will cause the app to redirect to the root of the app. Value <i>current</i> will reload the current page and force the user to confirm their identity. Any other URL will cause the app to redirect there upon the successful logout. </li><li>(Touch UI) Option <i>ui.state.clear</i> allow controlling when the user interface state variables are cleared. The default value is 'never'. Option value <i>always</i> will clear the UI state on login and logout. Value <i>logout</i> will clear the UI state on logout only.</li><li>(Display Flow) Flow Designer maintains the scroll position of the top-most visible display object when the page is resized.</li><li>(Display Flow) Properties <i>spacing</i>, <i>align</i>, and <i>color</i> are handled in more configuration variations of display objects.</li><li>(Display Flow) Display flow designer allows <i>Click</i>, <i>Shift+Click</i>, and <i>Ctrl+Click </i>selection of display objects. A count of objects is displayed when the selection is made. Read-only objects are not selectable. This makes possible creating forum posts with the ability to design enabled on the reply or comment only. </li><li>(Touch UI) Content pages will display a 3d shadow on the app toolbar when scrolled down.</li><li>(Display Flow) Content display object supports the "color" attribute to allow an explicit content color definition overriding the color of the theme and accent.</li><li>(Display Flow) Tags <i>h1-h6 </i> appear larger in the "hero" display blocks on <i>lg</i>, <i>xl</i>, and<i> xxl </i>screens</li><li>(Touch UI) Page menu is erased when an article is added to the page.</li><li>(Touch UI) Page header is invisible if the page is using the content framework (Bootstrap or Display Flow).</li><li>(Touch UI) Property <i>$app.agent</i> has <i>ie</i>, <i>iOS</i>, <i>chromeOS</i>, and other properties to provide quick shortcuts identifying the web view agent.</li><li>(Touch UI) Option <i>ui.state.storge</i> with the values <i>local </i>and <i>session</i> will control how the state of the GUI is persisted. The default value is <i>local</i>.</li><li>(Touch UI) Last vertical scroll position of the <i>Bootstrap </i>and <i>Display Flow</i> page is memorized in the session storage.</li><li>(Touch UI) Content pages will memorize the scroll position and have it restored when navigating back or forward to the page.</li><li>(Farmework) Font files are cached up on the client for 1 year .</li><li>(Touch UI) Icon class names are removed from the page body at runtime. Previously this has affected the page layout under certain conditions.</li><li>(Touch UI) Implemented an efficient assignment of display width breakpoints to the page. Classes <i>app-min-xxs </i>through <i>app-min-xxl </i>are assigned and removed only as needed for smooth animations and faster rendering.</li><li>(Display Flow) Increased the font size of "code" blocks to 3/4 or rem.</li><li>(Touch UI) Pages with the explicitly defined <i>data-app-role="page"</i> and <i>data-container-framework="bootstrap|display-flow" </i>attributes will not have a dedicated container page and will have their contents placed into the "Main" page if there are no other "virtual" pages in the markup. This speeds up the first paint in the browsers.</li><li>(Touch UI) Modal page header background color is not affected by the presence of the sidebar.</li><li>(Touch UI) The trailing list divider is not rendered in the mini sidebar.</li><li>(Classic UI) Fixed the exception raised when the New and Duplicate commands are executed.</li></ul><p></p>Customer Servicehttp://www.blogger.com/profile/04471166550881539854noreply@blogger.com0tag:blogger.com,1999:blog-2297698770491701674.post-50152501188121764622021-04-07T12:08:00.035-07:002021-04-09T02:18:55.029-07:00UI State Storage & Cleanup<p>The state of the user interface in the apps built with Touch UI is maintained on the client. Authenticated users find the search criteria, filters, sort expressions, view styles, theme choice, and many other traces of their interactions with the app to be persisted between sessions. This makes it easy to pick up where you left off on the same device even when the browser window is closed and opened again. The app framework uses the local storage of the web view for this purpose. Each identity used to sign into the app will have its own UI state.</p><p>Touch UI can be configured to keep the user interface state in the session storage of the web view instead. The user interface state will persist while the browser window is open. App users start with the clean slate when the session is started in the new window.</p><p>Set the option <i>ui.state.storage</i> to session in <i>~/touch-settings.json </i>configuration file to enable this behavior of the UI.</p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJ_K7b65vSDXLv_UqeEhOCOFZWdJBc9XwI1SbF7p0o_b3AKe-_ONcVdyr1Va7WMAJde6EyV69rr2yKxw0Jz49ufrq5elD87UxPOpzCLTG2TSH4COtDYsqQIIW5GMxgKUOoGSgPOOdezRBH/s403/01-ui-state-storage-and-cleanup.png"><img border="0" data-original-height="239" data-original-width="403" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJ_K7b65vSDXLv_UqeEhOCOFZWdJBc9XwI1SbF7p0o_b3AKe-_ONcVdyr1Va7WMAJde6EyV69rr2yKxw0Jz49ufrq5elD87UxPOpzCLTG2TSH4COtDYsqQIIW5GMxgKUOoGSgPOOdezRBH/s16000/01-ui-state-storage-and-cleanup.png" /></a></div><br /><p>User identities and avatars are still persisted in the local storage to avoid having the user to sign in while moving between the app pages and browsing sessions. So are the global choices such as the theme and the presence of the sidebar.</p><p>Another related option allows controlling whether the user interface state is cleared when the user logs in or logs out. Option <i>ui.state.clear</i> is set to <i>never </i>by default. Developers may choose to clear the user-specific application state on the client upon <i>logout</i>. Value <i>always </i>will force the app to clear the UI state both on login and logout.</p><p>If the app is expected to be used on the shared devices, then setting the UI state storage to session and having it cleared always will eliminate any potential data exposure that can be exploited by the individuals with the physical access to the device. Recommend the end users to sign out and to close the browser or app when not in use.</p><p>Cloud On Time app executes the front end of the applications created with Code On Time from the locally stored HTML pages. Neither <i>localStorage </i>nor the <i>sessionStorage </i>objects are available in the web view. The entire set of local data specific to the user is removed from the device when the user signs out.</p><p>Touch UI application in the screenshot is running as the Progressive Web App and behaves just like the app in the web browser. It will retain the minimized sidebar, the data filter, and the reading pane mode when restarted by the user if the options <i>ui.state.storage </i>and <i>ui.state.clear </i>are not specified in the application configuration.</p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAElxqLfjYdcVmNQV38kFc7pLycTMqYKvZbTa-cBTir4Onao6erqwZK_OqjakRQi7GxVlJezLH0dLQU89G_N5cfHYi9orWRaiUa5JsQRk-7JeFRpLLSfR5KRRAnM4N9QjUFgwjMnBvo3A2/s1099/02-ui-state-in-action.png"><img border="0" data-original-height="658" data-original-width="1099" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAElxqLfjYdcVmNQV38kFc7pLycTMqYKvZbTa-cBTir4Onao6erqwZK_OqjakRQi7GxVlJezLH0dLQU89G_N5cfHYi9orWRaiUa5JsQRk-7JeFRpLLSfR5KRRAnM4N9QjUFgwjMnBvo3A2/s16000/02-ui-state-in-action.png" /></a></div><br /><p><br /></p><div><br /></div>Customer Servicehttp://www.blogger.com/profile/04471166550881539854noreply@blogger.com0tag:blogger.com,1999:blog-2297698770491701674.post-51011919135879996472021-03-30T15:41:00.234-07:002021-03-31T04:45:21.111-07:00Grids, Label Icons, Collapsible Menus<p> Code On Time release 8.9.16.0 introduces the significant enhancements to Touch UI.</p><p><a href="https://codeontime.com/blog/2021/03/lines-lines-lines">Vertical grid lines</a> are now displayed in the grid view style be default. Developers can selectively hide the vertical lines in the grids and the horizontal lines in both forms and grids.<br /><br /></p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjEUuB4-Bm1Uer3bObAsglv_fctGsKBrbSJdlwbThnH3QDPvn5ZnnbioVMLKmxcnkkmlOInmxEfqXiDEgyRga8x3wrV0S0pEWAUfFHcZbbmNDaX6HwhU5zzo9L0rvacp4WLJYXs754nA8A/s1046/2021-03-31+%25283%2529.png"><img border="0" data-original-height="670" data-original-width="1046" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjEUuB4-Bm1Uer3bObAsglv_fctGsKBrbSJdlwbThnH3QDPvn5ZnnbioVMLKmxcnkkmlOInmxEfqXiDEgyRga8x3wrV0S0pEWAUfFHcZbbmNDaX6HwhU5zzo9L0rvacp4WLJYXs754nA8A/s16000/2021-03-31+%25283%2529.png" /></a></div><p><br />Label icons are now supported. Tag the data field with the <i>label-icon-</i> tag and include the icon name in it. The icon will be displayed next to the field value instead of the text label. For example, the tag <i>label-icon-work-outline</i> will assign the material icon <i>work_outline</i> to the <i>Title</i> data field in the screenshot.<br /><br /></p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg27WuIvm4c1pf_cp6AvaffQBYMBY-l9TTGNgVMSX4k-Jz1aPSOUfjtnLvep5QO7Deg_yT-ZpxZ6mHDy2v7cIFXfg12xO8xz2sI601dp4W8zSA9Yv4ZEA50XH_Al8zH_0yGlgQqZLmDQtzB/s1046/2021-03-31+%25285%2529.png"><img border="0" data-original-height="670" data-original-width="1046" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg27WuIvm4c1pf_cp6AvaffQBYMBY-l9TTGNgVMSX4k-Jz1aPSOUfjtnLvep5QO7Deg_yT-ZpxZ6mHDy2v7cIFXfg12xO8xz2sI601dp4W8zSA9Yv4ZEA50XH_Al8zH_0yGlgQqZLmDQtzB/s16000/2021-03-31+%25285%2529.png" /></a></div><p><br />The <a href="https://codeontime.com/blog/2021/03/navigation-menu">vertical navigation menu </a>rendered in the sidebar will display the icons assigned to the page. The vertical rendering of the navigation menu in the sidebar and sliding panels feature the collapse/expand buttons next to the menu items with the children. Only the node of the current page is expanded by default to conserve the vertical space. <br /><br /></p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiylA_ZPpPZTXICZwU1Hx1L6jfOZTztQxknvQMo3e65ewNVRnIs1GNjoRoebyLNWYmQ5FJzIQ1nAB-NQX4ZkEhUpFRaNHY0wIOFqcLV08wEE685EzQwvMzifpnnqf_sa2uzzWquWMxLeF-1/s961/2021-03-31+%25286%2529.png"><img border="0" data-original-height="877" data-original-width="961" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiylA_ZPpPZTXICZwU1Hx1L6jfOZTztQxknvQMo3e65ewNVRnIs1GNjoRoebyLNWYmQ5FJzIQ1nAB-NQX4ZkEhUpFRaNHY0wIOFqcLV08wEE685EzQwvMzifpnnqf_sa2uzzWquWMxLeF-1/s16000/2021-03-31+%25286%2529.png" /></a></div><p><br />The app toolbar displays the text of the left most "icon" button if there is no button bar in the form. This provides a mode of presentation on small form factor found in modern mobile operating systems.<br /><br /></p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidQqqqOLcE7Ksye4WC7C5x772BdArEI21ySJ5W3_IM-1Pdfs8YkvZnYjErVkwzzqTdb9F15eJPizFCP9OLim_hKYBE4fD0-3rgCycP4vflpFYaXu8TJUofvriWPFy8XVYsiqNjHFFoV_0G/s732/2021-03-31+%25287%2529.png"><img border="0" data-original-height="732" data-original-width="458" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidQqqqOLcE7Ksye4WC7C5x772BdArEI21ySJ5W3_IM-1Pdfs8YkvZnYjErVkwzzqTdb9F15eJPizFCP9OLim_hKYBE4fD0-3rgCycP4vflpFYaXu8TJUofvriWPFy8XVYsiqNjHFFoV_0G/s16000/2021-03-31+%25287%2529.png" /></a></div><p><br />Command <i>New Row </i>is now implemented. It will activate the inline editing mode and scroll the view to the very bottom while placing the input focus on the "new row" template marked with the "plus" icon.<br /><br /></p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9yjhtlQuTcC8XpiDVC1IsmiZv3tBNTQ2Ax4Kf3j76niGP_MC1A_TTfEfzxdNfwGqFLLAbcdEeynj2Oo0899hMmfV_Rz83T2flNYVEtMdeoTQD-HblxMiP9XHrOJDsvtzH6Bu37OJx7Vsx/s889/2021-03-31+%25288%2529.png"><img border="0" data-original-height="753" data-original-width="889" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9yjhtlQuTcC8XpiDVC1IsmiZv3tBNTQ2Ax4Kf3j76niGP_MC1A_TTfEfzxdNfwGqFLLAbcdEeynj2Oo0899hMmfV_Rz83T2flNYVEtMdeoTQD-HblxMiP9XHrOJDsvtzH6Bu37OJx7Vsx/s16000/2021-03-31+%25288%2529.png" /></a></div><p><br />The <a href="https://codeontime.com/blog/2021/03/icons-icons-icons">3rd party icon web fonts</a> can be now configured in the app.</p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtuesp-gZ9jCCvY8Easy52ZkW_w1AhjMNWA5zVNpMYUxWKR4Pp3nCknbr_u_42iF6Bvg6qgIGxr9NXR8q8_kJ0N7Lg8V8Wl5vrU5cGJ_-xnMeMWPgblJBAKTgX7S5y9NcyBboi25RD1G0e/s989/00-icons-icons-icons.png"><img border="0" data-original-height="989" data-original-width="952" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtuesp-gZ9jCCvY8Easy52ZkW_w1AhjMNWA5zVNpMYUxWKR4Pp3nCknbr_u_42iF6Bvg6qgIGxr9NXR8q8_kJ0N7Lg8V8Wl5vrU5cGJ_-xnMeMWPgblJBAKTgX7S5y9NcyBboi25RD1G0e/s16000/00-icons-icons-icons.png" /></a></div><p><br />The following features are introduced along with the numerous bug fixes:</p><p></p><ul><li>(Touch UI) Fully-functional animated main menu is displayed in the sidebar and context panels with the ability to expand/collapse items while maintaining the vertically scrolling of the panel.</li><li>(Touch UI) Option <i>ui.menu.autoExpand</i> controls the state of the navigation menu. The default value is <i>current</i> causing the current menu node to display in the expanded state while the remaining items with the children are collapsed. Set the value to "all" to force all items to expand. Set the value to false to prevent the current menu node from being expanded.</li><li>(Charts) Fetching of calendar data will not cause an exception when the data view has changed and is not available at the time of the attempt to fetch.</li><li>(Touch UI) Optimized the fitting of buttons in the form toolbar for speed and precision.</li><li>(Reading Pane) Button with the "Close" icon is displayed on the left side of the reading pane detail toolbar to allow quick closing to the detail pane.</li><li>(Touch UI) The toolbar of the sidebar is hidden if the settings button is disabled and the menu is positioned in the sidebar when it is fully expanded.</li><li>(Touch UI) Page name is displayed in the accent color on toolbar when the menu location is in the sidebar. The color changes to neutral when the reading pane detail is visible.</li><li>(Touch UI) Menu items show the icons when the location of the menu is in the sidebar. Primary page icons are not displayed in the toolbar of the sidebar when the sidebar is fully expanded since the menu items are visible.</li><li>(Touch UI) Compact styling of the context values of the current master record when rendered in the sidebar.</li><li>(Calendar) Calendar events visually reflect the end time of the event instead of displaying the event with the fixed height.</li><li>(Framework) Client-side business rules returning a deferred object will not perform a duplicate invocation of the method. The flow of execution will continue if the deferred object is resolved.</li><li>(Touch UI) Fixed incorrect bottom border color of the app name in the context panel.</li><li>(Touch UI) The leading header text is now displayed in the sliding panels if header is the first item in the context.</li><li>(Touch UI) Field labels are now displayed with the font size of 12 in all display densities for a consistent presentation in grid/list/cards/panels/sidebars.</li><li>(Touch UI) Fixed incorrect position of "dropped" chevron in the lookups.</li><li>(Touch UI) Focused item outline remains visible in list box/radio button list, and checkbox list when the input is focused.</li><li>(Touch UI) Setting <i>ui.form.lines.horizontal</i> set to false and the tag form-lines-horizontal-none will hide the horizontal lines in the forms.</li><li>(Touch UI) Setting <i>ui.form.lines.input </i>set to true and the tag form-lines-input will show an solid outline around the text inputs.</li><li>(Touch UI) Frozen part of the grid row with the averages will display with the same background color as the rest of the grid.</li><li>(Touch UI) Fixed incorrect "new row" execution under certain conditions in the summary views.</li><li>(Touch UI) Eliminated the erratic horizontal scrolling when the item in the list box, radio button list, and check box list with the large number of items.</li><li>(Touch UI) Placeholder "Optional" is displayed in the nullable field values when the horizontal lines are hidden in the forms.</li><li>(Universal Input) Keyboard navigation in radio button list, list box, and check box list is handling the focus transition correctly when Left and Right buttons are pressed on the keyboard.</li><li>(Touch UI) Tag <i>gird-lines-horzontal-none</i> applied to a data view on the page will hide the horizonal lines in the grid presentation style.</li><li>(Touch UI) Option <i>ui.grid.lines.horizontal</i> will hide the horizontal lines in the data grids globally if set to <i>false</i>.</li><li>(Touch UI) Selection of the main menu item on the toolbar will switch the "selected" state to it while the selected URL is being loaded.</li><li>(Touch UI) Click on the app toolbar menu options will immediately switch the selection in the menu as the page loads to provide a faster selection feedback.</li><li>(Touch UI) Simplified the horizontal scrolling in the grid.</li><li>(Inline Editor) Refreshing of the data view will cause the editor frame to display if the item is in the view.</li><li>(Inline Editing) Command New Row works in infinite and summary data views. The last "Row Template" is selected in response to this command to enable inline input of the new row.</li><li>(Touch UI) Page header main icon is consistently aligned with the top of the header in any state of the page.</li><li>(Reading Pane) The reading pane detail is displayed with a fade-in animation if there is no content in the detail area.</li><li>(Touch UI) Tags h1-h6 used to present the field values in grid/list/cards have the font size of 1 element.</li><li>(Touch UI) Sort order icon in the grid header will toggle the sort order if clicked with a mouse pointer.</li><li>(Touch UI) Apps button will display the navigation menu panel on the left side of the screen if the reading pane is enabled.</li><li>(Touch UI) Grid views are resized on the legacy pages with multiple container/data views when the page is resized.</li><li>(Touch UI) The app toolbar will display the text of the left most "icon" button if there is no button bar in the form. This provides a mode of presentation on small form factor found in modern mobile operating systems.</li><li>(Inline Edior) Notification bar is instantly hidden when the inline editor is activated on the field</li><li>(Touch UI) Aggregate values are displayed with the label in the grid.</li><li>(Touch UI) Aggerate bar uses the new cell separator between the values.</li><li>(Touch UI) Tap/click on the tab bar with the navigation icons will switch the focus to provide a fast visual response after navigation has been initiated.</li><li>(Inline Editor) The focus frame shows above the horizontal scrollbar when the new row is entered in the summary view.</li><li>(Touch UI) Collapsible container body hides the overflow content.</li><li>(Touch UI) External URLs are opened in the modal pages if the reading master or derail, or if another modal page is active.</li><li>(Touch UI) Zooming to fullscreen of a modal content page does not raise an exception.</li><li>(Rich Text) Does not create nested paragraphs when the cursor is positioned at the end of the paragraph. Instead a new sibling paragraph is created to ensure a clean document structure.</li><li>(Rich Text) Consistently inserts BR element across all platforms when <i>Shift+Enter </i>is pressed.</li><li>(Touch UI) Enabled ability to configure multiple icon fonts in the app.</li><li>(Touch UI) Tab bar at the bottom of the app senses the notch on the iOS devices and displays the tabs with the padding above the swipe bar.</li><li>(Touch UI) Fixed incorrect positioning of checkbox slider with the footer text.</li><li>(Touch UI) Geolocation map displayed in the forms is rendered in the DPI of the device for the maximum qualify of presentation.</li><li>(Touch UI) Collapsed categories are not expanded when automatic form focus is set in the form.</li><li>(Touch UI) Input focus forces the collapsed category to initialize the layout when the field in the collapsed category needs to be activated.</li><li>(Touch UI ) Added more font size variations for the prompt to click/tap the blob for upload.</li><li>(Touch UI) The toggle for the categories is not selectable anymore.</li></ul>Customer Servicehttp://www.blogger.com/profile/04471166550881539854noreply@blogger.com0tag:blogger.com,1999:blog-2297698770491701674.post-71726314033085805212021-03-30T14:53:00.113-07:002021-03-31T03:23:31.956-07:00Icons, Icons, Icons<h2> Material Icons and 3rd Party Icon Fonts</h2><p>Touch UI gets its good looks from the Material Icons library designed by Google. Apps based on Touch UI feel at home on the Android devices and Chromebooks. They look crisp and professional on iOS, Mac, and Windows.</p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeTRFfVBzlvtWfvOiyCWkSQsC_CbMzjZ-IW98WXHK3W5kKN04QzfSx9yaROfuGMP9yZJsjtD8LQaQOnwqUuihWDblS-ZDm7x3ZTxacnZWls376U3ygBmEsmKr6jSt5X2lVN78PITGH2F31/s2048/01-ios-good-looks.png" ><img border="0" data-original-height="1536" data-original-width="2048" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeTRFfVBzlvtWfvOiyCWkSQsC_CbMzjZ-IW98WXHK3W5kKN04QzfSx9yaROfuGMP9yZJsjtD8LQaQOnwqUuihWDblS-ZDm7x3ZTxacnZWls376U3ygBmEsmKr6jSt5X2lVN78PITGH2F31/s16000/01-ios-good-looks.png" /></a></div><p></p><p>Touch UI apps support several build-in icon styles and can be extended to use the 3rd party icon collections. </p><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGicS93aC9lhEwL7fdpQJ6ovwJfSv2Z8SM1t02xD0XbfiS9MuofYsWe9EN5iAD_tUh6aBoQ9AMvQfy5wdmHPxOg-ML09DzAoJHUUyfcEJwSeGQKFgWnTsKS0_GzNtTdyIXup0cKmEp558U/s989/00-icons-icons-icons.png"><img border="0" data-original-height="989" data-original-width="952" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGicS93aC9lhEwL7fdpQJ6ovwJfSv2Z8SM1t02xD0XbfiS9MuofYsWe9EN5iAD_tUh6aBoQ9AMvQfy5wdmHPxOg-ML09DzAoJHUUyfcEJwSeGQKFgWnTsKS0_GzNtTdyIXup0cKmEp558U/s16000/00-icons-icons-icons.png" /></a></div><p>There are four different styles of icons that help your app to stand out - <i>filled</i>, <i>outlined</i>, <i>rounded</i>, and <i>sharp</i>. The default style <i>filled </i>can be changed by setting the value to <i>ui.theme.icons </i>property in ~<i>/touch-settings.json </i>configuration file. </p><div><div><br /></div><div>The built-in icons come from the web fonts stored under the <i>~/fonts </i>folder of your application. </div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5Z3gWEf-c1D6ump9-U2VVOrqcKXAkHRWglf4l5PEwCaXU2DL4kEiBhJFweI4cRJVevbIRT3lO6wQHqe-q6OmK3LIvYMg8-Mgkz_F-7s7OANuHpQSUtyWrQjM9Jthnrnypu7ZFdvqZT1Ng/s495/02-icons-font-folder.png"><img border="0" data-original-height="495" data-original-width="290" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5Z3gWEf-c1D6ump9-U2VVOrqcKXAkHRWglf4l5PEwCaXU2DL4kEiBhJFweI4cRJVevbIRT3lO6wQHqe-q6OmK3LIvYMg8-Mgkz_F-7s7OANuHpQSUtyWrQjM9Jthnrnypu7ZFdvqZT1Ng/s16000/02-icons-font-folder.png" /></a></div><div><h2>Configuring 3rd Party Icon Fonts</h2><div>Touch UI makes it easy to integrate additional icon libraries in the application. The following configuration in the <i>~/touch-settings.json</i> file will set the built-in icon font to the outlined style and link the icon collections called <a href="https://fontawesome.com/icons?d=listing&p=2&s=regular,solid&m=free" target="_blank">Font Awesome</a> and <a href="https://materialdesignicons.com/" target="_blank">Material Design Icons</a>. The former offers the popular set of free and commercial icons. The latter is the community-driven effort not affiliated with Google, but bearing a similar name.</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGyXKoqnrnAUYW6imXrbfQWjpMejJ6uWdrXbDZGlkfLZYSdl74zjuJ7O8j6RiY6ajWwaLSv-5mycwSKjh3idzFsyZW8b86ufdPYgQOSrf_Z1dX9W2ewYssX4sIm8NgI4AlEghhsw8gcU7E/s998/03-icon-font-configuration.png"><img border="0" data-original-height="397" data-original-width="998" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGyXKoqnrnAUYW6imXrbfQWjpMejJ6uWdrXbDZGlkfLZYSdl74zjuJ7O8j6RiY6ajWwaLSv-5mycwSKjh3idzFsyZW8b86ufdPYgQOSrf_Z1dX9W2ewYssX4sIm8NgI4AlEghhsw8gcU7E/s16000/03-icon-font-configuration.png" /></a></div><div><br /></div><div><div>Please note that the Font Awesome URL is provided for illustrative purposes only. The vendor requires registration via email. Sign up and you will receive an email with the JavaScript snippet that will hook the web font to your pages. Use the script filename in the <i>ui.iconFonts.fa.url </i>property but keep the “*.css” extension as shown above.</div><div><br /></div><div>The prefixes “fa” and “mdi” are not accidental. Review the documentation of the web font provider and take a notice of the prefix used in the example. Use the same prefix when registering the font in your app. It is the industry standard to prefix the icon names with the same sequence of characters. The cascading style sheets linked to the app will have the corresponding definitions with the references to the icon font family. </div><div><br /></div><div>Touch UI will create dynamic CSS rules at runtime to make the 3rd party icons match the width and height of the built-in icons. Specify a numeric “size” property for the prefix defined in <i>ui.theme.iconFonts</i> if the icons appear to be larger or smaller than the standard icons of Touch UI. The default size of the icons is 24 pixels.</div></div><div><h2>Using Icons in the Application</h2><div><br /></div><div>Let’s apply the standard icon <i>shopping_cart</i> to the <i>editForm1 </i>view in the <i>Products </i>data controller. Open your app in the Project Designer, find the view, and enter <i>material-icon-shopping-cart </i>in the <i>Tags </i>property.</div></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPwn01d8mYO_5Fm2uXDgcUeyEooqAZOj3mk6VTs4Gcjjnzrv4ShogBI5trEQrnV0_r1wZ1AVeGbtYJ7aBUBcT1uvaqO-EiL-u0AikWgQrLCpaQgXufHJh3Blni7DBIZgsBbrdVUJz4ZRGe/s1040/04-touch-ui-edit-form.png"><img border="0" data-original-height="948" data-original-width="1040" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPwn01d8mYO_5Fm2uXDgcUeyEooqAZOj3mk6VTs4Gcjjnzrv4ShogBI5trEQrnV0_r1wZ1AVeGbtYJ7aBUBcT1uvaqO-EiL-u0AikWgQrLCpaQgXufHJh3Blni7DBIZgsBbrdVUJz4ZRGe/s16000/04-touch-ui-edit-form.png" /></a></div><br /><div>This will enhance your form with the corresponding icon in the header. The icon is over-imposed on the larger self visible partially in the background for an added artistic touch.</div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRhSNaxKfcRQyB_dd7kqlsASaGjUa4GN4AR4bJSrSo5TN5fGq_3ufs4HygEwf2hDW7GfmFoIkXxvAt_1fgYGkuC6OH6r3u1PLPaWPHFQpzlVwXsx2OlOtHmc0dX9fA9AqW1qGBoqyHUt6K/s1040/05-touch-ui-form-with-material-icon.png"><img border="0" data-original-height="948" data-original-width="1040" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRhSNaxKfcRQyB_dd7kqlsASaGjUa4GN4AR4bJSrSo5TN5fGq_3ufs4HygEwf2hDW7GfmFoIkXxvAt_1fgYGkuC6OH6r3u1PLPaWPHFQpzlVwXsx2OlOtHmc0dX9fA9AqW1qGBoqyHUt6K/s16000/05-touch-ui-form-with-material-icon.png" /></a></div><br /><div>Clear the tag on the view editForm1 and enter the<i> fa-shopping-basket</i> to activate the shopping basket icon from the Font Awesome library.</div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWcDZNdk1dv438z17NR-h9zl_YXsakOCgwbiGAFWWY8TngE0MgUezoXIeovCY26J5bL0OH5iLTTSpMYWv0V4zFW1KCn9KqGYYTYjZaR-9P5FmzI5xhlF_ZnyoRGHSSENtqVyAFb9dvr5vj/s1040/06-font-awesome-icon-in-form.png"><img border="0" data-original-height="948" data-original-width="1040" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWcDZNdk1dv438z17NR-h9zl_YXsakOCgwbiGAFWWY8TngE0MgUezoXIeovCY26J5bL0OH5iLTTSpMYWv0V4zFW1KCn9KqGYYTYjZaR-9P5FmzI5xhlF_ZnyoRGHSSENtqVyAFb9dvr5vj/s16000/06-font-awesome-icon-in-form.png" /></a></div><div><br /></div><div>Here is what happens if you tag the <i>editForm1</i> view with the <i>mdi-</i>basket and engage the Material Design Icons library.</div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeWcAyTSzHpSGFLtBG0_3YowMTBSWnhAFMhWk43xnqP0BX9lN13wiLPvLp_n9X-2mtMWwIGPMhyphenhyphen1rZINZ7Z5nVn6KaZy_UvCtCHIo5kRHHJcs4T7ZG0ySBAPH1hsD-O8F-DOVvtmFDZzo7/s1040/07-font-mdi-icon-in-form.png"><img border="0" data-original-height="948" data-original-width="1040" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeWcAyTSzHpSGFLtBG0_3YowMTBSWnhAFMhWk43xnqP0BX9lN13wiLPvLp_n9X-2mtMWwIGPMhyphenhyphen1rZINZ7Z5nVn6KaZy_UvCtCHIo5kRHHJcs4T7ZG0ySBAPH1hsD-O8F-DOVvtmFDZzo7/s16000/07-font-mdi-icon-in-form.png" /></a></div><div><br /></div><div>Assign icons to actions and pages by entering the icon name in their <i>Icon / Custom Style </i>property. For example, icons <i>fa-truck </i>and <i>fa-coffee </i>are assigned to the <i>Shippers </i>page and custom action <i>Take a Break </i>in the screenshots. The icons will show on the sidebar, in the navigation tabs, and in the menu options.</div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhChFz8ACdm3gieeSolrkMEg54zsVtpYPgXAcXyvSjagFKbVXO6osf7E3f17f6ZcnYg8UKgW5Ln-HaW_s1rZQvF-6_hbXn_PdbMvItpGg646i5RRH3Dm2rtZsRaGz9g9jL87YVat4Hdo0_S/s753/08-font-awesome-icons.png"><img border="0" data-original-height="753" data-original-width="502" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhChFz8ACdm3gieeSolrkMEg54zsVtpYPgXAcXyvSjagFKbVXO6osf7E3f17f6ZcnYg8UKgW5Ln-HaW_s1rZQvF-6_hbXn_PdbMvItpGg646i5RRH3Dm2rtZsRaGz9g9jL87YVat4Hdo0_S/s16000/08-font-awesome-icons.png" /></a></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKNNeFgVz3zXYlwVdwuUHR-duwrW6JPc-BYi1nrA0L5tYkNsv_MZuycMu0OB_cgpFcANFd49_Y8Fhp4CoYg673p3R-lVIJjoRfBe3QE4M_fmwalTF1L-oE7lveBC2-DaDIUctXq5_D6OZq/s801/09-font-awesome-sample2.png"><img border="0" data-original-height="792" data-original-width="801" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKNNeFgVz3zXYlwVdwuUHR-duwrW6JPc-BYi1nrA0L5tYkNsv_MZuycMu0OB_cgpFcANFd49_Y8Fhp4CoYg673p3R-lVIJjoRfBe3QE4M_fmwalTF1L-oE7lveBC2-DaDIUctXq5_D6OZq/s16000/09-font-awesome-sample2.png" /></a></div><div><h2>Embedding Icon Fonts in Apps</h2><div>If you plan to run your app in the native mode or prefer not to have the external dependencies, then consider embedding the stylesheets and fonts directly in the app folders. </div><div><br /></div><div>Run the app in the web browser and bring up its Web Inspector. Disable caching on the Network tab and refresh the page. You will find the external references to the CSS stylesheets and the web fonts listed in the traffic. Save them in a dedicated folder under <i>~/css </i>directory of your app. </div><div><br /></div><div>Next remove the “url” property from the prefix under <i>ui.iconFonts </i>in <i>~/touch-settings.json</i>. Keep the prefix even if it is empty. Run the app and make sure that only the local references appear in the network traffic of the browser. The CSS files will be loaded automatically, but you may need to manipulate the relative references to the web fonts in the CSS files if icons do not show up.</div><div><br /></div></div>Customer Servicehttp://www.blogger.com/profile/04471166550881539854noreply@blogger.com0tag:blogger.com,1999:blog-2297698770491701674.post-87083806377787850492021-03-27T11:06:00.065-07:002021-03-30T11:16:19.112-07:00Navigation Menu<p>Apps created with Touch UI have three options for the placement for the navigation menu. By default the top-level items of the navigation hierarchy are displayed as tabs in the toolbar. Menu items with children will have a dropdown menu. The spill-over items are moved under “More” menu item created automatically as needed.</p><div ><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPT5o1J2tiqvmwSlU14o4WHWIcm83HpIvkaSoGXBMqbMHZF6eY2GWH7iiLJNmyjkl-s0fZ8CRvm7fMZ0qwqkHXdynL7Vysw3Fin6VG7q16TVvI4wRmy6hxwhxIcd-lYrlujewxymQBnwz0/s821/01-touch-ui-default-menu.png" ><img border="0" data-original-height="733" data-original-width="821" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPT5o1J2tiqvmwSlU14o4WHWIcm83HpIvkaSoGXBMqbMHZF6eY2GWH7iiLJNmyjkl-s0fZ8CRvm7fMZ0qwqkHXdynL7Vysw3Fin6VG7q16TVvI4wRmy6hxwhxIcd-lYrlujewxymQBnwz0/s16000/01-touch-ui-default-menu.png" /></a></div><br /><div><div>Developers may choose to move the menu to the sidebar displayed on the left side of the app. The space in the sidebar is at the premium and the complex menus will be collapsed with the current node expanded. The sublevels of the menu can be individually expanded and collapsed. The same collapsible menu is also displayed when the Apps button is pressed. It is also visible in the hamburger menu and on the small screens.</div></div><div><br /></div><div ><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilYVaFcQGDHfE01PY4LLC8ndQLUHchx2SxjCN9dSBTFUPKe3oniqoA-YjuwoBE1SuTN7Umpq06X6i1myZUgvrx_L18nT5-oAiVJECtjggEkJa5E3XBPpDwP02Br8PpqqKseHW7lN7vyYQs/s1128/02-touch-ui-sidebar-menu.png" ><img border="0" data-original-height="842" data-original-width="1128" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilYVaFcQGDHfE01PY4LLC8ndQLUHchx2SxjCN9dSBTFUPKe3oniqoA-YjuwoBE1SuTN7Umpq06X6i1myZUgvrx_L18nT5-oAiVJECtjggEkJa5E3XBPpDwP02Br8PpqqKseHW7lN7vyYQs/s16000/02-touch-ui-sidebar-menu.png" /></a></div><div><br /></div><div>Enter the following in <i>~/touch-settings.json </i>to move the menu to the sidebar and to relocate the Apps button next to the user profile icon on the toolbar. </div><div><br /></div><div class="separator"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlEsVb9m8bDPyl1TsrWI_f8S04Tu0nHxXIweRwiLEw0vYvhViBLC7REPlpZlIR-uebrlyR9ZTuf2fCn1SxtWr5bx2z6J8f723I4acXvDxXFse3ZX9CkS_VV-_UgBZgNCzTicKjxonngfED/s416/03-sidebar-menu-config.png"><img border="0" data-original-height="287" data-original-width="416" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlEsVb9m8bDPyl1TsrWI_f8S04Tu0nHxXIweRwiLEw0vYvhViBLC7REPlpZlIR-uebrlyR9ZTuf2fCn1SxtWr5bx2z6J8f723I4acXvDxXFse3ZX9CkS_VV-_UgBZgNCzTicKjxonngfED/s320/03-sidebar-menu-config.png" width="320" /></a></div><div><br /></div><div><div>The <i>Apps</i> button is the icon represented with 3 x 3 solid squares or circles. You will find it in the sidebar, on the toolbar, or in the hamburger menu of your app. Its purpose is to provide quick access to the most important pages of the app and to the full navigation menu.</div><div><br /></div><div>Assign a dedicated icon to a page by entering the icon name in the <i>Icon / Custom Style</i> property of the page in the Project Designer .The extensive <a href="https://material.io/resources/icons" target="_blank">Material Icons</a> library is included with the framework. The name of the icon can be entered with the <i>material-icon-</i> prefix (e.g. <i>material-icon-emoji-people</i>).The icons will be displayed in the sidebar, in the context menu options, and in the drop down menus of the app toolbar. The top-level items will not have the icons in the menu with the default placement.</div><div><br /></div><div>Up to five icons are visible in the mini sidebar and the full set is presented in the context panel activated with the <i>Apps </i>button. The More option in the context panel will show the complete navigation menu.</div><div><br /></div></div><div ><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkGMoLLSeCZIyOtoYCtwYOGDLqnmKxXXiXV98CSjfEBp4-DpziUPslNvSR_O1NqT0fehBKpkQNVk8GnfLe3TCGSrqHUxo3I-uXZZT0A-sr9xN5exmf1zOVAKmnibQuOFLI5BwhZ-9ycpEh/s1128/04-apps-menu.png" ><img border="0" data-original-height="842" data-original-width="1128" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkGMoLLSeCZIyOtoYCtwYOGDLqnmKxXXiXV98CSjfEBp4-DpziUPslNvSR_O1NqT0fehBKpkQNVk8GnfLe3TCGSrqHUxo3I-uXZZT0A-sr9xN5exmf1zOVAKmnibQuOFLI5BwhZ-9ycpEh/s16000/04-apps-menu.png" /></a></div><div><br /></div><div>If at least two pages have a dedicated icon, then the app will display the tabs at the bottom of the screen when the sidebar is hidden. The spill-over icons will migrate to the <i>More </i>tab.</div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIFu1KWOMIu0q_PUqCDPdGyzDapf8rTKErMN43MJsLJYS3IEH-UHqXOVeksa3eUcwmS0ZRXoqNhJaACb8uxwgOcBALZ95bKqCL1PXlrBHXG1JXUAbNnAz8iXqltjo-jqDLI9qRuernsX-o/s680/05-navigation-tabs.png" ><img border="0" data-original-height="680" data-original-width="502" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIFu1KWOMIu0q_PUqCDPdGyzDapf8rTKErMN43MJsLJYS3IEH-UHqXOVeksa3eUcwmS0ZRXoqNhJaACb8uxwgOcBALZ95bKqCL1PXlrBHXG1JXUAbNnAz8iXqltjo-jqDLI9qRuernsX-o/s16000/05-navigation-tabs.png" /></a></div><br /><div>The hamburger menu will display the full navigation menu.</div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDfpjXHXTiodRqvE4RMFwrhx_1NOSEKV1ysreImF03T5ybwZgGtVf5KReDzjhDdP4fMt8GH6823BGvnajqhp9gYZmK9im0Egi5n1g15KDq1avy_k2N9BC71nbwapk285PMiS8EgQ5B2ojl/s680/06-hamburger-menu.png" ><img border="0" data-original-height="680" data-original-width="502" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDfpjXHXTiodRqvE4RMFwrhx_1NOSEKV1ysreImF03T5ybwZgGtVf5KReDzjhDdP4fMt8GH6823BGvnajqhp9gYZmK9im0Egi5n1g15KDq1avy_k2N9BC71nbwapk285PMiS8EgQ5B2ojl/s16000/06-hamburger-menu.png" /></a></div><div><br /></div><div><div>Developers may opt to hide the navigation menu from the toolbar and the sidebar by setting <i>ui.menu.location </i>to none in <i>~/touch-settings.jso</i>n for a minimalist look and feel. The navigation menu will still be available through the Apps button and the hamburger menu.</div><div><br /></div><div>The state of nodes in the navigation menu with the vertical layout is controlled by <i>ui.menu.autoExpand</i> property. The default value is <i>current</i>, which will expand one level of the menu node representing the current page. Setting this option to <i>false </i>will keep the current node collapsed. The <i>all </i>value will have all items fully expanded when the navigation menu is rendered vertically.</div><div><br /></div><div>Touch UI completely automates the navigation menu presentation while letting the developer focus on what’s important.</div></div><div><br /></div>Customer Servicehttp://www.blogger.com/profile/04471166550881539854noreply@blogger.com0