TweetFollow Us on Twitter

Advanced Tables with AppleScript Studio

Volume Number: 23 (2007)
Issue Number: 07
Column Tag: Programming

Advanced Tables with AppleScript Studio

Learn how to support editable tables and drag-and-drops

By José R.C. Cruz

Introduction

In a previous article, Building a Table View Project in AppleScript Studio;, Benjamin Waldie showed how to use AppleScript Studio to display tabular data. He demonstrated how to use Interface Builder to prepare a table view. He then showed how to use the table's data source property to display the desired data.

Today, we will take the subject of table views a few steps further. First, we will look into the concept of editable tables. We will learn two types of editing modes and how to implement each type. Second, we will look into the concept of table drags and drops. We will learn how to support drag-and-drop operations within the table as well as outside of the table.

At the time of this writing, Apple does not provide any useful instructions on the subject of table editing, and table drag-and-drops. It is hoped that this article will serve as an effective substitute. Also, as a bonus, readers can download the Xcode project, MoreTables, from the following MacTech URL.

http://www.mactech.com/articles/mactech/Vol.21/21.12/TableViewProject/index.html

This project implements many of the concepts shown in this article. It requires version 2.4.1, or newer, of the Xcode environment.

Editing Tabular Data

Types of editing modes

Editable table views can support at least one of two possible modes: inline and panel editing. Each mode differs on the amount of data to be edited. Also, each mode can be had on the same table on a per column basis. Choose the type most suited for the data at hand.

In inline editing, the target data is edited directly on the table cell itself (Figure 1). Users start an edit session by clicking on the desired cell. They then end the session in one of two ways. First, they can press the TAB key, which move the edit focus to a different cell on the table. Second, they can press the ENTER key, which keeps the focus on the same cell. Either way, the table view will display any changes made to target data.


Figure 1. Editing table data inline

Inline editing is suitable if the data fits within the visual area of the table cell. It also requires fewer resources since it is already built into the table view. But there are cases where the data is larger than the size of its cell. There are also cases where the data to be edited is part of a larger set. For these cases, the most suitable form is panel editing.

In panel editing, the table displays the target data on a separate view like a dialog or a window (Figure 2). That view can either be modal or non-modal depending on the design goals. Alternatively, the table can also display the data on a separate set of fields residing on the same view as the table.


Figure 2. Editing data on a separate panel

Users start an edit session by double-clicking on the desired cell. They then end the session in one of two ways. First, they can click on a pushbutton widget to close the view. Second, they can click on the view's close widget, which again closes the view.

How the users close the view also determines if the changes to the target data are saved into the table's data source. For instance, simply closing the view discards any changes made to the data. But clicking on the Enter pushbutton updates the data source with those changes.

As mentioned earlier, panel editing is preferred if the target data is part of a larger set. One good example is a table of addresses. The street address can have one or more lines of text. Also, editing the address may also require editing the city or state entries as well.

Panel editing is also preferred if the target data does not fit the size of the table cell. Again, a good example is a table of addresses. If table space is limited, only a portion of the street address will be visible to the users at a time. Using inline editing, users will have to use the left/right arrow keys to see and edit the rest of the address text. This can be inconvenient if the length of the text is quite substantial.

Implementing inline editing

To implement inline editing, first make sure that the target table column is editable. The best way to check is to double-click on the column in Interface Builder and choose Show Inspector from the Tools menu. Then, from the Attributes panel, make sure that the Editable checkbox is set (Figure 3).


Figure 3. Setting the Editable attribute.

Next, double-click on the entire table view itself. Again, choose Show Inspector from the Tools menu, and then choose AppleScript from the panel's drop down list. Scroll down until the Table View checkbox comes into view. Click on the disclosure triangle to display a list of event handlers. Then click to select the cell value changed handler (Figure 4). Make sure to select the correct AppleScript source file before saving the changes made to the table view.


Figure 4. Selecting the cell value changed handler.

The cell value changed handler (shown below) takes four labeled parameters.

         on cell value changed aTbl row aRow table column aCol
         value aVal

The aTbl parameter is a reference to the table view calling the handler. The aRow parameter is the index of the table row being edited. The aCol parameter is a reference to the table column being edited. Finally, the aVal parameter is the edited cell value itself.

Listing 1 shows one way to use this handler. In this example, the handler validates the changes made to the file sizes displayed by the table view.

