Introduction Welcome to the first EnterPage Newsletter for 2013. This makes 16 years of newsletters! You can see the whole archive at http://www.plattecanyon.com/enterPage.aspx if you want a "blast from the past." We have spent the last couple of months since the last newsletter updating our popular Learning & Mastering ToolBook training as well as add-on products like the Plug-In Pro for ToolBook 11.5. This newsletter describes these new products, gives a review of ToolBook 11.5, and offers the usual dose of blog postings and Programming for e-Learning Developers tips on ToolBook and JavaScript. Thanks for being part of the Platte Canyon extended family! |
Learning & Mastering ToolBook 11.5 Released We have completely updated this popular training application for ToolBook 11.5. This was more work than usual since we moved to Windows 8 for this release. So every screen capture, "Show Me" video, and "Let Me Try" simulation has been redone with the Windows 8 interface. We have added new content on publishing to the web, the various new tools available, updated screens such as Resource Manager, and more. It also has extensive and updated content on the Quiz Summary, Certificates, XML, importing from PowerPoint, the Actions Editor, Flash, OpenScript, JavaScript, SmartPages/SmartStyles, HTTP Post, REST calls, Simulations, and much more. There are tons of reference applications, server-side source code (Visual Studio 2012 files), and other files included. Learning & Mastering ToolBook contains over 30 hours of training with:
Information Purchase |
ToolBook 11.5 Review By Jeff Rhodes, Platte Canyon Multimedia Software Corporation It is always nice to see a new ToolBook release. While I didn't see all that I hoped for (particularly HTML 5 media), there are some nice additions to the product. With the appropriate updates from Microsoft, I have found it to be quite stable on my new Windows 8, 64-bit machine. Publishing has been quite fast, though my 32 GB of memory and quad-core processor probably help! With additional resources from SumTotal, ToolBook 11.5 should be a good basis for more substantial features in future versions. My personal wish list still includes HTML 5 export (including media via HTML 5 rather than Windows Media Player or Flash), additional SmartPages, more capabilities in the Actions Editor, and the ability to export PowerPoint directly to a SmartPage. Here are some of the new features of 11.5: New features of version 11.5:
We recommend keeping your support current and getting your hands on this new release. In particular, those of you who are publishing to DHTML will want to stay with the newest release to support the widest range of browsers. Platte Canyon ToolBook Information ToolBook 11.5 User Guide ToolBook Web Site |
Plug-In Pro 11.5 and Other ToolBook Products Now Available
We have updated Plug-In Pro for ToolBook 11.5. A full license is $395. The upgrade from 11.0 is $75 and from any previous Plug-In Pro version is $260. With over 140 utilities, editors, and short-cuts, the Platte Canyon® Plug-In Pro is the ToolBook developer's best friend. We have also created Storyboarder for ToolBook 11.5. If you own Storyboarder for a different ToolBook version, the price is only $95. A full version is $295. The Platte Canyon® Storyboarder creates a Microsoft Word or PowerPoint storyboard from an existing ToolBook book. The document or presentation includes an optional screen capture of each page, field, button, and other text, question answers/feedback, simulation information, and other content - all in the same order top to bottom as in your book. For the PowerPoint storyboard, you can put the content in speaker notes and/or a contents textbox. You can also have an optional comments textbox on each slide. You can run Storyboarder in author-level ToolBook or download the complete ToolBook runtime installation. We have also updated TBK Tracker and the ToolBook Translation System for ToolBook 11.5. There is no charge to download the ToolBook 11.5 files for developers who own the current versions of these products. Plug-In Pro Information Storyboarder Information TBK Tracker Information ToolBook Translation System Information |
Recent Blog Posts
Here are some recent blog posts. Responsive Web Design Book Setting SkipNavigation via the Command Window We hope you will visit our blog often and consider subscribing to the RSS feed. Blog RSS Feed |
Programming for e-Learning Developers Segment This feature is a short segment from Jeff's Programming for e-Learning Developers book. Building a GlossaryA common e-Learning requirement is to be able to click on a hyperlink and display a popup display of the corresponding definition. We'll implement a simple version of this capability in this chapter. We'll build on techniques we learned in the Hyperlinking to a URL chapter in order to create the hyperlinks. To make things interesting and to avoid having to create a custom "data store" of the glossary names and definitions for each environment, We'll add a GetGlossaryDefinition method to our ASP.NET service and call that to retrieve the actual definition.ASP.NET Web ServiceWe first created this service in the Sending Email chapter. To add a glossary lookup capability, we first need to decide how to store the glossary entries. A good choice is a database. We'll use an Access database adapted from our Training Studio product and locate it in the "App_Data" directory of our web site. This is a good choice since ASP.NET will prevent anything in this directory from being downloaded. We'll use a simple structure where we look up the value based on the GlossaryName column and store the value in the GlossaryDefinition column.We'll include a stored query called ReadGlossaryEntries that We'll use to load the entire table of glossary entries into memory from the web service. This allows us to "cache" the data on the web server. When a glossary request comes in, the web server will only read the database if it is not already in memory. This dramatically improves performance and is why we can get away with using Access rather than a higher-powered database like SQL Server. We don't have time to get into the details of how the e-Learning developer would add, edit, or delete glossary entries, but there are options ranging from simple forms in Access to a separate editor application (which is what we use in Training Studio). Here is the implementation code (Visual Basic) for our new GetGlossaryDefinition web method. Imports System.Data Imports System.Data.OleDb <WebMethod()> Public Function GetGlossaryDefinition(ByVal accessKey _ As String, ByVal glossaryKey As String) As String Dim glossaryDefinition As String = accessKeyInvalidString If accessKey = Me.WebServiceAuthorizationKey Then Dim viewId As DataView = Me.GlossaryDataView viewId.RowFilter = String.Format("GlossaryName = '{0}'", _ glossaryKey.Replace("'", "")) If viewId.Count > 0 Then glossaryDefinition = viewId(0)("GlossaryDefinition").ToString Else glossaryDefinition = "Definition not found." End If End If Return glossaryDefinition End Function Private ReadOnly Property GlossaryDataView() As DataView Get Dim viewId As DataView If Current.Cache("GlossaryDataView") Is Nothing Then Dim conStr As String = _ String.Format("provider=Microsoft.Jet.OLEDB.4.0; Data Source={0}App_Data\Glossary.mdb", _ Current.Request.PhysicalApplicationPath) Dim conId As New OleDbConnection(conStr) Dim commandId As New OleDbCommand("ReadGlossaryEntries", conId) Dim adapterId As New OleDbDataAdapter(commandId) Dim tableId As New DataTable conId.Open() commandId.CommandType = CommandType.StoredProcedure adapterId.Fill(tableId) viewId = tableId.DefaultView Current.Cache("GlossaryDataView") = viewId conId.Close() Else viewId = CType(Current.Cache("GlossaryDataView"), DataView) End If Return viewId End Get End Property We start by importing two additional namespaces that we need: System.Data (having to do with general database objects) and System.Data.OleDb (having to do with communicating with Access databases). We then mark GetGlossaryDefinition with the <WebMethod()> attribute to denote that it can be called externally and make it Public. As with our previous examples, we validate against our WebServiceAuthorizationKey, which is stored in the web.config file on the web site. From there we read our GlossaryDataView property to get our viewId object, which is of type DataView. A DataView is a representation of a table that can be sorted and, what we are looking for, filtered. To do this, we set its RowFilter property. We use the fact that the column with our "key" is named "GlossaryName." So if we are looking for the definition of "bass," the RowFilter would be: GlossaryName = 'bass'. We put the value in single quotes to account for the situation where it is multiple words (like "lead guitar"). We remove any single quotes in the key to avoid formatting problems. We now check the Count of our viewId. If it is greater than 0 (it should be 1 but we don't want it to stop working if we get a duplicate entry for some reason), we get the first row (viewId(0)) and then the "GlossaryDefinition" column. Since this could presumably have other types of data, we call its ToString method to get the text version. This is what we return from our method call. Let's now look at the GlossaryDataView property. This is ReadOnly, meaning that we only read the data and never set it. It is also Private, which means that it can only be used by methods within the web service (e.g., we couldn't read it from our ToolBook, Flash, or other applications). We define our viewId return type and then check the Cache to see if it is holding an object with the "GlossaryDataView" key. If not, we read the database. To do this, we start with our "connection string," which is the conStr variable. We use Request.PhysicalApplicationPath to get our hands on the actual local file path of our web site. Our provider is "Microsoft.Jet.OLEDB.4.0" and our data source is the complete path to the database. We could add a password if needed as well. Once we have a connection string, we use this to build an OleDbConnection object. This is what actually connects to the database. We use this in turn to build an OleDbCommand object, telling it the name of the query, more generally called a "stored procedure," ("ReadGlossaryEntries") and passing it the connection. Still not done, we use this command to create an OleDbDataAdapter object. This is what actually executes the query. We want to read the query into a DataTable object, so that is what we create next. We are now ready to go. We call the Open method of our conId connection object. We set the CommandType property of our command object to tell it that what we passed back in its "constructor" was the name of a stored procedure (query). We then call the Fill method of the adapter to execute the query and write the results to our tableId object. From there, we read its DefaultView property to get what we are looking for, a DataView object. So that we don't have to keep touching the database (which is a relatively slow operation), we add viewId to the Cache. Until the web server needs the memory for something else, future calls the web service will get viewId directly out of memory. Either way, we return viewId to the calling method. Programming for e-Learning Developers Information Order Programming for e-Learning Developers ($29.95 with free shipping in the U.S.) |
Expert Information from Learning & Mastering ToolBook By Jeff Rhodes, Platte Canyon Multimedia Software Corporation fontFace, fontStyle, and fontSize Here is a recent email from a customer: Is there a code you know of.... to use in the Command Window that would change the text of a field to: font = ms sans serif, font style = bold, size = 14. I am have to change several fields (not all) to this and looking for a faster method than highlighting and clicking on all the info to change. Here is my response: Good idea. Easiest is to select the field in question and use this script in the Command Window: fontFace of selection = "ms sans serif"; fontStyle of selection = "bold"; fontSize of selection = 14 If you don't see the results, the text itself may have a different font applied. In that case, you can use this script: fontFace of text of selection = "ms sans serif"; fontStyle of text of selection = "bold"; fontSize of text of selection = 14 |
OpenScript Tip from Learning & Mastering ToolBook
By Peter Jackson, ToolBookDeveloper.com Phantom Question Feedback Clips Question: Every time I export, I get a fatal error ... something to the effect of "invalid element group in content of question ..." When I check the error log, I get a list of "field id with error: File not found: clip whatever." The problem is that in the Book Explorer these fields and clips don't exist. The Clip Manager shows no clips. I have run validate tools, repair kits, etc., but nothing seems to remedy the situation. Anyone have any thoughts? Answer: This sounds like you have inadvertently added a clip to either the immediate or delayed feedback of one or more of the questions in your book. Copy and paste the OpenScript below into the script of a button. Then go to reader and click the button. to handle buttonClick local array ansArray[][] local object pageObj, qObj local logical ss, hasChanged local int pCnt, p, qCnt, q, aCnt, a, updCnt forward ss = sysSuspend; sysSuspend = false; clear sysError updCnt = 0 pCnt = pageCount of this book step p from 1 to pCnt pageObj = page p of this book qObjs = getObjectList(pageObj,"","ASYM_WID_QType") qCnt = itemCount(qObjs) step q from 1 to qCnt qObj = item q of qObjs ansArray = ASYM_WID_AnsArray of qObj if sysError = "" then -- First we check Immediate Feedback hasChanged = false aCnt = item 1 of dimensions(ansArray) step a from 1 to aCnt if ansArray[a][13] <> "" then ansArray[a][13] = "" hasChanged = true end if end step if hasChanged then ASYM_WID_AnsArray of qObj = ansArray increment updCnt end if else clear sysError end if ansArray = ASYM_WID_SummaryFeedback of qObj if sysError = "" then -- Now we check Delayed Feedback hasChanged = false step a from 1 to 3 if ansArray[a][13] <> "" then ansArray[a][13] = "" hasChanged = true end if end step if hasChanged then ASYM_WID_SummaryFeedback of qObj = ansArray increment updCnt end if else clear sysError end if end step end step sysSuspend = ss; clear sysError request "Updated" && updCnt && "items." end buttonClick Note that this script will remove any clip reference from the immediate and/or delayed feedback of all questions. As always, it's a good idea to make a backup of you book first:-) |
Web Hint from Learning & Mastering ToolBook
By Denny Dedmore, SumTotal Systems, Inc. Dynamic Display Document Question: I am exporting to DHTML. Is there a way to use the Display Document action using an expression instead of pointing to a specific file? Basically, I need to dynamically call PDF files. Answer: No, but you can use the Jump To URL #1 Catalog object for the same purpose. - Add one to your page - Programmatically populate the field, within the Jump To URL #1, with your path - Programmatically trigger the GO button Of course you can HIDE the object if you like, it does not need to be visible to function. |
JavaScript Tip
By Jeff Rhodes, Platte Canyon Multimedia Software Corporation Enabling the Next Page Button after Media Completion in Training Studio One of our Training Studio customers wanted to disable the "Next Page" button on a "Media Full Screen" template until the video was completed. We had the hooks in there and thus this was an easy change. The relevant "load" code is shown below. $(function () { // template population code omitted var videoId = document.getElementById("player_0"); if (videoId != null) { // can play HTML5 video videoId.addEventListener("ended", contentCompleted); } else { contentCompleted(); } // bind keyboard events $(document).keydown(parent.ImplementKeyDown); }); The $() means that the jQuery will call the function after the page fully loads. We then get our hands on the HTML object that we use to play our HTML 5 audio or video. If the browser is not HTML 5 capable, then we call the contentCompleted function right away so that the user is not stuck. We then handle the ended event with the addEventListener method. We tell it to call the contentCompleted function when the video is ended. This function is shown below. function contentCompleted(e) { // show completion image parent.CompletionImageRef.show(); // enable next page button parent.SetBtnStatus(parent.NextButtonRef,"Next",true,true); } We make two function calls to our main JavaScript file. We refer to it via parent since it is attached to the parent object (the templates are shown in an iFrame of the page - so the page is the parent). The CompletionImageRef.show() line shows our completion image while the SetBtnStatus method sets the Next page button to enabled (and keeps it visible). |
The EnterPage is distributed up to four times per year, with occasional special issues. Individuals who have expressed interest in Platte Canyon Multimedia Software Corporation or its products receive The EnterPage. Suggestions for articles or proposals for article submissions are welcome. Send information to ep@plattecanyon.com. Back issues of the EnterPage are available at: http://www.plattecanyon.com/enterpage.aspx |
Platte Canyon Multimedia Software Corporation, 8870 Edgefield Drive, Colorado Springs, CO 80920, (719) 548-1110 |