Genie en Francais!
When initially installed, Genie is set up with an English-language interface. However, Genie can also be set up with French-language screens so that staff and users can work in the language of their choice. Installation is fairly straightforward using Inmagic's instructions and localization files, but does involve editing some Genie .config files. From your library home page, you can direct end users to the OPAC and have it start in either language, simply by specifying the language in the URL. e.g. http://yourserver/InmagicGenie/opac.aspx?Language=fr-CA will start the OPAC in Canadian French. Library staff can also choose a language for working with the Catalog, Serials and other modules. In both the OPAC and library staff area, a cookie is set to retain the language choice. Contact Andornot or Inmagic, Inc. to obtain the French localization files and step-by-step instructions for installation.
Use Genie Resource Files to Change Textual Elements
The Genie config files allow changes to many textual elements within Genie, from field names and labels to the names of the Browse buttons. However, not everything that appears on the Genie screens is exposed in the config files. Other text is stored in a resource file, one for different languages, that can be copied and edited using the procedure below. Note that there is currently no documentation for changing these files. 1. Locate the file "GlobalResource.RESX ". It is typically installed in C:\Program Files\Inmagic\Genie\App_GlobalResources. 2. Create a new plain text file in this same folder called "GlobalResource.en-US.RESX" (or if your instance of Genie is configured for a different locale, change en-US to that locale). 3. Copy the following from the GlobalResource.RESX file to the new .RESX file: - The header information: Everything from the top of the file to just before the first <data> tag.
- Only those <data> tags containing messages that you want to be different than the original message.
- The </root> tag from the bottom of the file.
4. Within the <data> tags you copied, edit the text between <value> and </value> to change the message. For example, to change the name of the InfoCart to "Record List", you would copy all of the <data> tags that refer to the InfoCart and edit their values to incorporate Records List. 
Index Popups 2008.2.9.10 Update
Index popups for Inmagic Webpublisher Pro have been updated to fix some subtle bugs: - Entering certain characters in find box causes invalid XML errors.
- Previous Page and Last Page do not work with some secondary fieldnames, or when fieldname is provided whose sentence case does not match actual field exactly.
- Passwords are not passed through after the initial page. (Ok, not so subtle this one.)
- Code fields can cause invalid XML errors.
- Last Page fails if icsweb.ini/dbtwpub.ini SoapFormat=0 or SoapFormat=n and fieldname requires modification for XML use.
Unfixable issue: - Previous Page fails if icsweb.ini/dbtwpub.ini SoapFormat=0 or SoapFormat=n and fieldname requires modification for XML use. (Can only fix by changing SoapFormat=1 due to Webpublisher restrictions on fetching index lists with a key delta.)
Download Index Popups 2008.2.9.10 (~600 kB) Labels: inmagic, Webpublisher
Virtual PC 2007 networking tip
If you want to interact with a virtual machine as part of your network, you need to adjust its networking settings to specifically use one of the host machine's network adapters. Don't set the adapter to "Shared networking (NAT)". This isolates the virtual machine behind the virtual networking adapter. You'll find you can't even ping the VM from the host. Good for interacting Bad for interacting 
DB/Text trace log format method
Further to my post of May 2007, where I described how to create a trace log in DB/Text and handle exceptions, here is a method that is handy for building more complex log statements. 1: // construct formatted log statement
2: function logFormat(val, arg1, arg2, arg3)
3: {
4: var formattedVal = val;
5: if (arg1 != null) {
6: formattedVal = formattedVal.replace("{0}", arg1);
7: }
8: if (arg2 != null) {
9: formattedVal = formattedVal.replace("{1}", arg2);
10: }
11: if (arg3 != null) {
12: formattedVal = formattedVal.replace("{2}", arg3);
13: }
14: log(formattedVal);
15: }
16:
17: // write log statement to form box
18: function log(val)
19: {
20: var box = Form.boxes("boxDebugLog");
21: if (box == null)
22: return;
23:
24: if (box.content != '')
25: {
26: box.content += "\n";
27: }
28: box.content += val;
29: }
Overview
logFormat takes a string value and up to 3 arguments, and replaces tokens found in the string value with those arguments. It's based on C#'s string.Format method, and others like it.
Example
It's easier to read (and write) a format string that contains tokens than a string concatenated together with plus signs.
1: var count = 10;
2: var name = "Peter";
3: var duration = 30;
4:
5: function LogTheOldWay()
6: {
7: log(name + " was lashed with a wet noodle " + count + " times for " + duration + " seconds.");
8: }
9:
10: function LogTheNewWay()
11: {
12: logFormat("{0} was lashed with a wet noodle {1} times for {2} seconds.", name, count, duration);
13: }
Update
My example above only proves how piddly my skills really are. There's a *much* better way of doing this that allows for n arguments instead of a maximum of three. I had forgotten that every javascript function has a local property called arguments that contains all parameters passed to the function as an array.
1: function logFormat(val)
2: {
3: var formattedVal = val;
4: for(i = 1; i < arguments.length; i++)
5: {
6: formattedVal = formattedVal.replace("{" + (i - 1) + "}", arguments[i]);
7: }
8: return formattedVal;
9: }
Labels: db/textworks, javascript
"Static" properties in javascript. Kinda.
The following gives me the ability to access javascript properties in a static kind of way. Not really, since the object has been instantiated, but at least I don't have to define a specific object, then call its constructor all the time to new it up and get at its properties. 1: // declare globally
2: var Artist = {
3: Fields: {
4: Id: "ID",
5: FullName: "Term",
6: FirstName: "First Name",
7: LastName: "Last Name",
8: Birth: "Date of Birth",
9: Death: "Date of Death"
10: }
11: };
Overview
I like to store DB/Text field names in this way, as they become (pseudo) strongly-typed and the magic strings are stored in one place only, instead of scattered across my code like dandelion seeds.
It can be difficult to work in javascript after C# and other full-featured languages. This is the closest I could come to static properties or a struct. If I weren't scripting in DB/Text, a proprietary closed system, I would be using jQuery or mootools, which put the joy back in joyvascript.
Example
Now I can access field names statically as follows. Look ma, no constructors!
1: function SomeMethod()
2: {
3: var idFieldName = Artist.Fields.Id;
4: }
Labels: db/textworks, javascript
A highly reusable recordset script for DB/Text
This javascript function performs a search against a DB/Text database and returns a sorted array of dictionary objects with fieldnames as keys. Parameters Search(commandQuery, textbase, password, fieldsToReturn, sortFields) commandQuery (string): A query in command syntax. textbase (string): The name of the textbase to query. password (string): A textbase password that allows querying. fieldsToReturn (array): An array of field names whose values the query will retrieve from result records. sortFields (array): An array of field names to sort the recordset by. Dependencies SortByField(recordset, sortFields): A method that sorts a recordset by the fields provided. 1: // returns array of dictionaries with fieldsToReturn as keys
2: function Search(commandQuery, textbase, password, fieldsToReturn, sortFields)
3: {
4: var rs;
5: var output = [];
6:
7: rs = Application.newRecordset(textbase, Application.activeTextbase.path, password);
8: if (rs != null)
9: {
10: try {
11: rs.Open(commandQuery);
12: if (rs.Errors.Count > 0)
13: {
14: // log error
15: }
16: else if (rs.RecordCount > 0)
17: {
18: // sort the recordset
19: rs = SortByField(rs, sortFields);
20:
21: rs.MoveFirst();
22: while (!rs.EOF)
23: {
24: // create dictionary of field values, add to output list
25: var record = new Object();
26: for (var i = 0;i < fieldsToReturn.length;i++)
27: {
28: record[fieldsToReturn[i]] = rs.Fields(fieldsToReturn[i]).Value;
29: }
30: output[output.length] = record;
31:
32: rs.MoveNext();
33: }
34: }
35: }
36: catch (e) {
37: // log exception
38: }
39: finally
40: {
41: rs.Close();
42: }
43: }
44: return output;
45: }
46:
47: // returns recordset sorted by fields provided
48: function SortByField(recordset, sortFields)
49: {
50: var sort = recordset.NewSortDescriptor();
51: for (var i = 0;i < sortFields.length;i++)
52: {
53: if (i >= (sort.MaxSORTFIELDS - 1))
54: {
55: break;
56: }
57: sort.sortFieldName(i) = sortFields[i];
58: }
59: recordset.Sort(sort);
60: return recordset;
61: }
Overview
The main advantage of this function is its agnosticism towards the fields it is to retrieve. It relies on the fact that objects in javascript inherently behave as associative arrays, e.g.
var myObject = new Object();
myObject["myKey"] = "some value";
For each record in the query's result set, an object is created with fieldsToReturn as keys, and the function's return type is simply an array of these objects. The fact that I am using these objects solely for their key/value behaviour leads me to refer to them as dictionaries. They are not dictionaries in the sense of specialized collections as with other languages outside of javascript.
Example
The following is a simplified method that I would never use in production code. It grabs search text from a box, creates a command query, then searches the Catalog. The result set will be sorted by Title, and will contain values from Title and Author fields. It then shows an alert message with the title from the first result in the set.
Note that field values are retrieved by using field names as keys on the objects in the results array.
1: function btnSearch_onClick()
2: {
3: var searchText = Form.boxes("boxSearchText").content;
4: var query = "find (Title ct {0}) or (Author ct {0})".replace("{0}", searchText);
5: var results = Search(query, "Catalog", "password", ["Title", "Author"], ["Title"]);
6:
7: var msg = "First result Title is '{0}'".replace("{0}", results[0]["Title"];
8: Application.message(msg);
9: }
Labels: db/textworks, javascript
Genie labels and query constraints
The default myLabels.config file for Inmagic Genie comes with a section that can be uncommented out to also include Item specific information, ie. for the Gaylord Label form <!-- Sample Configuration for Item Fields <ItemInfo> <Field Name="ItemVolume" Header="<br>"/> <Field Name="ItemIssue" Header="<br>"/> </ItemInfo> --> We ran across an interesting situation recently where the client has multiple offices and currently location information is just in the Catalog records. Only a couple of the offices will will be printing label sets and these offices will start populating Item records for new material. They have set the Query Filter on in their myGenie config file with a cookie to keep the last used setting, as they usually only want to see their own holdings. We were testing printing the labels and at first everything worked fine but we needed to move the labels over and adjust the fields shown, so we started making some changes to their myLabels config file. Then they started getting a completely blank screen when displaying the record labels from the InfoCart for printing. I could not replicate the problem and nor could Inmagic Support so we were temporarily baffled. The cause turned out to be the ItemInfo section that I had uncommented out to allow them to print additional item specific location information on the spine label. However we were testing printing with existing records in the Catalog (ie. with no Item records) and the client had started using using the Query filter. If using a Query filter and a label form with an ItemInfo section, then records must have an Item record with an ItemLocation field. If they do not, a blank page results. The solution for this client, for the moment at least, is to have two separate label forms and choose which one to use accordingly. One for printing labels for existing records that only have data in the catalog, and one for labels for new records that will also have item information. This is easy to do in just a few steps: - open the myLabels config file and copy the existing Gaylord label code and paste it just below the original
- rename Label Name="Gaylord" to Label Name="Gaylord for Items" in this copied section
- make sure to comment out the ItemInfo code on the original Gaylord label, and uncomment it on the new Gaylord for Items label
- Open myGenie config and add in a reference to the extra label to the <!-- Actions exposed to library staff in the Catalog InfoCart --> section, ie.
- <Action Name="Gaylord for Items" Display="Print Labels (Items)" Type="Label" />
- Reset the Genie application from the About Genie screen.
Changing Inmagic Genie dropdown lists to text boxes
Several edit screens in Genie use dropdown lists,for example, Payment Methods, Order Types, Currencies etc. The wording for these can be edited in the myGenie.config file, eg. <!-- PaymentMethods --> <PaymentMethods> <Method Default="true">Credit Card</Method> <Method>Check</Method> <Method>Money Order</Method> <Method>Gift Card</Method> <Method>Wire Transfer</Method> </PaymentMethods> However some clients may not be used to having this type of information validated, or their existing data to be converted into Genie may have a variety of values that cannot be easily batch modified to fit. In this case it is possible to change the edit screen and switch to a simple textbox and if required, add a link to browse a validation list instead. In myEditScreens.config file change this: <Field Name="OrdPaymentMethod" Type="DropDownList" CssClass="orders_edit_qtr_textinput" ShowBrowse="false" Required="false" Width="170"/> To: <Field Name="OrdPaymentMethod" Type="TextBox" CssClass="orders_edit_qtr_textinput" ShowBrowse="true" Required="false" Width="170"/> Dropdowns that should not be changed are CatSerFrequency (as this is used to set up arrival patterns in Serials using the calculation values specified in the myGenie config file); and the Suppliers dropdown in Orders (needed to show the linked Supplier name rather than the OrdSuppID). A good rule is to always make a backup before changing any config file setting.
|