The handler first retrieves the selected table row. Next, it retrieves the contents of the cell ftyp from that table row. If that cell has the string value "Folder", the handler checks aVal to see if it is set to "n/a". If this is not the case, the handler then sets the value of the cell fsiz for that table row back to "n/a".

Now if the cell ftyp is not set to "Folder", the handler checks to see if aVal is set to a non-negative value. If this is not the case, the handler then sets the cell fsiz for that table row to zero.

Listing 1. Handling a change in a table cell value.

on cell value changed aTbl row aRow table column aCol value aVal
   local tRow, tTyp, tOrg
   
   -- check the current item type
   set tRow to selected data row of aTbl
   set tTyp to contents of the data cell "ftyp" of tRow
   
   -- validate the data change
   if (tTyp is equal to "Folder") then
      if (aVal is not equal to "n/a") then
         set the contents of the data cell "fsiz" of tRow to "n/a"
      end if -- (aVal is not equal to "n/a")
   else
      try
         set tOrg to aVal as integer
         if (tOrg is less than 0) then
            set the contents of the data cell "fsiz" of tRow to 0
         end if -- (tOrg is less than 0)
      on error
         set the contents of the data cell "fsiz" of tRow to gTemp
      end try
   end if -- (tTyp is equal to "Folder")
end cell value changed -- aTbl row aRow table column aCol value aVal

A problem with the cell value changed handler is that it does not preserve the previous cell value. Once the handler is invoked, the aVal parameter already contains the new value for that cell. One way to solve this is to add a selection changed handler using Interface Builder. Then implement the handler as shown in Listing 2.

This handler is invoked each time users selects a row on the table view. It retrieves the contents of the cell fsiz, and stores its value into the global variable gTemp. The cell value changed handler then set the cell fsiz with the contents of gTemp each time an error occurs.

Listing 2. Storing the previous cell value.

global gTemp
on selection changed aTbl
   local tRow
   
   -- retrieve the selected row
   set tRow to selected data row of aTbl
   
   -- buffer the data value
   set gTemp to the contents of the data cell "fsiz" of tRow
end selection changed -- aTbl

Since one of the handler's parameters is a reference to a table view, it is possible for more than one table views to call the same handler. If this is the case, make sure to identify which table is calling the handler at that time. The best way to do so is to retrieve the name property of the view.

   set tNom to name of aTbl as string

Make sure as well to recast the property value as a string before performing the ID tests. Failing to do so can result into some interesting errors.

Implementing panel editing

To implement panel editing, first make sure that the target table column is not editable. To do so, display the Inspector panel for that column, and clear the Enabled checkbox (Figure 5). Then choose AppleScript from the panel's drop down list, and click to select the double clicked handler for the entire table view.


Figure 5. Clearing the Editable attribute.

The double clicked handler (shown below) takes a single input argument. That argument, aTbl, is a reference to the calling table view.

      on double clicked aTbl

But other table views can call then above handler. Other UI controls that are not table views can also call that same handler. One way to identify which control made the call is to use an if...then construct.

   if (the class of aTbl is table view) then
      set tNom to the name of aTbl
      if (tNom is equal to "oTbl") then
         -- your code goes here
      end if -- (tNom is equal to "oTbl")
   end if -- (the class of aTbl is table view)

In the above example, the first if...then block retrieves and tests the class of aTbl. If aTbl is a table view, the second block retrieves and tests the name property. Then, if aTbl has the correct name of "oTbl", the code for that table view is executed.

Listing 3 shows one way to implement panel editing with the double clicked handler. First, the handler retrieves the row and column index of the double-clicked table cell. Next, it is retrieves the contents of that cell. It then displays the data on a modal dialog to the users for editing. Once users have edited the data, they click on the Enter pushbutton to commit the changes back to the table. The handler then updates the table cell with the updated value.

Listing 3. Handling a double-click event.

on double clicked aTbl
   local tRow, tCol, tDat
   local tMsg
      
   try
      -- initialize the following locals
      set tRow to clicked row of aTbl as string
      set tCol to clicked column of aTbl as integer
      
      -- check the selected data column
      if (tCol is equal to 1) then
         -- retrieve the original string
         set tRow to selected data row of aTbl
         set tDat to contents of data cell "fnom" of tRow
         
         -- prompt the user for a new string
         display dialog pNewName default answer tDat ¬ 
            buttons pBtnList default button "Enter"
         
         -- retrieve the new string data
         set tDat to result
         if (button returned of tDat is equal to "Enter") then
            set tDat to text returned of tDat
            
            -- update the data source
            set the contents of data cell "fnom" of tRow to tDat
         end if -- (button returned of tDat is equal to "Enter")
      end if -- (tCol = 1)
      
   on error tErr number tNum
      -- did the user cancelled the edit session?
      if not (tNum is equal to -128) then
         set tMsg to "[Error] MoreTables:double clicked:"
         set tMsg to tMsg & tErr & "(" & (tNum as string) & ")"
         display dialog tMsg buttons {"OK"}
      end if -- not(tNum is equal to -128)
   end try
end double clicked -- aTbl

Notice that the above example uses the display dialog command to serve the editing panel. This dialog generates the error signal -128 when users click on the Cancel pushbutton. To correctly process the signal, the handler uses a try...end try block. The on error sub-block traps any errors generated by the code. If it identifies the error as a -128, the sub-block quietly ignores the error signal. Otherwise, it displays a description of the error using a modal dialog.

Combining inline and panel editing

As stated earlier, a table view can support inline and panel editing modes on a per column basis. All that is required is to use the Show Inspector panel (Figure 5), and set or clear the Enabled checkbox for each table column.

For instance, the table view in the MoreTables project has the Editable checkbox cleared for the Name and Type column. Then it has the same checkbox set for the Size column. So, when users double-click on a cell in the Name column, the table view starts a panel editing session. But when users click on a cell in the Size column, the table view starts an inline editing session.

However, if users try to double-click on a cell in the Type column, the table view does not start a panel editing session. Though the double-click event is routed to the correct handler, it is rejected by the code since it occurred in the wrong column. Examine the first if...then construct in Listing 5 to see how this is done.

Dragging and Dropping Tabular Data

Getting started

Drag-and-drop actions are another way of managing tabular data. Users can select a row or column on the table view and drag them to a new location on the same table view. Users can also drag those same selections and drop them onto a different table view. And in some cases, users can drag those selections off the table's parent view. Doing so will cause the table view to delete those selections from its data source.

In fact, the table view itself already supports the dragging and dropping of table columns. All it requires is to set the Column Ordering checkbox on the Show Inspector panel (Figure 6) for the entire view. But the table view does not have the same level of support for dragging and dropping table rows. Enabling this feature will require some effort on our part.


Figure 6. Enabling column reordering.

The drag info object

The drag info object (Figure 13) is the main component of all drag-and-drop operations. It carries all the information that describes the operation. The object has a number of useful properties and methods. But the most interesting one is the pasteboard property.


Figure 7. Structure of the drag info object.

The pasteboard property (Figure 15) serves as the container for drag-and-drop data. It can carry a wide range of data, from integer values to lists or records. The property consists of two parts. The first part is a list of type signatures for each data it carries. The second part is the data itself.


Figure 8. Structure of the pasteboard object.

Now the drag-and-drop process sets most of the properties of the drag info object. In fact, the only property that should be set by code is the pasteboard. To demonstrate, assume the variable tClip as the pasteboard property. To store the string "Hello world" into the pasteboard, use the following code statements.

   set preferred type of tClip to "string"
   set content of tClip to "Hello World"
To retrieve the string from the pasteboard, use the following code statements.
   set preferred type of tClip to "string"
   get the content of tClip

But the drag info object only allows read-access to its pasteboard property. A separate handler is needed to store data into that property. This handler is described in the next subtopic.

Preparing the drag event

The table view must first be prepared to support drag-and-drop operations. To do so, select the view in Interface Builder and choose Show Inspector from the Tools menu. Then click to select the handlers shown in Figure 17.


Figure 9. Selecting the drag-and-drop handlers

Next, the table view needs to register the correct data types. To do so, use the Show Inspector panel to select the awake from nib handler for that view. Then update the handler with the code statements shown below.

on awake from nib aTbl
   tell aTbl to register drag types {"rows", "file names"}
end awake from nib -- aTbl

In the above example, the table view aTbl registered two data types: rows and file names. The first type refers to selected table rows, the second to selected files.

The prepare table drag handler (shown below) is executed at the start of a drag event. This handler initializes the drag info object. It takes three input parameters.

   on prepare table drag aTbl drag rows aRows pasteboard aClip

The parameter aTbl is the table view that started the drag event. The parameter aRows are the table rows selected by users. It contains not the row indices but the actual row data themselves. Lastly, the parameter aClip is the pasteboard object. It is through this parameter that the drag info object gets its pasteboard property set to the right data.

Listing 4 shows how to use this handler. Here, the handler sets the preferred data type for the pasteboard aClip to "rows". Next, it sets the contents of aClip to the selected table rows. The handler then returns a true to allow the drag event to continue. But if it needs to abort the event, perhaps due to an error, the handler should then return a false.

Listing 4. Starting a drag event

on prepare table drag aTbl drag rows aRows pasteboard aClip
   -- set the following properties
   set preferred type of aClip to "rows"
   set content of aClip to aRows
   
   -- return a true to continue the drag
   return (true)
end prepare table drag --  aTbl drag rows aRows pasteboard aClip

Preparing for a drop event

The prepare table drop handler (shown below) is executed at the start of a drop event. It also initializes the drag info object. The handler takes four input parameters.

   on prepare table drop aTbl drag info aDat row aRow drop operation anOp

The parameter aTbl is the table view accepting the dragged data. The parameter aDat is the drag info object initialized by the prepare table drag handler. The parameter aRow is the location where the dragged data will be dropped.

Finally, the parameter anOp is the drop mode. If this parameter is set to 0, the data will be placed on the selected row. But if it is set to 1, the default mode, the data will be placed above the selected row.

Error! Reference source not found. shows one way to use this handler. The handler first sets the default drag operation to no drag. Next, it retrieves the type of data stored in the drag info's pasteboard. If the data is a list of table rows, the handler returns a move drag operation. This means the data is placed at the new locale and removed from the old one.

On the other hand, if the data is a list of filenames, the handler returns a copy drag operation. This means the data is still placed at the new locale. But it is not removed from the old locale, if applicable.

Listing 5. Starting a drop event

on prepare table drop aTbl drag info aDat row aRow drop operation anOps
   local tTyp, tDrg   
   -- set the default operation
   set tDrg to no drag operation
   
   -- check the type of drop operation
   if (anOps is equal to 1) then
      -- set the type of drag operation to use
      set tTyp to types of pasteboard of aDat
      
      if (tTyp contains "rows") then
         set tDrg to move drag operation
      else if (tTyp contains "file names") then
         set tDrg to copy drag operation
      end if -- (tTyp contains "rows")
   end if -- (anOps is equal to 1)
   
   -- return the desired drag operation
   return (tDrg)
end prepare table drop -- aTbl drag info aDat drop operation anOps row aRow

Handling the drop event

The accept table drop handler (shown below) is executed after the drop event. Its purpose is to take the dragged data, and place it correctly on the table view. The handler takes four input parameters.

   on accept table drop aTbl drag info aDat drop operation anOps row aRow

The aTbl parameter is the table view accepting the dragged data. The aDat parameter is the drag info object. The anOps operation is the drop operation specified by the prepare table drop handler. Finally, the aRow parameter is the row where the dragged data will be placed.

Listing 6 shows one way to use this handler. In this example, the dragged data is a selection of table rows being moved to a new location.

The handler first disables aTbl's ability to update itself. It then counts the number of table rows present and sets the local tTmp to a null list. Next, the handler compares aRow against the number of table rows. It uses the results of the comparison to set the final drop location on the table view.

The handler then retrieves the pasteboard contents of aDat. It appends each data as a table row to the local tTmp. Once done, the handler then adds the contents of tTmp to the table view. Finally, it enables aTbl's update mode, thus refreshing the table's list of data.

Listing 6. Handling a selection of table rows

on accept table drop aTbl drag info aDat drop operation ¬
anOps row aRow
   local tDst, tSrc, tTmp
   local tCnt, tRow, tTyp, tRec
      
   -- initialize the following locals
   set tTyp to types of pasteboard of aDat
   set tSrc to data source of aTbl
   set tCnt to count of data rows in tSrc
   set tTmp to {}
   
   -- disable the table update event
   set update views of tSrc to false
   
   -- determine where to place the new row
   if (aRow > tCnt) then
      -- place the new row at the end of the list
      set tDst to missing value
   else
      -- place the row above the target row
      set tDst to the data row aRow of tSrc
   end if -- (aRow > tCnt)
   
   -- determine what type of data is being dragged
   if (tTyp contains "rows") then
      -- drag:type:table:row
      -- retrieve the following table data
      set the preferred type of the pasteboard of aDat to "rows"
      set tCnt to the contents of the pasteboard of aDat
      
      -- create a copy of the table data source contents
      repeat with tRow in tCnt
         copy data row tRow of tSrc to the end of tTmp
      end repeat -- with tRow in tCnt
      
      -- add the moved row entry
      repeat with tRow in tTmp
         -- determine if the moved entry should be inserted or appended
         if (tDst is equal to the missing value) then
            -- drag:row:operation:append
            move tRow to end of data rows of tSrc
         else
            -- drag:row:operation:insert
            move tRow to before tDst
         end if -- (tRow is equal to the missing value)
      end repeat -- with tRow in tTmp
      
   else if (tTyp contains "file names") then
      -- drag:type:file:name
      -- ...see Listing 12...
   end if -- (tTyp is equal to "rows")
   
   -- enable the table update event
   set update views of tSrc to true
   
   -- return a true to continue the drop
   return true
end accept table drop -- aTbl drag info aDat drop operation anOps row aRow

Listing 7 shows a different way of using the accept table drop handler. In this case, the dragged data consists of a selection of files from the Finder.

First, the handler follows the same steps to retrieve the dragged data from the drag info object aDat. It then retrieves the POSIX path to each file and converts it to a MacOS path format. Next, the handler calls the getInfo utility method. This method retrieves the Finder information for each file, and returns the results as a record. The handler then adds a new data row to the table view and updates that row with the Finder information. Finally, the handler enables aTbl's update mode, which refreshes its data display.

Listing 7. Handling a selection of files

on accept table drop aTbl drag info aDat drop operation anOps row aRow
   local tDst, tSrc, tTmp
   local tCnt, tRow, tTyp, tRec
   
   -- initialize the following locals
   set tTyp to types of pasteboard of aDat
   set tSrc to data source of aTbl
   set tCnt to count of data rows in tSrc
   set tTmp to {}
   
   -- disable the table update event
   set update views of tSrc to false
   
   -- determine where to place the new row
   if (aRow > tCnt) then
      -- place the new row at the end of the list
      set tDst to missing value
   else
      -- place the row above the target row
      set tDst to the data row aRow of tSrc
   end if -- (aRow > tCnt)
   
   -- determine what type of data is being dragged
   if (tTyp contains "rows") then
      -- drag:type:table:row
      -- see Listing 10...
   else if (tTyp contains "file names") then
      -- drag:type:file:name
      -- retrieve the list of selected files
      set the preferred type of the pasteboard of aDat to "file names"
      set tCnt to the content of the pasteboard of aDat
      
      if (the (count of tCnt) is greater than 0) then
         repeat with tRow in tCnt
            -- retrieve the info record
            set tRec to POSIX file tRow as text
            set tRec to getInfo for tRec
            
            if not (tRec is null) then
               -- determine if the new entry should be inserted or appended
               if (tDst is equal to the missing value) then
                  -- drag:file:operation:append
                  set tTmp to make new data row at end of data rows of tSrc
               else
                  -- drag:file:operation:insert
                  set tTmp to make new data row at before tDst
               end if -- (tRow is equal to the missing value)
               
               
               -- update the table entry
               set the contents of the data cell "fnom" ¬
                     of tTmp to the fnom of tRec
               set the contents of the data cell "ftyp" ¬
                     of tTmp to the ftyp of tRec
               set the contents of the data cell "fsiz" ¬
                     of tTmp to the fsiz of tRec
            end if -- not (tRec is null) 
         end repeat -- with tRow in tCnt
      end if -- (the count of tCnt is greater than 0)
   end if -- (tTyp is equal to "rows")
   
   -- enable the table update event
   set update views of tSrc to true
   
   -- return a true to continue the drop
   return true
end accept table drop -- aTbl drag info aDat drop operation anOps row aRow

Concluding Remarks

Table views are an integral part of many AppleScript applications. They allow users to view their data in a structured tabular form. They also allow users to edit specific data items or move them to a new locale.

AppleScript Studio helps in making an editable table view easy to support. Users can either edit the data directly on the table view, or on a separate panel view. Drag and drops on table views are also easily done with AppleScript Studio. User can use drag-and-drops to rearrange table columns or rows. Users can also use them to add data from a separate application, such as the Finder, to a table view.

Thanks to AppleScript Studio, table views can be an effective and flexible way of presenting data to users.

Bibliography and References

Apple Computers. "Data View Suite:Table View". AppleScript Studio Terminology Reference. Copyright 2006. Apple Computers, Inc.

Apple Computers. "Drag and Drop Suite:Drag Info Class". AppleScript Studio Terminology Reference. Copyright 2006. Apple Computers, Inc.

Apple Computers. AppleScript Studio 1.4 Release Notes. Copyright 2005. Apple Computers, Inc.

Benjamin S. Waldie. "Building a Table View Project in AppleScript Studio". MacTech Magazine. Volume 21, Issue 12. Online:

http://www.mactech.com/articles/mactech/Vol.21/21.12/
TableViewProject/index.html


JC is a freelance engineering writer currently residing in North Vancouver, British Columbia. He divides his time between writing technical articles, and teaching origami at his local district's public library. He can be reached at anarakisware@icmail.com.

 
AAPL
$119.00
Apple Inc.
+1.40
MSFT
$47.75
Microsoft Corpora
+0.28
GOOG
$540.37
Google Inc.
-0.71

MacTech Search:
Community Search:

Software Updates via MacUpdate

HoudahSpot 3.9.6 - Advanced file search...
HoudahSpot is a powerful file search tool built upon MacOS X Spotlight. Spotlight unleashed Create detailed queries to locate the exact file you need Narrow down searches. Zero in on files Save... Read more
RapidWeaver 6.0.3 - Create template-base...
RapidWeaver is a next-generation Web design application to help you easily create professional-looking Web sites in minutes. No knowledge of complex code is required, RapidWeaver will take care of... Read more
iPhoto Library Manager 4.1.10 - Manage m...
iPhoto Library Manager lets you organize your photos into multiple iPhoto libraries. Separate your high school and college photos from your latest summer vacation pictures. Or keep some photo... Read more
iExplorer 3.5.1.9 - View and transfer al...
iExplorer is an iPhone browser for Mac lets you view the files on your iOS device. By using a drag and drop interface, you can quickly copy files and folders between your Mac and your iPhone or... Read more
MacUpdate Desktop 6.0.3 - Discover and i...
MacUpdate Desktop 6 brings seamless 1-click installs and version updates to your Mac. With a free MacUpdate account and MacUpdate Desktop 6, Mac users can now install almost any Mac app on macupdate.... Read more
SteerMouse 4.2.2 - Powerful third-party...
SteerMouse is an advanced driver for USB and Bluetooth mice. It also supports Apple Mighty Mouse very well. SteerMouse can assign various functions to buttons that Apple's software does not allow,... Read more
iMazing 1.1 - Complete iOS device manage...
iMazing (was DiskAid) is the ultimate iOS device manager with capabilities far beyond what iTunes offers. With iMazing and your iOS device (iPhone, iPad, or iPod), you can: Copy music to and from... Read more
PopChar X 7.0 - Floating window shows av...
PopChar X helps you get the most out of your font collection. With its crystal-clear interface, PopChar X provides a frustration-free way to access any font's special characters. Expanded... Read more
Carbon Copy Cloner 4.0.3 - Easy-to-use b...
Carbon Copy Cloner backups are better than ordinary backups. Suppose the unthinkable happens while you're under deadline to finish a project: your Mac is unresponsive and all you hear is an ominous,... Read more
ForeverSave 2.1.3 - Universal auto-save...
ForeverSave auto-saves all documents you're working on while simultaneously doing backup versioning in the background. Lost data can be quickly restored at any time. Losing data, caused by... Read more

Latest Forum Discussions

See All

Make Way for Fat Chicken, from the Maker...
Make Way for Fat Chicken, from the Makers of Scrap Squad Posted by Jessica Fisher on November 26th, 2014 [ permalink ] Relevant Games has announced they will be releasing their reverse tower defense game, | Read more »
Tripnary Review
Tripnary Review By Jennifer Allen on November 26th, 2014 Our Rating: :: TRAVEL BUCKET LISTiPhone App - Designed for the iPhone, compatible with the iPad Want to create a travel bucket list? Tripnary is a fun way to do exactly that... | Read more »
Ossian Studios’ RPG, The Shadow Sun, is...
Ossian Studios’ RPG, The Shadow Sun, is Now Available for $4.99 Posted by Jessica Fisher on November 26th, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Mmmm, Tasty – Having the Angry Birds for...
The very first Angry Birds debuted on iOS back in 2009. When you sit back and tally up the number of Angry Birds games out there and the impact they’ve had on pop culture as a whole, you just need to ask yourself: “How would the birds taste... | Read more »
Rescue Quest Review
Rescue Quest Review By Jennifer Allen on November 26th, 2014 Our Rating: :: PATH BASED MATCH-3Universal App - Designed for iPhone and iPad Guide a wizard to safety by matching gems. Rescue Quest might not be an entirely original... | Read more »
You Can Play the Final Chapter of Lone W...
You Can Play the Final Chapter of Lone Wolf: Dawn Over V’taag Right Now Posted by Jessica Fisher on November 26th, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Swords of Anima (Games)
Swords of Anima 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: A new tactical turn-based RPG experience. Command the Savior Rex Squad in an epic journey of courage and deception. Can you... | Read more »
Audio Defence: Zombie Arena
Audio Defence: Zombie Arena By Lee Hamlet on November 26th, 2014 Our Rating: :: DRAGS ITS FEETUniversal App - Designed for iPhone and iPad From the makers of Papa Sangre comes a defense game that forces players to listen carefully... | Read more »
Tales from the Borderland​s Will be Comi...
Tales from the Borderland​s Will be Coming to iOS by the End of the Year Posted by Jessica Fisher on November 26th, 2014 [ permalink ] Telltale Games has announced | Read more »
Sunburn! Review
Sunburn! Review By Campbell Bird on November 26th, 2014 Our Rating: :: DON'T DIE ALONEUniversal App - Designed for iPhone and iPad Platform through the depths of space to make sure your entire crew dies together in this satisfying... | Read more »

Price Scanner via MacPrices.net

2014 1.4GHz Mac mini on sale for $449, save $...
 B&H Photo has the new 1.4GHz Mac mini on sale for $449.99 including free shipping plus NY tax only. Their price is $50 off MSRP, and it’s the lowest price available for this new model. Adorama... Read more
Early Black Friday pricing on 27-inch 5K iMac...
 B&H Photo continues to offer Black Friday sale prices on the 27″ 3.5GHz 5K iMac, in stock today and on sale for $2299 including free shipping plus NY sales tax only. Their price is $200 off MSRP... Read more
Early Black Friday sale prices on iPad Air 2,...
 MacMall is discounting iPad Air 2s by up to $75 off MSRP as part of their Black Friday sale. Shipping is free: - 16GB iPad Air WiFi: $459 $40 off - 64GB iPad Air WiFi: $559 $40 off - 128GB iPad Air... Read more
Early Black Friday MacBook Air sale prices, $...
 MacMall has posted early Black Friday MacBook Air sale prices. Save $101 on all models for a limited time: - 11″ 1.4GHz/128GB MacBook Air: $798 - 11″ 1.4GHz/256GB MacBook Air: $998 - 13″ 1.4GHz/... Read more
Why iPhone 6 Tablet/Laptop Cannibalization Is...
247wallst.com blogger Douglas A. McIntyre noted last week that according to research posted on the Applovin blog site the iPhone 6 is outselling the iPhone 6 Plus by a wide margin . Hardly a surprise... Read more
Worldwide Tablet Growth Expected to Slow to 7...
The global tablet market is expected to record massive deceleration in 2014 with year-over-year growth slowing to 7.2%, down from 52.5% in 2013, according to a new forecast from International Data... Read more
Touchscreen Glove Company Announces New Produ...
Surrey, United Kingdom based TouchAbility specializes in design and manufacture of a wide variety of products compatible with touchscreen devices including smartphones, tablets and computers. Their... Read more
OtterBox Alpha Glass Screen Protectors for iP...
To complement the bigger, sharper displays on the latest Apple devices, OtterBox has introduced Alpha Glass screen protectors to the iPhone 6 and iPhone 6 Plus. The fortified glass screen protectors... Read more
Early Black Friday Mac Pro sale, 6-Core 3.5GH...
 B&H Photo has the 6-Core 3.5GHz Mac Pro on sale today for $3499 including free shipping plus NY sales tax. Their price is $500 off MSRP, and it’s the lowest price available for this model from... Read more
Early Black Friday sale price: 15-inch 2.2GHz...
 B&H Photo has the 2014 15″ 2.2GHz Retina MacBook Pro on sale today for $1699.99. Shipping is free, and B&H charges NY sales tax only. Their price is $300 off MSRP, equalling Best Buy’s price... Read more

Jobs Board

*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
Senior Event Manager, *Apple* Retail Market...
…This senior level position is responsible for leading and imagining the Apple Retail Team's global event strategy. Delivering an overarching brand story; in-store, Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.