Compare commits

...
202 Commits
Author SHA1 Message Date
Ross Boucher 2453e403ef Make nil a completely valid object in a CPArray.
Closes #630.
2010-04-29 12:04:44 -07:00
Tom Robinson 22668b6b43 Use 127.0.0.1 instead of localhost in case localhost != loopback. 2010-04-28 02:23:07 -07:00
Francisco Ryan Tolmasky I f9c786f3eb Merge branch 'master' of git@github.com:280north/cappuccino 2010-04-28 02:06:48 -07:00
Francisco Ryan Tolmasky I 0f2ee1966e Only create main menu in code if no cib is loaded.
Reviewed by me.
2010-04-28 02:06:01 -07:00
Tom Robinson 62e520a6a5 Some more NativeHost building enhancements. 2010-04-28 01:45:04 -07:00
Ross Boucher 2f9cf6bc9b Add action buttons to button bars. 2010-04-27 22:11:17 -07:00
Ross Boucher e03cfe8287 Missing printResults() in Jakefile for ThemeDescriptor template
Conflicts:

	Tools/capp/Resources/Templates/ThemeDescriptor/Jakefile
2010-04-27 13:16:17 -07:00
Tom Robinson 0d97dfacd6 give zero sized borderless bridge windows a default size if we're not in the browser so they show up in NativeHost. 2010-04-27 12:56:24 -07:00
Francisco Ryan Tolmasky I 6ac0191451 Show main menu in cibless apps.
Remaining: Make a main menu with quit for desktop version, without for web version.

Reviewed by me.
2010-04-27 11:33:00 -07:00
Ross Boucher f5b360f66c Move a lot of common initialization code into the _init method. 2010-04-27 10:49:50 -07:00
Ross Boucher 1d5c21fa72 If we decode a scroll view without a header clip view, create one. 2010-04-27 10:49:50 -07:00
Francisco Ryan Tolmasky I d3e1c39e35 Merge branch 'master' of git@github.com:280north/cappuccino 2010-04-27 01:05:14 -07:00
Francisco Ryan Tolmasky I ae47509aa7 Add convinience methods for dealing with multiple objects and controls.
Reviewed by me.
2010-04-27 01:04:46 -07:00
Tom Robinson 5ff798306f Copy CFBundleIconFile in NativeHost building. 2010-04-26 23:19:05 -07:00
Ross Boucher c41ffc14c7 checkboxes and radio buttons shouldn't be bold. 2010-04-26 21:36:45 -07:00
Ross Boucher 1e7a3bef0d Fix a potential infinite loop in CPBrowser. 2010-04-26 12:56:52 -07:00
Nicholas Small 243f564396 Fix typo in new autoscroll stuff. 2010-04-26 11:11:42 -04:00
Tom Robinson dae1e44a8f Merge Cappuccino Info.plist into NativeHost's Info.plist. 2010-04-25 23:22:16 -07:00
Tom Robinson 67bcc29baf NativeHost. 2010-04-25 22:33:31 -07:00
Ross Boucher cdb089778c autoscroll when drag selecting. 2010-04-25 15:43:23 -07:00
Ross Boucher 5e43a02ffa Fix some faulty validation logic. 2010-04-25 15:43:22 -07:00
Ross Boucher 7395d13c3e Typo in CPJSONPConnection. 2010-04-25 15:43:22 -07:00
Tom Robinson f6000468db Missing printResults function in ThemeDescriptor Jakefile. 2010-04-25 14:58:27 -07:00
Stephen IerodiaconouandRoss Boucher 09e52d82bf Code style clean up, as per style guide 2010-04-24 15:06:12 -07:00
Ross Boucher 0e98f44a93 Fix for IE transparent backgrounds not being resized.
Closes #604.
2010-04-24 14:51:10 -07:00
Ross Boucher 6d595c1344 Collection view should tile itself to be the height of its superview if inside a clip view. 2010-04-24 11:10:58 -07:00
Ross Boucher 5f6f997095 Only attempt to scroll views, not windows. 2010-04-24 11:10:36 -07:00
Ross Boucher 6662fabcb8 Tests for the bug exposed in the previous cparray commit. 2010-04-23 16:43:22 -07:00
Stephen IerodiaconouandRoss Boucher 7577cf8645 Fix error in initWithArray:copyItems: 2010-04-23 16:42:55 -07:00
Ross Boucher 8340791824 Don't let color wells work if they are disabled.
Closes #626.
2010-04-23 16:34:47 -07:00
Ross Boucher 14f0d16fae Update scrollWheel: to propagate unused scroll deltas to parent scroll views. 2010-04-23 16:16:46 -07:00
cacaodevandRoss Boucher e1ad4a2fce CPTableView: remove custom scrolling now that it's handled in the CPDragServer + CPClipView 2010-04-23 14:31:25 -07:00
Ross Boucher f67580e2b2 Add support for automatically scrolling during drag and drop operations. 2010-04-23 14:00:47 -07:00
Ross Boucher 31f408478a Update to scrolling behavior. 2010-04-23 12:03:25 -07:00
Randall Luecke ab6d5d6a90 Added connectionDidFinsihLoading delegate to CPJSONPConnection 2010-04-23 01:29:46 -04:00
Ross Boucher 6b3600d67b Slight update to button bar theme values. 2010-04-22 11:50:06 -07:00
Francisco Ryan Tolmasky I bf8ff44b84 Merge branch 'master' of git@github.com:280north/cappuccino 2010-04-21 22:56:21 -07:00
Francisco Ryan Tolmasky I 72a3888062 Add ObjectiveJ global to CommonJS so that references to it aren't broken in Cappuccino.
Reviewed by me.
2010-04-21 22:55:46 -07:00
Ross Boucher 4479233bea Return nil fonts if they are the aristo default, so that the theme default is used instead of the arist default (for custom themes). 2010-04-21 20:57:53 -07:00
Alexander LjungbergandRoss Boucher a7021e6b66 Fixed a parameter type typo. 2010-04-21 15:48:47 -07:00
Alexander LjungbergandRoss Boucher 0f5dd9d469 [CPSet description] with unit test. 2010-04-21 15:48:39 -07:00
Alexander LjungbergandRoss Boucher 388f008189 Fixed: CPCollectionView frameForItemsAtIndexes used the deprecated method rectForItemAtIndex causing warnings. 2010-04-21 15:47:48 -07:00
Alexander LjungbergandRoss Boucher 639a32ea7e CPWindow alpha value support. 2010-04-21 15:47:25 -07:00
Alexander LjungbergandRoss Boucher 5838f1aec8 Implemented CPCoding for CPNull. 2010-04-21 15:36:29 -07:00
Ross Boucher d2399b6157 Add support for not clipping to bounds in cpview. 2010-04-21 14:15:05 -07:00
Ross Boucher b1282b4362 Fix an infinite recursion bug in CPBrowser, and add support for looking up a column/row by location. 2010-04-21 12:58:31 -07:00
Francisco Ryan Tolmasky I bbd402fcff Partial fix for HTML5 drag and drop with collection views.
Reviewed by me.
2010-04-20 23:51:18 -07:00
Tom Robinson a18fb1b686 Add manifest generation options to press and flatten, since manifests need to be updated after each is run. 2010-04-12 13:47:38 -07:00
Francisco Ryan Tolmasky I 6a72e1b6ff Merge branch 'master' of git@github.com:280north/cappuccino 2010-04-12 12:22:25 -07:00
Francisco Ryan Tolmasky I b3141f1a62 Add CPApplicationWillTerminateNotification.
Reviewed by me.
2010-04-12 12:21:45 -07:00
Randall Luecke aea8f1f0dc Added proper background color to the tableview. 2010-04-12 02:09:46 -04:00
Francisco Ryan Tolmasky I 8aecf880e5 Merge branch 'master' of git@github.com:280north/cappuccino 2010-04-09 22:22:55 -07:00
Francisco Ryan Tolmasky I 7d5ce51910 Upped the version number to 0.8.1.
Reviewed by me.
2010-04-09 22:22:35 -07:00
Ross Boucher cfc8ccafce Remove typo. 2010-04-09 14:56:54 -07:00
Kelly McDonaldandRoss Boucher e11dfc2875 CPDragServer was checking the selector on the delegate of draggedImage:endAt:operation: but calling draggedImage:endedAt:operation:. I changed so that it uses endedAt to better reflect what is done in cocoa 2010-04-09 14:56:43 -07:00
Ross Boucher b3ef31ad05 Fixed: [CPArray isEqualToArray:nil] threw an exception instead of returning NO.
Conflicts:

	Foundation/CPArray.j
	Tests/Foundation/CPArrayTest.j
2010-04-09 14:51:46 -07:00
Ross Boucher 70410d6311 Fix the buttonNumber method of CPEvent.
Closes #70.
2010-04-09 14:38:08 -07:00
Ross Boucher 4cc7dec35b Throw syntax error for # followed by anything other than pragma. 2010-04-09 14:34:02 -07:00
Ross Boucher 47ecd40c4f Made the pre-processor capable of recognizing and ignoring Xcode's '#pragma mark' mark-ups
Conflicts:

	Objective-J/Preprocessor.js
2010-04-09 14:26:29 -07:00
saikatandRoss Boucher 489f2bcfa0 Reverting 1c9763eaa8 - autoresizing the contentview breaks sizetofit 2010-04-09 14:18:20 -07:00
Ross Boucher 16590e0603 Closes #590.
Closes #594.
2010-04-09 14:17:11 -07:00
Paul BaumgartandRoss Boucher f50cda9abc change CPAccordionItem to CPAccordionViewItem in CPAccordionView
selector types. Closes gh-596.
2010-04-09 13:58:05 -07:00
Francisco Ryan Tolmasky I 7543968203 Merge branch 'master' of git@github.com:280north/cappuccino 2010-04-08 23:59:00 -07:00
Francisco Ryan Tolmasky I 54685b1f36 One additional fix for IE not loading in certain occasions.
Reviewed by me.
2010-04-08 23:58:47 -07:00
Francisco Ryan Tolmasky I abdc601d92 Fix for IE not loading bug.
Reviewed by me.
2010-04-08 23:58:31 -07:00
Tom Robinson 9f50f08065 Add automated HTML5 cache manifest generation. Disabled by default. 2010-04-07 22:46:23 -07:00
Tom Robinson aabb1fa6f2 Move CPCursor test out of Resources. 2010-04-07 16:03:42 -07:00
Tom Robinson 4b770714bd Update starter task to include version of bootstrap which installs Cappuccino packages. 2010-04-06 12:54:23 -07:00
Ross Boucher 8175dbca53 Updates to the Jakefile and capp gen. 2010-04-06 12:26:35 -07:00
Tom Robinson c91332afb4 Add the other MobileSafari meta/link tags. 2010-04-05 20:09:04 -07:00
Tom Robinson 08fb1b33b4 Add viewport tag to templates. Fixes drawing errors on MobileSafari. 2010-04-05 18:14:04 -07:00
Ross Boucher cd6b6afc65 Don't convert text fields to bold default system font. 2010-04-05 10:38:20 -07:00
Tom Robinson cd4a70ea78 Add hook to CPApplicationMain to notify parent frame (if app is in a child frame of same origin) 2010-04-04 18:39:47 -07:00
Tom Robinson eb24ba9835 Re-enable flatten compression by default. 2010-04-01 23:48:48 -07:00
Tom Robinson 468869821f Add charset attributes to all external script tags, including flatten. Fixes unicode bugs in flatten. 2010-04-01 23:41:08 -07:00
Tom Robinson 0c85dbf9b0 Add some charset options, and disable compressor by default. 2010-04-01 23:15:47 -07:00
Tom Robinson 2db47e413e Add comrpessor support to flatten. 2010-04-01 12:01:16 -07:00
Tom Robinson b8fddc98bf Fixes flatten, splitting mode. Also escape dollar signs before replacing. 2010-04-01 11:12:08 -07:00
Tom Robinson 467f798147 Fixes flatten, non-splitting mode. 2010-04-01 11:11:58 -07:00
Ross Boucher 374f3d13f1 Convert default IB fonts to default Cappuccino fonts 2010-03-31 21:31:09 -07:00
Tom Robinson b0a35a183f Only enable debug logger in browsers, not command line utilities. 2010-03-31 17:28:46 -07:00
Francisco Ryan Tolmasky I 74e349ed33 Merge branch 'master' of git@github.com:280north/cappuccino 2010-03-31 17:05:32 -07:00
Francisco Ryan Tolmasky I c57aa2ac5e Fix for menu bar being broken if displayed after a window is ordered front in IE.
Reviewed by me.
2010-03-31 17:04:35 -07:00
Ross Boucher acac29dcda Merge branch 'master' of github.com:280north/cappuccino 2010-03-31 16:37:16 -07:00
Paul BaumgartandTom Robinson 675969af6d Add some dependency checking to bootstrap.sh: make sure correct JVM is
being used and ensure other dependencies are installed and on the $PATH.
2010-03-31 15:00:09 -07:00
Tom Robinson ce32177e1d Use "CommonJS" task as the dependency for "test" task for now. 2010-03-31 13:53:09 -07:00
Randall Luecke e956d61a08 Fixed bug introduced by renaming of private class. 2010-03-31 16:41:13 -04:00
Alexander LjungbergandRoss Boucher 068cdb9817 CPNull valueForKey:X returns CPNull for any value of X, paralleling [nil valueForKey:X]. Verified against Cocoa through empirical testing. 2010-03-31 13:17:42 -07:00
Randall Luecke 0ec7d4cd9a Made drag feedback view in the tableview more correct, fixed encoding issues.
Conflicts:

	AppKit/CPTableView.j
2010-03-31 16:11:10 -04:00
Nicholas Small 6a8126337c Added right click responder methods and context menu support. 2010-03-31 15:56:18 -04:00
Ross Boucher 12db25a829 Fix for a potential error in IE when setting a width to a negative value. 2010-03-31 12:11:21 -07:00
Ross Boucher a347bfb8b1 Sprite images recursively. 2010-03-31 11:10:17 -07:00
Francisco Ryan Tolmasky I 9255af210c Fix for loading Cappuccino apps locally on Windows.
Reviewed by me.
2010-03-30 16:28:42 -07:00
Tom Robinson 0b3264a99d Enable default logger in debug frameworks. Add configurable options to index-debug.html. 2010-03-30 14:12:59 -07:00
Ross Boucher 2bf16da441 These menu key equivs were incorrect. 2010-03-30 11:10:36 -07:00
Ross Boucher 5c4d890100 Fix a nil variable error that caused problems in Firefox 2. 2010-03-30 10:52:48 -07:00
Francisco Ryan Tolmasky I 99282026fa One more fix for image spriting.
Reviewed by me.
2010-03-30 00:45:11 -07:00
Francisco Ryan Tolmasky I 8f4b2a7cfd Fail more gracefully when main cib is not found.
Reviewed by me.
2010-03-29 23:20:31 -07:00
Randall Luecke c78feda3d6 Fixed nib2cib bug with cornerview where resources were not loaded from the correct location. 2010-03-30 01:45:36 -04:00
Francisco Ryan Tolmasky I a279d62c88 Merge branch 'master' of git@github.com:280north/cappuccino 2010-03-28 11:40:38 -07:00
Francisco Ryan Tolmasky I 8d1f787179 Fix for a few minor regressions:
1. Split out flatten specific code to get file size back down.
2. Fix for non-native string URL not working with the URLCache (typeof x !=== "string")
3. Fix for slight IE performance regression.

Reviewed by me.
2010-03-28 11:39:36 -07:00
Ross Boucher 7ab41cf195 If there is no key window or no main window make the first opened window those things. 2010-03-28 09:03:33 -07:00
Ross Boucher df728b7a21 Support terminating method signatures with ;. Closes #416. 2010-03-28 08:51:35 -07:00
Francisco Ryan Tolmasky I cba26faf9b Fix for HelloWorld not flattening correctly.
Reviewed by me.
2010-03-27 19:31:16 -07:00
Francisco Ryan Tolmasky I c4c1cffc01 Merge branch 'master' of git@github.com:280north/cappuccino 2010-03-27 18:53:03 -07:00
Francisco Ryan Tolmasky I 321706e5c6 Fix for user code errors during load not being reported (Cappuccino failing silently).
Reviewed by me.
2010-03-27 18:52:19 -07:00
Ross Boucher 47bf4c0baa Finish split view cursor implementation.
Closes #494.
2010-03-27 15:47:10 -07:00
Alexander LjungbergandRoss Boucher fc628c1221 CPSplitView resize cursors now require [[self window] setAcceptsMouseMovedEvents:YES]; to be called manually pending a CPTrackingArea based implementation. 2010-03-27 15:47:10 -07:00
Ross Boucher eb6a03704a Proper resize cursors for CPSplitView. Also enables resize cursor for additionalEffectiveRectOfDividerAtIndex areas.
Conflicts:

	AppKit/CPSplitView.j
2010-03-27 15:47:10 -07:00
Francisco Ryan Tolmasky I 7b855e6c68 Merge branch 'master' of git@github.com:280north/cappuccino 2010-03-27 13:56:35 -07:00
Francisco Ryan Tolmasky I fe0818c612 Don't generate image files if there aren't any.
Reviewed by me.
2010-03-27 13:54:07 -07:00
Ross Boucher 74dabcae8a Update the CPDictionary test suite. 2010-03-27 13:52:44 -07:00
Emmanuel MaillardandRoss Boucher daf7870bab - add containsKey: method 2010-03-27 13:41:32 -07:00
Ross Boucher 64da7f8775 define out DOM code from _CPImageAndTextView.
Closes #562.
2010-03-27 13:37:13 -07:00
aburkhalterandRoss Boucher 6cfa11a94d Initial boilerplate and file for putting the untested (at least not directly) CPView.j under test. Initial test to confirm we can actually create the object and a test demonstrating issue #562. 2010-03-27 13:33:04 -07:00
Ross Boucher db3c6c1463 A few minor updates to the pathExtension patch. 2010-03-27 13:25:44 -07:00
Emmanuel MaillardandRoss Boucher 65a669a9a1 - correct pathExtension and stringByDeletingPathExtension 2010-03-27 13:23:55 -07:00
Emmanuel MaillardandRoss Boucher 33f56bb203 - implement stringByDeletingPathExtension 2010-03-27 13:23:32 -07:00
Emmanuel MaillardandRoss Boucher 1ff873e170 - add tests for pathExtension and stringByDeletingPathExtension 2010-03-27 13:22:36 -07:00
Ross Boucher b0e0156880 Fix support for initial first responder. 2010-03-27 13:08:47 -07:00
Ross Boucher 896f36dffb A better (but not perfect) way to handle the browser's first responder state. 2010-03-27 11:27:44 -07:00
Ross Boucher eae975652e Add default line break mode. 2010-03-26 16:59:02 -07:00
Ross Boucher e46d1a793c autoresize the cpbrowser test browser. 2010-03-26 16:41:33 -07:00
Ross Boucher 1c9763eaa8 CPBox should autoresize its content view. 2010-03-26 16:41:23 -07:00
Ross Boucher 686370ac0e Add convenience accessors for the browser's selected items. 2010-03-26 15:52:53 -07:00
Ross Boucher e4ca057e4c Fix import directives. 2010-03-26 14:27:46 -07:00
Ross Boucher ac5a0e3dfc Add CPBrowser manual test app. 2010-03-26 14:00:51 -07:00
Ross Boucher a580b522e3 Add initial CPBrowser implementation. 2010-03-26 14:00:30 -07:00
Ross Boucher af53c271c7 Fix a few naming convention violations.
Make dragView.... use the columns its passed, rather than computing from scratch.
2010-03-26 13:59:41 -07:00
Ross Boucher 4476dad395 Whitespace fix. 2010-03-26 10:36:08 -07:00
Emmanuel MaillardandRoss Boucher b7b2dd2915 - CGPathAddQuadCurveToPoint fix for an unknown variable when using a transformation matrix 2010-03-26 10:36:08 -07:00
Francisco Ryan Tolmasky I efb6a0f5c6 Merge branch 'master' of git@github.com:280north/cappuccino 2010-03-26 01:31:39 -07:00
Francisco Ryan Tolmasky I deba653661 Fix for unrecognized selector in CPURL's initWithCoder:.
Reviewed by me.
2010-03-26 01:30:50 -07:00
Ross Boucher eb831dc4ac Typo. Closes #572. 2010-03-25 10:40:37 -07:00
Scott KyleandRoss Boucher b0d355a71c Some somewhat minor style fixes 2010-03-24 19:46:38 -07:00
Ross Boucher af11b4e423 Fix for pattern images not being displayed correctly under the new background color system 2010-03-23 14:32:24 -07:00
Ross Boucher 0cf86318ce Make semi-transparent background colors work in browsers that don't support RGBA.
Closes #569.
2010-03-23 14:26:32 -07:00
Ross Boucher 4175b762c3 Disable new syntax check while we work out the build issue some people are having. 2010-03-23 13:29:55 -07:00
Ross Boucher 3ddcb5f118 Remove duplicate method declaration. 2010-03-23 13:29:43 -07:00
Ross Boucher d0ad865976 Add the with{} back in for Class methods, instead take the disallowed list from objj_class. 2010-03-23 11:21:59 -07:00
Ross Boucher 7013b34897 Add a few additional syntax checks.
Throw an error if a method uses a parameter name that is also an ivar name.
Stop using with{} block for class methods.
2010-03-23 11:21:59 -07:00
Ross Boucher bbbae36e6a Missing - on a method. 2010-03-23 11:21:59 -07:00
Francisco Ryan Tolmasky I 34c3a9530b Fixed a bug where CPKeyedUnarchiver would incorrectly unarchive 0 as null.
Reviewed by me.
2010-03-23 02:06:44 -07:00
Francisco Ryan Tolmasky I 78cb522874 Temporarily revert "Make semi-transparent background colors work in browsers that don't support RGBA."
This fix was making lots of resources not show up.

This reverts commit f8c13f1e30.
2010-03-23 01:22:59 -07:00
Francisco Ryan Tolmasky I e8a0d2acf6 Merge branch 'master' of git@github.com:280north/cappuccino 2010-03-23 00:04:59 -07:00
Ross Boucher f8c13f1e30 Make semi-transparent background colors work in browsers that don't support RGBA.
Closes #569.
2010-03-22 19:00:49 -07:00
Randall Luecke 4b272a76fd Merge branch 'master' of git://github.com/280north/cappuccino 2010-03-22 19:27:13 -04:00
Randall Luecke f73d96af08 Fixed black background of dragview in Opera and IE. 2010-03-22 19:24:32 -04:00
Scott KyleandRoss Boucher bb0835e2f3 CPImageView should send action on drop, as in Cocoa 2010-03-22 16:15:02 -07:00
Ross Boucher ef4c108b9e Date test wasn't accurately accounting for daylight savings time. 2010-03-22 15:08:29 -07:00
Ross Boucher 319b9ed00f Use === not ==. 2010-03-22 14:53:49 -07:00
Alan RogersandRoss Boucher 35b62ca53f Updated test and fix for gh issue #539 2010-03-22 14:53:07 -07:00
Alan RogersandRoss Boucher 4e1e6f3c0b Little fix for CPDictionary, we should not try and recursively convert null JSON objects. 2010-03-22 14:52:55 -07:00
Alan RogersandRoss Boucher c8f3445fa6 Adding a unit test to verify fix to +[CPDictionary dictionaryWithJSObject:(JSObject)object recursively:(BOOL)recursively] 2010-03-22 14:52:49 -07:00
Emmanuel MaillardandRoss Boucher 7aa1ae6bd4 - fix typo 2010-03-22 14:43:53 -07:00
Emmanuel MaillardandRoss Boucher 58179939bb - fix a typo in documentation 2010-03-22 14:43:31 -07:00
Scott KyleandRoss Boucher 5d3eae9022 deleteBackwards: => deleteBackward: 2010-03-22 14:30:48 -07:00
aburkhalterandRoss Boucher 05f8a10b3d Trivial syntax fixes. 2010-03-22 14:29:27 -07:00
Francisco Ryan Tolmasky I 6843df410a Fix for empty data URLs, MHTML, etc. files being created when no image resources exist, causing a useless xhr.
Reviewed by me.
2010-03-21 14:30:31 -07:00
Randall Luecke f324577014 Fixed default height in tableheader for Nib2Cib. 2010-03-21 02:54:14 -04:00
Tom Robinson df8357e1fc Add --split option to flatten. Asynchronously load multiple flattened files. 2010-03-20 23:38:40 -07:00
Tom Robinson 35d14939c4 Fix for flatten in Firefox (silly security restriction makes onreadystatechange not readable) 2010-03-20 22:32:11 -07:00
Francisco Ryan Tolmasky I f2c19ad403 Slight fix for collectionView:canDragItemsAtIndexes:withEvent: not passing the correct event.
Reviewed by me.
2010-03-20 20:58:08 -07:00
Francisco Ryan Tolmasky I ed9fee3038 Added collectionView:canDragItemAtIndexes:forEvent:.
Reviewed by me.
2010-03-20 20:56:37 -07:00
Francisco Ryan Tolmasky I 58e31b9cb4 Merge branch 'master' of git@github.com:280north/cappuccino 2010-03-19 12:25:39 -07:00
Francisco Ryan Tolmasky I 401ee3fd94 Added itemAtIndex: to CPCollectionView and updates API names.
Reviewed by me.
2010-03-19 12:24:07 -07:00
Randall Luecke 43b601af9b Fixed TableTest for IE. 2010-03-17 21:07:47 -04:00
Francisco Ryan Tolmasky I 5581dd71fa Merge branch 'master' of git@github.com:280north/cappuccino 2010-03-17 01:17:50 -07:00
Tom Robinson d8fb849691 Refactor objj_eval to work in the browser. Move from CommonJS-specific code to Objective-J proper. 2010-03-16 23:57:37 -07:00
Tom Robinson 5f4281b851 Add default theme to flattened app, "-P" option for specifying other inlined files. 2010-03-16 22:38:30 -07:00
Tom Robinson 24ab176236 Make asyncLoader a configurable option on exports. 2010-03-16 22:38:30 -07:00
Tom Robinson 9c342ca19c Fix objj_eval (used in objj REPL, etc). 2010-03-16 22:38:30 -07:00
Randall Luecke 3ee3acc948 Fixed failed TableCibTest in Firefox. 2010-03-17 00:11:36 -04:00
Randall Luecke 9bdc5fa0fe Various nib2cib improvements on the tableview. 2010-03-16 22:49:38 -04:00
Randall Luecke d7a7d8e2ae Merge branch 'master' of git://github.com/280north/cappuccino 2010-03-16 22:47:40 -04:00
Ross Boucher 5a9682b1bd Remove two calls to a dead function. 2010-03-16 18:13:57 -07:00
Randall Luecke 3c97903ed0 Fixed Nib2Cib selection color for the tableview. 2010-03-16 19:34:04 -04:00
Ross Boucher c9cf21be80 Fix for sizeWithFont: in Internet Explorer. 2010-03-16 16:01:44 -07:00
Tom Robinson f0818d94e9 Typo in window.clearNativeInterval. 2010-03-16 15:44:45 -07:00
Francisco Ryan Tolmasky I 831555cf5a Merge branch 'master' of git@github.com:280north/cappuccino 2010-03-15 02:33:36 -07:00
Randall Luecke e0483e316e Fixed bug with nib2cib tableviews loading incorrect resources. 2010-03-14 17:24:36 -04:00
Ross Boucher c1fe45cbcd Add a way to tell a CPSplitView about a button bar for a specific divider index,
which mitigates the need to use additional effective rect delegate method when
using a split view + button bar.
2010-03-14 12:32:52 -07:00
Ross Boucher ef7ad8ee8e A few minor bug fixes for key/main window handling. 2010-03-13 22:49:06 -08:00
Ross Boucher 0ed7d46926 Add encoding support for CPButtonBar. 2010-03-13 22:49:06 -08:00
Tom Robinson ac69879fba Update flatten to use new file/function caching system. 2010-03-13 21:42:51 -08:00
Tom Robinson 50e779ef5a Add CFHTTPRequest and FileExecutable hooks for inlining files and module functions (for flatten). Removed hook used by flatten. 2010-03-13 21:35:15 -08:00
Tom Robinson 0032af1468 Merge branch 'master' of github.com:280north/cappuccino 2010-03-13 19:05:10 -08:00
Ross Boucher cf1c369dc3 Rewrite of CPButtonBar. Now it will automatically layout the buttons, and the position
and visibility of the resize control is configurable.

Also has class methods for plusButton and minusButton. API subject to change.
2010-03-13 17:37:28 -08:00
Randall Luecke 3cdfc1192a Fixes flickering issues with CPTableView if you hold the command key and drag. Closes #544 2010-03-13 00:07:00 -05:00
Ross Boucher 8b8998a2b9 Don't encode the search/cancel buttons. They add bloat and complicate the process. 2010-03-12 19:46:05 -08:00
Francisco Ryan Tolmasky I cc2d579bc9 Merge branch '0.8.0' of git@github.com:280north/cappuccino 2010-03-12 03:33:21 -08:00
Ross Boucher ed66d78585 Update the template files to more modern standards. 2010-03-11 14:27:15 -08:00
Ross Boucher 39e1514620 temporary fix for whiteSpace style issue in IE. 2010-03-11 14:18:24 -08:00
Randall Luecke 672be3991d Merge branch '0.8.0' of git://github.com/280north/cappuccino into 0.8.0 2010-03-09 23:49:03 -05:00
Randall Luecke b350c2be91 Fixed previous commit so it doesn't break buttons in the tableview. 2010-03-09 19:19:25 -05:00
Tom Robinson 68ab5bd4e7 Typo in CI script. 2010-03-09 16:12:13 -08:00
Tom Robinson 9cca7ead17 Factor out nightly build portion of CI script so not all branches push builds 2010-03-09 15:35:53 -08:00
Randall Luecke 6d353f378d Fixed bug where editable tableview would not honor setEditable:NO for columns unless resized. closes #426 2010-03-09 14:43:12 -05:00
appdenandRandall Luecke 67def34e29 Added semi-colons to global vars and removed accidental gloabl variable. 2010-03-09 03:22:02 -05:00
Tom Robinson 3e7c3e952b Merge branch '0.8.0' of github.com:280north/cappuccino into 0.8.0 2010-03-08 19:03:14 -08:00
Francisco Ryan Tolmasky I e6411d7d90 Fix for classes declared in subfolders reporting wrong bundle (fictional).
Reviewed by me.
2010-03-08 18:27:43 -08:00
Ross Boucher d85e8798c2 Create the args and namedArgs objects in Bootstrap.js, pass them along up to CPApplication. 2010-03-08 15:00:52 -08:00
181 changed files with 9279 additions and 1551 deletions
+1
View File
@@ -26,6 +26,7 @@
@import "CPApplication.j"
@import "CPBezierPath.j"
@import "CPBox.j"
@import "CPBrowser.j"
@import "CPButton.j"
@import "CPButtonBar.j"
@import "CPCheckBox.j"
+3 -3
View File
@@ -96,12 +96,12 @@
return _items;
}
- (void)addItem:(CPAccordionItem)anItem
- (void)addItem:(CPAccordionViewItem)anItem
{
[self insertItem:anItem atIndex:_items.length];
}
- (void)insertItem:(CPAccordionItem)anItem atIndex:(CPInteger)anIndex
- (void)insertItem:(CPAccordionViewItem)anItem atIndex:(CPInteger)anIndex
{
// FIXME: SHIFT ITEMS RIGHT
[_expandedItemIndexes addIndex:anIndex];
@@ -122,7 +122,7 @@
[self setNeedsLayout];
}
- (void)removeItem:(CPAccordionItem)anItem
- (void)removeItem:(CPAccordionViewItem)anItem
{
[self removeItemAtIndex:[_items indexOfObjectIdenticalTo:anItem]];
}
+193 -210
View File
@@ -31,6 +31,7 @@
@import "CPCibLoading.j"
@import "CPPlatform.j"
#include "Platform/Platform.h"
var CPMainCibFile = @"CPMainCibFile",
CPMainCibFileHumanFriendly = @"Main cib file base name";
@@ -53,7 +54,7 @@ CPRunStoppedResponse = -1000;
CPRunAbortedResponse = -1001;
CPRunContinuesResponse = -1002;
/*!
/*!
@ingroup appkit
@class CPApplication
@@ -61,7 +62,7 @@ CPRunContinuesResponse = -1002;
Every GUI application has exactly one instance of CPApplication (or of a custom subclass of
CPApplication). Your program's main() function can create that instance by calling the
\c CPApplicationMain function. A simple example looks like this:
<pre>
function main(args, namedArgs)
{
@@ -81,25 +82,25 @@ CPRunContinuesResponse = -1002;
@implementation CPApplication : CPResponder
{
CPArray _eventListeners;
CPEvent _currentEvent;
CPArray _windows;
CPWindow _keyWindow;
CPWindow _mainWindow;
CPWindow _previousKeyWindow;
CPWindow _previousMainWindow;
CPMenu _mainMenu;
CPDocumentController _documentController;
CPModalSession _currentSession;
//
id _delegate;
BOOL _finishedLaunching;
BOOL _isActive;
CPDictionary _namedArgs;
CPArray _args;
CPString _fullArgsString;
@@ -118,7 +119,7 @@ CPRunContinuesResponse = -1002;
{
if (!CPApp)
CPApp = [[CPApplication alloc] init];
return CPApp;
}
@@ -130,73 +131,18 @@ CPRunContinuesResponse = -1002;
- (id)init
{
self = [super init];
CPApp = self;
if (self)
{
_eventListeners = [];
_windows = [];
[_windows addObject:nil];
// FIXME: This should be read from the cib.
_mainMenu = [[CPMenu alloc] initWithTitle:@"MainMenu"];
// FIXME: We should implement autoenabling.
[_mainMenu setAutoenablesItems:NO];
var bundle = [CPBundle bundleForClass:[CPApplication class]],
newMenuItem = [[CPMenuItem alloc] initWithTitle:@"New" action:@selector(newDocument:) keyEquivalent:@"N"];
[newMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/New.png"] size:CGSizeMake(16.0, 16.0)]];
[newMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/NewHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
[_mainMenu addItem:newMenuItem];
var openMenuItem = [[CPMenuItem alloc] initWithTitle:@"Open" action:@selector(openDocument:) keyEquivalent:@"O"];
[openMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/Open.png"] size:CGSizeMake(16.0, 16.0)]];
[openMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/OpenHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
[_mainMenu addItem:openMenuItem];
var saveMenu = [[CPMenu alloc] initWithTitle:@"Save"],
saveMenuItem = [[CPMenuItem alloc] initWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:nil];
[saveMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/Save.png"] size:CGSizeMake(16.0, 16.0)]];
[saveMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/SaveHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
[saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:@"S"]];
[saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Save As" action:@selector(saveDocumentAs:) keyEquivalent:nil]];
[saveMenuItem setSubmenu:saveMenu];
[_mainMenu addItem:saveMenuItem];
var editMenuItem = [[CPMenuItem alloc] initWithTitle:@"Edit" action:nil keyEquivalent:nil],
editMenu = [[CPMenu alloc] initWithTitle:@"Edit"],
undoMenuItem = [[CPMenuItem alloc] initWithTitle:@"Undo" action:@selector(undo:) keyEquivalent:CPUndoKeyEquivalent],
redoMenuItem = [[CPMenuItem alloc] initWithTitle:@"Redo" action:@selector(redo:) keyEquivalent:CPRedoKeyEquivalent];
[undoMenuItem setKeyEquivalentModifierMask:CPUndoKeyEquivalentModifierMask];
[redoMenuItem setKeyEquivalentModifierMask:CPRedoKeyEquivalentModifierMask];
[editMenu addItem:undoMenuItem];
[editMenu addItem:redoMenuItem];
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Cut" action:@selector(cut:) keyEquivalent:@"X"]],
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Copy" action:@selector(copy:) keyEquivalent:@"C"]],
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Paste" action:@selector(paste:) keyEquivalent:@"V"]];
[editMenuItem setSubmenu:editMenu];
[editMenuItem setHidden:YES];
[_mainMenu addItem:editMenuItem];
[_mainMenu addItem:[CPMenuItem separatorItem]];
}
return self;
}
@@ -212,85 +158,46 @@ CPRunContinuesResponse = -1002;
{
if (_delegate == aDelegate)
return;
var defaultCenter = [CPNotificationCenter defaultCenter];
var defaultCenter = [CPNotificationCenter defaultCenter],
delegateNotifications =
[
CPApplicationWillFinishLaunchingNotification, @selector(applicationWillFinishLaunching:),
CPApplicationDidFinishLaunchingNotification, @selector(applicationDidFinishLaunching:),
CPApplicationWillBecomeActiveNotification, @selector(applicationWillBecomeActive:),
CPApplicationDidBecomeActiveNotification, @selector(applicationDidBecomeActive:),
CPApplicationWillResignActiveNotification, @selector(applicationWillResignActive:),
CPApplicationDidResignActiveNotification, @selector(applicationDidResignActive:),
CPApplicationWillTerminateNotification, @selector(applicationWillTerminate:)
],
count = [delegateNotifications count];
if (_delegate)
{
[defaultCenter
removeObserver:_delegate
name:CPApplicationWillFinishLaunchingNotification
object:self];
var index = 0;
[defaultCenter
removeObserver:_delegate
name:CPApplicationDidFinishLaunchingNotification
object:self];
for (; index < count; index += 2)
{
var notificationName = delegateNotifications[index],
selector = delegateNotifications[index + 1];
[defaultCenter
removeObserver:_delegate
name:CPApplicationWillBecomeActiveNotification
object:self];
[defaultCenter
removeObserver:_delegate
name:CPApplicationDidBecomeActiveNotification
object:self];
[defaultCenter
removeObserver:_delegate
name:CPApplicationWillResignActiveNotification
object:self];
[defaultCenter
removeObserver:_delegate
name:CPApplicationDidResignActiveNotification
object:self];
if ([_delegate respondsToSelector:selector])
[defaultCenter removeObserver:_delegate name:notificationName object:self];
}
}
_delegate = aDelegate;
if ([_delegate respondsToSelector:@selector(applicationWillFinishLaunching:)])
[defaultCenter
addObserver:_delegate
selector:@selector(applicationWillFinishLaunching:)
name:CPApplicationWillFinishLaunchingNotification
object:self];
if ([_delegate respondsToSelector:@selector(applicationDidFinishLaunching:)])
[defaultCenter
addObserver:_delegate
selector:@selector(applicationDidFinishLaunching:)
name:CPApplicationDidFinishLaunchingNotification
object:self];
if ([_delegate respondsToSelector:@selector(applicationWillBecomeActive:)])
[defaultCenter
addObserver:_delegate
selector:@selector(applicationWillBecomeActive:)
name:CPApplicationWillBecomeActiveNotification
object:self];
var index = 0;
if ([_delegate respondsToSelector:@selector(applicationDidBecomeActive:)])
[defaultCenter
addObserver:_delegate
selector:@selector(applicationDidBecomeActive:)
name:CPApplicationDidBecomeActiveNotification
object:self];
for (; index < count; index += 2)
{
var notificationName = delegateNotifications[index],
selector = delegateNotifications[index + 1];
if ([_delegate respondsToSelector:@selector(applicationWillResignActive:)])
[defaultCenter
addObserver:_delegate
selector:@selector(applicationWillResignActive:)
name:CPApplicationWillResignActiveNotification
object:self];
if ([_delegate respondsToSelector:@selector(applicationDidResignActive:)])
[defaultCenter
addObserver:_delegate
selector:@selector(applicationDidResignActive:)
name:CPApplicationDidResignActiveNotification
object:self];
if ([_delegate respondsToSelector:selector])
[defaultCenter addObserver:_delegate selector:selector name:notificationName object:self];
}
}
/*!
@@ -316,28 +223,28 @@ CPRunContinuesResponse = -1002;
// We also want to set the default cursor on the body, so that buttons and things don't have an iBeam
[[CPCursor arrowCursor] set];
var bundle = [CPBundle mainBundle],
types = [bundle objectForInfoDictionaryKey:@"CPBundleDocumentTypes"];
if ([types count] > 0)
_documentController = [CPDocumentController sharedDocumentController];
var delegateClassName = [bundle objectForInfoDictionaryKey:@"CPApplicationDelegateClass"];
if (delegateClassName)
{
var delegateClass = objj_getClass(delegateClassName);
if (delegateClass)
if ([_documentController class] == delegateClass)
[self setDelegate:_documentController];
else
[self setDelegate:[[delegateClass alloc] init]];
}
var defaultCenter = [CPNotificationCenter defaultCenter];
[defaultCenter
postNotificationName:CPApplicationWillFinishLaunchingNotification
object:self];
@@ -369,6 +276,10 @@ CPRunContinuesResponse = -1002;
- (void)terminate:(id)aSender
{
[[CPNotificationCenter defaultCenter]
postNotificationName:CPApplicationWillTerminateNotification
object:self];
if (![CPPlatform isBrowser])
{
[[CPDocumentController sharedDocumentController] closeAllDocumentsWithDelegate:self
@@ -422,14 +333,14 @@ CPRunContinuesResponse = -1002;
versionLabel = [contentView viewWithTag:3],
copyrightLabel = [contentView viewWithTag:4],
standardPath = [[CPBundle bundleForClass:[self class]] pathForResource:@"standardApplicationIcon.png"];
// FIXME move this into the CIB eventually
[applicationLabel setFont:[CPFont boldSystemFontOfSize:14.0]];
[applicationLabel setAlignment:CPCenterTextAlignment];
[versionLabel setAlignment:CPCenterTextAlignment];
[copyrightLabel setAlignment:CPCenterTextAlignment];
[imageView setImage:applicationIcon || [[CPImage alloc] initWithContentsOfFile:standardPath
[imageView setImage:applicationIcon || [[CPImage alloc] initWithContentsOfFile:standardPath
size:CGSizeMake(256, 256)]];
[applicationLabel setStringValue:applicationTitle || ""];
@@ -533,10 +444,10 @@ CPRunContinuesResponse = -1002;
return;
// raise exception;
}
_currentSession._state = aCode;
_currentSession = _currentSession._previous;
// if (aCode == CPRunAbortedResponse)
[self _removeRunModalLoop];
}
@@ -545,12 +456,12 @@ CPRunContinuesResponse = -1002;
- (void)_removeRunModalLoop
{
var count = _eventListeners.length;
while (count--)
if (_eventListeners[count]._callback === _CPRunModalLoop)
{
_eventListeners.splice(count, 1);
return;
}
}
@@ -588,12 +499,12 @@ CPRunContinuesResponse = -1002;
{
aModalSession._previous = _currentSession;
_currentSession = aModalSession;
var theWindow = aModalSession._window;
[theWindow center];
[theWindow makeKeyAndOrderFront:self];
// [theWindow._bridge _obscureWindowsBelowModalWindow];
[CPApp setCallback:_CPRunModalLoop forNextEventMatchingMask:CPAnyEventMask untilDate:nil inMode:0 dequeue:NO];
@@ -607,7 +518,7 @@ CPRunContinuesResponse = -1002;
{
if (!_currentSession)
return nil;
return _currentSession._window;
}
@@ -652,7 +563,7 @@ CPRunContinuesResponse = -1002;
{
if (_eventListeners[_eventListeners.length - 1]._mask & (1 << [anEvent type]))
_eventListeners.pop()._callback(anEvent);
return;
}
@@ -763,11 +674,11 @@ CPRunContinuesResponse = -1002;
if ([super tryToPerform:anAction with:anObject])
return YES;
if([_delegate respondsToSelector:anAction])
{
[_delegate performSelector:anAction withObject:anObject];
return YES;
}
@@ -787,9 +698,9 @@ CPRunContinuesResponse = -1002;
if (!target)
return NO;
[target performSelector:anAction withObject:aSender];
return YES;
}
@@ -808,10 +719,10 @@ CPRunContinuesResponse = -1002;
{
if (!anAction)
return nil;
if (aTarget)
return aTarget;
return [self targetForAction:anAction];
}
@@ -836,36 +747,35 @@ CPRunContinuesResponse = -1002;
{
var responder = [aWindow firstResponder],
checkWindow = YES;
while (responder)
{
if ([responder respondsToSelector:anAction])
return responder;
if (responder == aWindow)
checkWindow = NO;
responder = [responder nextResponder];
}
if (checkWindow && [aWindow respondsToSelector:anAction])
return aWindow;
var delegate = [aWindow delegate];
if ([delegate respondsToSelector:anAction])
return delegate;
var windowController = [aWindow windowController];
if ([windowController respondsToSelector:anAction])
return windowController;
var theDocument = [windowController document];
if (theDocument != delegate && [theDocument respondsToSelector:anAction])
if (theDocument !== delegate && [theDocument respondsToSelector:anAction])
return theDocument;
return nil;
}
@@ -874,7 +784,7 @@ CPRunContinuesResponse = -1002;
Checks for a target in the following order:
<ol>
<li>a responder from the key window</li>
<li>a responder frmo the main window</li>
<li>a responder from the main window</li>
<li>the CPApplication instance</li>
<li>the application delegate</li>
<li>the document controller</li>
@@ -887,34 +797,32 @@ CPRunContinuesResponse = -1002;
{
if (!anAction)
return nil;
var target = [self _targetForWindow:[self keyWindow] action:anAction];
if (target)
return target;
target = [self _targetForWindow:[self mainWindow] action:anAction];
if (target)
return target;
if ([self respondsToSelector:anAction])
return self;
if ([_delegate respondsToSelector:anAction])
return _delegate;
if ([_documentController respondsToSelector:anAction])
return _documentController;
return nil;
}
- (void)setCallback:(Function)aCallback forNextEventMatchingMask:(unsigned int)aMask untilDate:(CPDate)anExpiration inMode:(CPString)aMode dequeue:(BOOL)shouldDequeue
{
_eventListeners.push(_CPEventListenerMake(aMask, aCallback));
if (_eventListeners.length == 3) objj_debug_print_backtrace();
}
- (CPEvent)setTarget:(id)aTarget selector:(SEL)aSelector forNextEventMatchingMask:(unsigned int)aMask untilDate:(CPDate)anExpiration inMode:(CPString)aMode dequeue:(BOOL)shouldDequeue
@@ -938,14 +846,14 @@ CPRunContinuesResponse = -1002;
@param aContextInfo
*/
- (void)beginSheet:(CPWindow)aSheet modalForWindow:(CPWindow)aWindow modalDelegate:(id)aModalDelegate didEndSelector:(SEL)aDidEndSelector contextInfo:(id)aContextInfo
{
{
var styleMask = [aSheet styleMask];
if (!(styleMask & CPDocModalWindowMask))
{
[CPException raise:CPInternalInconsistencyException reason:@"Currently only CPDocModalWindowMask style mask is supported for attached sheets"];
return;
}
[aWindow orderFront:self];
[aWindow _attachSheet:aSheet modalDelegate:aModalDelegate didEndSelector:aDidEndSelector contextInfo:aContextInfo];
}
@@ -953,15 +861,15 @@ CPRunContinuesResponse = -1002;
- (void)endSheet:(CPWindow)sheet returnCode:(int)returnCode
{
var count = [_windows count];
while (--count >= 0)
{
var aWindow = [_windows objectAtIndex:count];
var context = aWindow._sheetContext;
if (context != nil && context["sheet"] === sheet)
{
context["returnCode"] = returnCode;
context["returnCode"] = returnCode;
[aWindow _detachSheetWindow];
return;
}
@@ -977,7 +885,7 @@ CPRunContinuesResponse = -1002;
{
if(_fullArgsString !== window.location.hash)
[self _reloadArguments];
return _args;
}
@@ -987,28 +895,28 @@ CPRunContinuesResponse = -1002;
{
_args = [];
window.location.hash = @"#";
return;
}
if([args class] != CPArray)
args = [CPArray arrayWithObject:args];
_args = args;
var toEncode = [_args copy];
for(var i=0, count = toEncode.length; i<count; i++)
toEncode[i] = encodeURIComponent(toEncode[i]);
var hash = [toEncode componentsJoinedByString:@"/"];
window.location.hash = @"#" + hash;
}
- (void)_reloadArguments
{
_fullArgsString = window.location.hash;
if (_fullArgsString.length)
{
var args = _fullArgsString.substring(1).split("/");
@@ -1043,18 +951,18 @@ CPRunContinuesResponse = -1002;
- (void)_willBecomeActive
{
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationWillBecomeActiveNotification
object:self
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationWillBecomeActiveNotification
object:self
userInfo:nil];
}
- (void)_didBecomeActive
{
if (![self keyWindow] && _previousKeyWindow &&
if (![self keyWindow] && _previousKeyWindow &&
[[self windows] indexOfObjectIdenticalTo:_previousKeyWindow] !== CPNotFound)
[_previousKeyWindow makeKeyWindow];
if (![self mainWindow] && _previousMainWindow &&
if (![self mainWindow] && _previousMainWindow &&
[[self windows] indexOfObjectIdenticalTo:_previousMainWindow] !== CPNotFound)
[_previousMainWindow makeMainWindow];
@@ -1063,20 +971,20 @@ CPRunContinuesResponse = -1002;
else if ([self mainWindow])
[[self mainWindow] makeKeyAndOrderFront:self];
else
[[[self mainMenu] window] makeKeyWindow]; //FIXME this may not actually work
[[self mainMenu]._menuWindow makeKeyWindow]; //FIXME this may not actually work
_previousKeyWindow = nil;
_previousMainWindow = nil;
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationDidBecomeActiveNotification
object:self
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationDidBecomeActiveNotification
object:self
userInfo:nil];
}
- (void)_willResignActive
{
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationWillResignActiveNotification
object:self
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationWillResignActiveNotification
object:self
userInfo:nil];
}
@@ -1097,8 +1005,8 @@ CPRunContinuesResponse = -1002;
[_previousMainWindow resignMainWindow];
}
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationDidResignActiveNotification
object:self
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationDidResignActiveNotification
object:self
userInfo:nil];
}
@@ -1126,7 +1034,7 @@ var _CPRunModalLoop = function(anEvent)
var theWindow = [anEvent window],
modalSession = CPApp._currentSession;
if (theWindow == modalSession._window || [theWindow worksWhenModal])
[theWindow sendEvent:anEvent];
}
@@ -1140,6 +1048,13 @@ var _CPRunModalLoop = function(anEvent)
function CPApplicationMain(args, namedArgs)
{
#if PLATFORM(DOM)
// hook to allow recorder, etc to manipulate things before starting AppKit
if (window.parent !== window && typeof window.parent._childAppIsStarting === "function")
window.parent._childAppIsStarting(window);
#endif
var mainBundle = [CPBundle mainBundle],
principalClass = [mainBundle principalClass];
@@ -1218,15 +1133,83 @@ var _CPAppBootstrapperActions = nil;
return YES;
}
else
[self loadCiblessBrowserMainMenu];
return NO;
}
+ (void)loadCiblessBrowserMainMenu
{
var mainMenu = [[CPMenu alloc] initWithTitle:@"MainMenu"];
// FIXME: We should implement autoenabling.
[mainMenu setAutoenablesItems:NO];
var bundle = [CPBundle bundleForClass:[CPApplication class]],
newMenuItem = [[CPMenuItem alloc] initWithTitle:@"New" action:@selector(newDocument:) keyEquivalent:@"n"];
[newMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/New.png"] size:CGSizeMake(16.0, 16.0)]];
[newMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/NewHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
[mainMenu addItem:newMenuItem];
var openMenuItem = [[CPMenuItem alloc] initWithTitle:@"Open" action:@selector(openDocument:) keyEquivalent:@"o"];
[openMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/Open.png"] size:CGSizeMake(16.0, 16.0)]];
[openMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/OpenHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
[mainMenu addItem:openMenuItem];
var saveMenu = [[CPMenu alloc] initWithTitle:@"Save"],
saveMenuItem = [[CPMenuItem alloc] initWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:nil];
[saveMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/Save.png"] size:CGSizeMake(16.0, 16.0)]];
[saveMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/SaveHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
[saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:@"s"]];
[saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Save As" action:@selector(saveDocumentAs:) keyEquivalent:nil]];
[saveMenuItem setSubmenu:saveMenu];
[mainMenu addItem:saveMenuItem];
var editMenuItem = [[CPMenuItem alloc] initWithTitle:@"Edit" action:nil keyEquivalent:nil],
editMenu = [[CPMenu alloc] initWithTitle:@"Edit"],
undoMenuItem = [[CPMenuItem alloc] initWithTitle:@"Undo" action:@selector(undo:) keyEquivalent:CPUndoKeyEquivalent],
redoMenuItem = [[CPMenuItem alloc] initWithTitle:@"Redo" action:@selector(redo:) keyEquivalent:CPRedoKeyEquivalent];
[undoMenuItem setKeyEquivalentModifierMask:CPUndoKeyEquivalentModifierMask];
[redoMenuItem setKeyEquivalentModifierMask:CPRedoKeyEquivalentModifierMask];
[editMenu addItem:undoMenuItem];
[editMenu addItem:redoMenuItem];
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Cut" action:@selector(cut:) keyEquivalent:@"x"]],
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Copy" action:@selector(copy:) keyEquivalent:@"c"]],
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Paste" action:@selector(paste:) keyEquivalent:@"v"]];
[editMenuItem setSubmenu:editMenu];
[editMenuItem setHidden:YES];
[mainMenu addItem:editMenuItem];
[mainMenu addItem:[CPMenuItem separatorItem]];
[CPApp setMainMenu:mainMenu];
}
+ (void)cibDidFinishLoading:(CPCib)aCib
{
[self performActions];
}
+ (void)cibDidFailToLoad:(CPCib)aCib
{
throw new Error("Could not load main cib file (Did you forget to nib2cib it?).");
}
+ (void)reset
{
_CPAppBootstrapperActions = nil;
+952
View File
@@ -0,0 +1,952 @@
/*
* CPBrowser.j
* AppKit
*
* Created by Ross Boucher.
* Copyright 2010, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPControl.j"
@import "CPImage.j"
@import "CPTableView.j"
@import "CPScrollView.j"
/*!
@ingroup appkit
@class CPBrowser
*/
@implementation CPBrowser : CPControl
{
id _delegate;
CPString _pathSeparator;
CPView _contentView;
CPScrollView _horizontalScrollView;
CPView _prototypeView;
CPArray _tableViews;
CPArray _tableDelegates;
id _rootItem;
BOOL _delegateSupportsImages;
SEL _doubleAction @accessors(property=doubleAction);
BOOL _allowsMultipleSelection;
BOOL _allowsEmptySelection;
Class _tableViewClass @accessors(property=tableViewClass);
float _rowHeight;
float _imageWidth;
float _leafWidth;
float _minColumnWidth;
float _defaultColumnWidth @accessors(property=defaultColumnWidth);
CPArray _columnWidths;
}
+ (CPImage)branchImage
{
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPBrowser class]]
pathForResource:"browser-leaf.png"]
size:CGSizeMake(9,9)];
}
+ (CPImage)highlightedBranchImage
{
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPBrowser class]]
pathForResource:"browser-leaf-highlighted.png"]
size:CGSizeMake(9,9)];
}
- (id)initWithFrame:(CGRect)aFrame
{
if (self = [super initWithFrame:aFrame])
{
_rowHeight = 23.0;
_defaultColumnWidth = 140.0;
_minColumnWidth = 80.0;
_imageWidth = 23.0;
_leafWidth = 13.0;
_columnWidths = [];
_pathSeparator = "/";
_tableViews = [];
_tableDelegates = [];
_allowsMultipleSelection = YES;
_allowsEmptySelection = YES;
_tableViewClass = [_CPBrowserTableView class];
_prototypeView = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
[_prototypeView setVerticalAlignment:CPCenterVerticalTextAlignment];
[_prototypeView setValue:[CPColor whiteColor] forThemeAttribute:"text-color" inState:CPThemeStateSelected];
[_prototypeView setLineBreakMode:CPLineBreakByTruncatingTail];
_horizontalScrollView = [[CPScrollView alloc] initWithFrame:[self bounds]];
[_horizontalScrollView setHasVerticalScroller:NO];
[_horizontalScrollView setAutohidesScrollers:YES];
[_horizontalScrollView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
_contentView = [[CPView alloc] initWithFrame:CGRectMake(0, 0, 0, CGRectGetHeight([self bounds]))];
[_contentView setAutoresizingMask:CPViewHeightSizable];
[_horizontalScrollView setDocumentView:_contentView];
[self addSubview:_horizontalScrollView];
}
return self;
}
- (void)setPrototypeView:(CPView)aPrototypeView
{
_prototypeView = [CPKeyedUnarchiver unarchiveObjectWithData:
[CPKeyedArchiver archivedDataWithRootObject:aPrototypeView]];
}
- (CPView)prototypeView
{
return [CPKeyedUnarchiver unarchiveObjectWithData:
[CPKeyedArchiver archivedDataWithRootObject:_prototypeView]];
}
- (void)setDelegate:(id)anObject
{
_delegate = anObject;
_delegateSupportsImages = [_delegate respondsToSelector:@selector(browser:imageValueForItem:)];
[self loadColumnZero];
}
- (id)delegate
{
return _delegate;
}
- (CPTableView)tableViewInColumn:(unsigned)index
{
return _tableViews[index];
}
- (unsigned)columnOfTableView:(CPTableView)aTableView
{
return [_tableViews indexOfObject:aTableView];
}
- (void)loadColumnZero
{
if ([_delegate respondsToSelector:@selector(rootItemForBrowser:)])
_rootItem = [_delegate rootItemForBrowser:self];
else
_rootItem = nil;
[self setLastColumn:-1];
[self addColumn];
}
- (void)setLastColumn:(int)columnIndex
{
if (columnIndex >= _tableViews.length)
return;
var oldValue = _tableViews.length - 1;
// unloads all later columns.
var indexPlusOne = columnIndex + 1;
[[_tableViews.slice(indexPlusOne) valueForKey:"enclosingScrollView"]
makeObjectsPerformSelector:@selector(removeFromSuperview)];
_tableViews = _tableViews.slice(0, indexPlusOne);
_tableDelegates = _tableDelegates.slice(0, indexPlusOne);
if ([_delegate respondsToSelector:@selector(browser:didChangeLastColumn:toColumn:)])
[_delegate browser:self didChangeLastColumn:oldValue toColumn:columnIndex];
[self tile];
}
- (int)lastColumn
{
return _tableViews.length - 1;
}
- (void)addColumn
{
var lastIndex = [self lastColumn],
lastColumn = _tableViews[lastIndex],
selectionIndexes = [lastColumn selectedRowIndexes];
if (lastIndex >= 0 && [selectionIndexes count] > 1)
[CPException raise:CPInvalidArgumentException
reason:"Can't add column, column "+lastIndex+" has invalid selection."];
var index = lastIndex+1,
item = index === 0 ? _rootItem : [_tableDelegates[lastIndex] childAtIndex:[selectionIndexes firstIndex]];
if (index > 0 && item && [self isLeafItem:item])
return;
var table = [[_tableViewClass alloc] initWithFrame:CGRectMakeZero() browser:self];
[table setHeaderView:nil];
[table setCornerView:nil];
[table setAllowsMultipleSelection:_allowsMultipleSelection];
[table setAllowsEmptySelection:_allowsEmptySelection];
[table registerForDraggedTypes:[self registeredDraggedTypes]];
[self _addTableColumnsToTableView:table forColumnIndex:index];
var delegate = [[_CPBrowserTableDelegate alloc] init];
[delegate _setDelegate:_delegate];
[delegate _setBrowser:self];
[delegate _setIndex:index];
[delegate _setItem:item];
_tableViews[index] = table;
_tableDelegates[index] = delegate;
[table setDelegate:delegate];
[table setDataSource:delegate];
[table setTarget:delegate];
[table setAction:@selector(_tableViewClicked:)];
[table setDoubleAction:@selector(_tableViewDoubleClicked:)];
[table setDraggingDestinationFeedbackStyle:CPTableViewDraggingDestinationFeedbackStyleRegular];
var scrollView = [[_CPBrowserScrollView alloc] initWithFrame:CGRectMakeZero()];
[scrollView _setBrowser:self];
[scrollView setDocumentView:table];
[scrollView setHasHorizontalScroller:NO];
[scrollView setAutoresizingMask:CPViewHeightSizable];
[_contentView addSubview:scrollView];
[self tile];
[self scrollColumnToVisible:index];
}
- (void)_addTableColumnsToTableView:(CPTableView)aTableView forColumnIndex:(unsigned)index
{
if (_delegateSupportsImages)
{
var column = [[CPTableColumn alloc] initWithIdentifier:@"Image"],
view = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
[view setImageScaling:CPScaleProportionally];
[column setDataView:view];
[column setResizingMask:CPTableColumnNoResizing];
[aTableView addTableColumn:column];
}
var column = [[CPTableColumn alloc] initWithIdentifier:@"Content"];
[column setDataView:_prototypeView];
[column setResizingMask:CPTableColumnNoResizing];
[aTableView addTableColumn:column];
var column = [[CPTableColumn alloc] initWithIdentifier:@"Leaf"],
view = [[_CPBrowserLeafView alloc] initWithFrame:CGRectMakeZero()];
[view setBranchImage:[[self class] branchImage]];
[view setHighlightedBranchImage:[[self class] highlightedBranchImage]];
[column setDataView:view];
[column setResizingMask:CPTableColumnNoResizing];
[aTableView addTableColumn:column];
}
- (void)reloadColumn:(int)column
{
[[self tableViewInColumn:column] reloadData];
}
- (void)tile
{
var xOrigin = 0,
scrollerWidth = [CPScroller scrollerWidth],
height = CGRectGetHeight([_contentView bounds]);
for (var i = 0, count = _tableViews.length; i < count; i++)
{
var tableView = _tableViews[i],
scrollView = [tableView enclosingScrollView],
width = [self widthOfColumn:i],
tableHeight = CGRectGetHeight([tableView bounds]);
[[tableView tableColumnWithIdentifier:"Image"] setWidth:_imageWidth];
[[tableView tableColumnWithIdentifier:"Content"] setWidth:width - (_leafWidth + _delegateSupportsImages ? _imageWidth : 0) - scrollerWidth - scrollerWidth];
[[tableView tableColumnWithIdentifier:"Leaf"] setWidth:_leafWidth];
[tableView setRowHeight:_rowHeight];
[tableView setFrameSize:CGSizeMake(width - scrollerWidth, tableHeight)];
[scrollView setFrameOrigin:CGPointMake(xOrigin, 0)];
[scrollView setFrameSize:CGSizeMake(width, height)];
xOrigin += width;
}
[_contentView setFrameSize:CGSizeMake(xOrigin, height)];
}
- (unsigned)rowAtPoint:(CGPoint)aPoint
{
var column = [self columnAtPoint:aPoint];
if (column === -1)
return -1;
var tableView = _tableViews[column];
return [tableView rowAtPoint:[tableView convertPoint:aPoint fromView:self]];
}
- (unsigned)columnAtPoint:(CGPoint)aPoint
{
var adjustedPoint = [_contentView convertPoint:aPoint fromView:self];
for (var i = 0, count = _tableViews.length; i < count; i++)
{
var frame = [[_tableViews[i] enclosingScrollView] frame];
if (CGRectContainsPoint(frame, adjustedPoint))
return i;
}
return -1;
}
- (CGRect)rectOfRow:(unsigned)aRow inColumn:(unsigned)aColumn
{
var tableView = _tableViews[aColumn],
rect = [tableView rectOfRow:aRow];
rect.origin = [self convertPoint:rect.origin fromView:tableView];
return rect;
}
// ITEMS
- (id)itemAtRow:(int)row inColumn:(int)column
{
return [_tableDelegates[column] childAtIndex:row];
}
- (BOOL)isLeafItem:(id)item
{
return [_delegate respondsToSelector:@selector(browser:isLeafItem:)] && [_delegate browser:self isLeafItem:item];
}
- (id)parentForItemsInColumn:(int)column
{
return [_tableDelegates[column] _item];
}
- (CPSet)selectedItems
{
var selectedColumn = [self selectedColumn],
selectedIndexes = [self selectedRowIndexesInColumn:selectedColumn],
set = [CPSet set],
index = [selectedIndexes firstIndex];
while (index !== CPNotFound)
{
[set addObject:[self itemAtRow:index inColumn:selectedColumn]];
index = [selectedIndexes indexGreaterThanIndex:index];
}
return set;
}
- (id)selectedItem
{
var selectedColumn = [self selectedColumn],
selectedRow = [self selectedRowInColumn:selectedColumn];
return [self itemAtRow:selectedRow inColumn:selectedColumn];
}
// CLICK EVENTS
- (void)trackMouse:(CPEvent)anEvent
{
}
- (void)_column:(unsigned)columnIndex clickedRow:(unsigned)rowIndex
{
[self setLastColumn:columnIndex];
if (rowIndex >= 0)
[self addColumn];
[self doClick:self];
}
- (void)sendAction
{
[self sendAction:_action to:_target];
}
- (void)doClick:(id)sender
{
[self sendAction:_action to:_target];
}
- (void)doDoubleClick:(id)sender
{
[self sendAction:_doubleAction to:_target];
}
- (void)keyDown:(CPEvent)anEvent
{
var column = [self selectedColumn];
if (column === -1)
return;
[_tableViews[column] keyDown:anEvent];
}
// SIZING
- (float)columnContentWidthForColumnWidth:(float)aWidth
{
return aWidth - (_leafWidth + _delegateSupportsImages ? _imageWidth : 0) - [CPScroller scrollerWidth];
}
- (float)columnWidthForColumnContentWidth:(float)aWidth
{
return aWidth + (_leafWidth + _delegateSupportsImages ? _imageWidth : 0) + [CPScroller scrollerWidth];
}
- (void)setImageWidth:(float)aWidth
{
_imageWidth = aWidth;
[self tile];
}
- (float)imageWidth
{
return _imageWidth;
}
- (void)setMinColumnWidth:(float)minWidth
{
_minColumnWidth = minWidth;
[self tile];
}
- (float)minColumnWidth
{
return _minColumnWidth;
}
- (void)setWidth:(float)aWidth ofColumn:(unsigned)column
{
_columnWidths[column] = aWidth;
if ([_delegate respondsToSelector:@selector(browser:didResizeColumn:)])
[_delegate browser:self didResizeColumn:column];
[self tile];
}
- (float)widthOfColumn:(unsigned)column
{
var width = _columnWidths[column];
if (width == null)
width = _defaultColumnWidth;
return MAX([CPScroller scrollerWidth], MAX(_minColumnWidth, width));
}
- (void)setRowHeight:(float)aHeight
{
_rowHeight = aHeight;
}
- (float)rowHeight
{
return _rowHeight;
}
// SCROLLERS
- (void)scrollColumnToVisible:(unsigned)columnIndex
{
[_contentView scrollRectToVisible:[[[self tableViewInColumn:columnIndex] enclosingScrollView] frame]];
}
(void)scrollRowToVisible:(unsigned)rowIndex inColumn:(unsigned)columnIndex
{
[self scrollColumnToVisible:columnIndex];
[[self tableViewInColumn:columnIndex] scrollRowToVisible:rowIndex];
}
- (BOOL)autohidesScroller
{
return [_horizontalScrollView autohidesScrollers];
}
- (void)setAutohidesScroller:(BOOL)shouldHide
{
[_horizontalScrollView setAutohidesScrollers:shouldHide];
}
// SELECTION
- (unsigned)selectedRowInColumn:(unsigned)columnIndex
{
if (columnIndex > [self lastColumn] || columnIndex < 0)
return -1;
return [_tableViews[columnIndex] selectedRow];
}
- (unsigned)selectedColumn
{
var column = [self lastColumn],
row = [self selectedRowInColumn:column];
if (row >= 0)
return column;
else
return column - 1;
}
- (void)selectRow:(unsigned)row inColumn:(unsigned)column
{
var selectedIndexes = row === -1 ? [CPIndexSet indexSet] : [CPIndexSet indexSetWithIndex:row];
[self selectRowIndexes:selectedIndexes inColumn:column];
}
- (BOOL)allowsMultipleSelection
{
return _allowsMultipleSelection;
}
- (void)setAllowsMultipleSelection:(BOOL)shouldAllow
{
if (_allowsMultipleSelection === shouldAllow)
return;
_allowsMultipleSelection = shouldAllow;
[_tableViews makeObjectsPerformSelector:@selector(setAllowsMultipleSelection:) withObject:shouldAllow];
}
- (BOOL)allowsEmptySelection
{
return _allowsEmptySelection;
}
- (void)setAllowsEmptySelection:(BOOL)shouldAllow
{
if (_allowsEmptySelection === shouldAllow)
return;
_allowsEmptySelection = shouldAllow;
[_tableViews makeObjectsPerformSelector:@selector(setAllowsEmptySelection:) withObject:shouldAllow];
}
- (CPIndexSet)selectedRowIndexesInColumn:(unsigned)column
{
if (column < 0 || column > [self lastColumn] +1)
return [CPIndexSet indexSet];
return [[self tableViewInColumn:column] selectedRowIndexes];
}
- (void)selectRowIndexes:(CPIndexSet)indexSet inColumn:(unsigned)column
{
if (column < 0 || column > [self lastColumn] + 1)
return;
if ([_delegate respondsToSelector:@selector(browser:selectionIndexesForProposedSelection:inColumn:)])
indexSet = [_delegate browser:self selectionIndexesForProposedSelection:indexSet inColumn:column];
if ([_delegate respondsToSelector:@selector(browser:shouldSelectRowIndexes:inColumn:)] &&
![_delegate browser:self shouldSelectRowIndexes:indexSet inColumn:column])
return;
if ([_delegate respondsToSelector:@selector(browserSelectionIsChanging:)])
[_delegate browserSelectionIsChanging:self];
if (column > [self lastColumn])
[self addColumn];
[self setLastColumn:column];
[[self tableViewInColumn:column] selectRowIndexes:indexSet byExtendingSelection:NO];
[self scrollColumnToVisible:column];
if ([_delegate respondsToSelector:@selector(browserSelectionDidChange:)])
[_delegate browserSelectionDidChange:self];
}
- (void)setBackgroundColor:(CPColor)aColor
{
[super setBackgroundColor:aColor];
[_contentView setBackgroundColor:aColor];
}
- (BOOL)acceptsFirstResponder
{
return YES;
}
// DRAG AND DROP
- (void)registerForDraggedTypes:(CPArray)types
{
[super registerForDraggedTypes:types];
[_tableViews makeObjectsPerformSelector:@selector(registerForDraggedTypes:) withObject:types];
}
- (BOOL)canDragRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(int)columnIndex withEvent:(CPEvent)dragEvent
{
if ([_delegate respondsToSelector:@selector(browser:canDragRowsWithIndexes:inColumn:withEvent:)])
return [_delegate browser:self canDragRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent];
return YES;
}
- (CPImage)draggingImageForRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(int)columnIndex withEvent:(CPEvent)dragEvent offset:(CGPoint)dragImageOffset
{
if ([_delegate respondsToSelector:@selector(browser:draggingImageForRowsWithIndexes:inColumn:withEvent:offset:)])
return [_delegate browser:self draggingImageForRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent offset:dragImageOffset];
return nil;
}
- (CPView)draggingViewForRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(int)columnIndex withEvent:(CPEvent)dragEvent offset:(CGPoint)dragImageOffset
{
if ([_delegate respondsToSelector:@selector(browser:draggingViewForRowsWithIndexes:inColumn:withEvent:offset:)])
return [_delegate browser:self draggingViewForRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent offset:dragImageOffset];
return nil;
}
@end
var _CPBrowserResizeControlBackgroundImage = nil;
@implementation _CPBrowserResizeControl : CPView
{
CGPoint _mouseDownX;
CPBrowser _browser;
unsigned _index;
unsigned _width;
}
+ (CPImage)backgroundImage
{
if (!_CPBrowserResizeControlBackgroundImage)
{
var path = [[CPBundle bundleForClass:[self class]] pathForResource:"browser-resize-control.png"];
_CPBrowserResizeControlBackgroundImage = [[CPImage alloc] initWithContentsOfFile:path
size:CGSizeMake(15, 14)];
}
return _CPBrowserResizeControlBackgroundImage;
}
- (id)initWithFrame:(CGRect)aFrame
{
if (self = [super initWithFrame:aFrame])
[self setBackgroundColor:[CPColor colorWithPatternImage:[[self class] backgroundImage]]];
return self;
}
- (void)mouseDown:(CPEvent)anEvent
{
_mouseDownX = [anEvent locationInWindow].x;
_browser = [[self superview] _browser];
_index = [_browser columnOfTableView:[[self superview] documentView]];
_width = [_browser widthOfColumn:_index];
}
- (void)mouseDragged:(CPEvent)anEvent
{
var deltaX = [anEvent locationInWindow].x - _mouseDownX;
[_browser setWidth:_width + deltaX ofColumn:_index];
}
- (void)mouseUp:(CPEvent)anEvent
{
}
@end
@implementation _CPBrowserScrollView : CPScrollView
{
_CPBrowserResizeControl _resizeControl;
CPBrowser _browser @accessors;
}
- (void)initWithFrame:(CGRect)aFrame
{
if (self = [super initWithFrame:aFrame])
{
_resizeControl = [[_CPBrowserResizeControl alloc] initWithFrame:CGRectMakeZero()];
[self addSubview:_resizeControl];
}
return self;
}
- (void)reflectScrolledClipView:(CPClipView)aClipView
{
[super reflectScrolledClipView:aClipView];
var frame = [_verticalScroller frame];
frame.size.height = CGRectGetHeight([self bounds]) - 14.0 - frame.origin.y;
[_verticalScroller setFrameSize:frame.size];
var resizeFrame = CGRectMake(CGRectGetMinX(frame), CGRectGetMaxY(frame), [CPScroller scrollerWidth], 14.0);
[_resizeControl setFrame:resizeFrame];
}
@end
@implementation _CPBrowserTableView : CPTableView
{
CPBrowser _browser;
}
- (id)initWithFrame:(CGRect)aFrame browser:(CPBrowser)aBrowser
{
if (self = [super initWithFrame:aFrame])
_browser = aBrowser;
return self;
}
- (BOOL)acceptsFirstResponder
{
return NO;
}
- (void)mouseDown:(CPEvent)anEvent
{
[super mouseDown:anEvent];
[[self window] makeFirstResponder:_browser];
}
- (CPView)browserView
{
return _browser;
}
- (BOOL)canDragRowsWithIndexes:(CPIndexSet)rowIndexes atPoint:(CGPoint)mouseDownPoint
{
return [_browser canDragRowsWithIndexes:rowIndexes inColumn:[_browser columnOfTableView:self] withEvent:[CPApp currentEvent]];
}
- (CPImage)dragImageForRowsWithIndexes:(CPIndexSet)dragRows tableColumns:(CPArray)theTableColumns event:(CPEvent)dragEvent offset:(CPPointPointer)dragImageOffset
{
return [_browser draggingImageForRowsWithIndexes:dragRows inColumn:[_browser columnOfTableView:self] withEvent:dragEvent offset:dragImageOffset] ||
[super dragImageForRowsWithIndexes:dragRows tableColumns:theTableColumns event:dragEvent offset:dragImageOffset];
}
- (CPView)dragViewForRowsWithIndexes:(CPIndexSet)dragRows tableColumns:(CPArray)theTableColumns event:(CPEvent)dragEvent offset:(CPPoint)dragViewOffset
{
var count = theTableColumns.length;
while (count--)
{
if ([theTableColumns[count] identifier] === "Leaf")
[theTableColumns removeObject:theTableColumns[count]];
}
return [_browser draggingViewForRowsWithIndexes:dragRows inColumn:[_browser columnOfTableView:self] withEvent:dragEvent offset:dragViewOffset] ||
[super dragViewForRowsWithIndexes:dragRows tableColumns:theTableColumns event:dragEvent offset:dragViewOffset];
}
- (void)moveUp:(id)sender
{
[super moveUp:sender];
[_browser selectRow:[self selectedRow] inColumn:[_browser selectedColumn]];
}
- (void)moveDown:(id)sender
{
[super moveDown:sender];
[_browser selectRow:[self selectedRow] inColumn:[_browser selectedColumn]];
}
- (void)moveLeft:(id)sender
{
var previousColumn = [_browser selectedColumn] - 1,
selectedRow = [_browser selectedRowInColumn:previousColumn];
[_browser selectRow:selectedRow inColumn:previousColumn];
}
- (void)moveRight:(id)sender
{
[_browser selectRow:0 inColumn:[_browser selectedColumn] + 1];
}
@end
@implementation _CPBrowserTableDelegate : CPObject
{
CPBrowser _browser @accessors;
unsigned _index @accessors;
id _delegate @accessors;
id _item @accessors;
}
- (unsigned)numberOfRowsInTableView:(CPTableView)aTableView
{
return [_delegate browser:_browser numberOfChildrenOfItem:_item];
}
- (void)tableView:(CPTableView)aTableView objectValueForTableColumn:(CPTableColumn)column row:(unsigned)row
{
if ([column identifier] === "Image")
return [_delegate browser:_browser imageValueForItem:[self childAtIndex:row]];
else if ([column identifier] === "Leaf")
return ![_browser isLeafItem:[self childAtIndex:row]];
else
return [_delegate browser:_browser objectValueForItem:[self childAtIndex:row]];
}
- (void)_tableViewDoubleClicked:(CPTableView)aTableView
{
[_browser doDoubleClick:self];
}
- (void)_tableViewClicked:(CPTableView)aTableView
{
var selectedIndexes = [aTableView selectedRowIndexes];
[_browser _column:_index clickedRow:[selectedIndexes count] === 1 ? [selectedIndexes firstIndex] : -1];
}
- (id)childAtIndex:(unsigned)index
{
return [_delegate browser:_browser child:index ofItem:_item];
}
- (BOOL)tableView:(CPTableView)aTableView acceptDrop:(id)info row:(int)row dropOperation:(CPTableViewDropOperation)operation
{
if ([_delegate respondsToSelector:@selector(browser:acceptDrop:atRow:column:dropOperation:)])
return [_delegate browser:_browser acceptDrop:info atRow:row column:_index dropOperation:operation];
else
return NO;
}
- (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(id)info proposedRow:(int)row proposedDropOperation:(CPTableViewDropOperation)operation
{
if ([_delegate respondsToSelector:@selector(browser:validateDrop:proposedRow:column:dropOperation:)])
[_delegate browser:_browser validateDrop:info proposedRow:row column:_index dropOperation:operation];
else
return CPDragOperationNone;
}
- (BOOL)tableView:(CPTableView)aTableView writeRowsWithIndexes:(CPIndexSet)rowIndexes toPasteboard:(CPPasteboard)pboard
{
if ([_delegate respondsToSelector:@selector(browser:writeRowsWithIndexes:inColumn:toPasteboard:)])
return [_delegate browser:_browser writeRowsWithIndexes:rowIndexes inColumn:_index toPasteboard:pboard];
else
return NO;
}
- (BOOL)respondsToSelector:(SEL)aSelector
{
if (aSelector === @selector(browser:writeRowsWithIndexes:inColumn:toPasteboard:))
return [_delegate respondsToSelector:@selector(browser:writeRowsWithIndexes:inColumn:toPasteboard:)];
else
return [super respondsToSelector:aSelector];
}
@end
@implementation _CPBrowserLeafView : CPView
{
BOOL _isLeaf @accessors(readonly, property=isLeaf);
CPImage _branchImage @accessors(property=branchImage);
CPImage _highlightedBranchImage @accessors(property=highlightedBranchImage);
}
- (BOOL)objectValue
{
return _isLeaf;
}
- (void)setObjectValue:(id)aValue
{
_isLeaf = !!aValue;
[self setNeedsLayout];
}
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
{
if (aName === "image-view")
return CGRectInset([self bounds], 1, 1);
return [super rectForEphemeralSubviewNamed:aName];
}
- (CPView)createEphemeralSubviewNamed:(CPString)aName
{
if (aName === "image-view")
return [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
return [super createEphemeralSubviewNamed:aName];
}
- (void)layoutSubviews
{
var imageView = [self layoutEphemeralSubviewNamed:@"image-view"
positioned:CPWindowAbove
relativeToEphemeralSubviewNamed:nil];
var isHighlighted = [self themeState] & CPThemeStateSelected;
[imageView setImage: _isLeaf ? (isHighlighted ? _highlightedBranchImage : _branchImage) : nil];
[imageView setImageScaling:CPScaleNone];
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeBool:_isLeaf forKey:"_CPBrowserLeafViewIsLeafKey"];
[aCoder encodeObject:_branchImage forKey:"_CPBrowserLeafViewBranchImageKey"];
[aCoder encodeObject:_highlightedBranchImage forKey:"_CPBrowserLeafViewHighlightedBranchImageKey"];
}
- (void)initWithCoder:(CPCoder)aCoder
{
if (self = [super initWithCoder:aCoder])
{
_isLeaf = [aCoder decodeBoolForKey:"_CPBrowserLeafViewIsLeafKey"];
_branchImage = [aCoder decodeObjectForKey:"_CPBrowserLeafViewBranchImageKey"];
_highlightedBranchImage = [aCoder decodeObjectForKey:"_CPBrowserLeafViewHighlightedBranchImageKey"];
}
return self;
}
@end
+2 -5
View File
@@ -502,8 +502,6 @@ CPButtonStateMixed = CPThemeState("mixed");
}
else
return [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
return [super createEphemeralSubviewNamed:aName];
}
- (void)layoutSubviews
@@ -511,9 +509,8 @@ CPButtonStateMixed = CPThemeState("mixed");
var bezelView = [self layoutEphemeralSubviewNamed:@"bezel-view"
positioned:CPWindowBelow
relativeToEphemeralSubviewNamed:@"content-view"];
if (bezelView)
[bezelView setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
[bezelView setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
var contentView = [self layoutEphemeralSubviewNamed:@"content-view"
positioned:CPWindowAbove
+237 -29
View File
@@ -4,18 +4,50 @@
#include "CoreGraphics/CGGeometry.h"
@implementation CPButtonBar : CPControl
@implementation CPButtonBar : CPView
{
BOOL _hasResizeControl;
BOOL _resizeControlIsLeftAligned;
CPArray _buttons;
}
- (id)initWithFrame:(CGRect)aFrame
+ (id)plusButton
{
self = [super initWithFrame:aFrame];
var button = [[CPButton alloc] initWithFrame:CGRectMake(0, 0, 35, 25)],
image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPButtonBar class]] pathForResource:@"plus_button.png"] size:CGSizeMake(11, 12)];
if (self)
[self setNeedsLayout];
[button setBordered:NO];
[button setImage:image];
[button setImagePosition:CPImageOnly];
return self;
return button;
}
+ (id)minusButton
{
var button = [[CPButton alloc] initWithFrame:CGRectMake(0, 0, 35, 25)],
image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPButtonBar class]] pathForResource:@"minus_button.png"] size:CGSizeMake(11, 4)];
[button setBordered:NO];
[button setImage:image];
[button setImagePosition:CPImageOnly];
return button;
}
+ (id)actionPopupButton
{
var button = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0, 0, 35, 25)],
image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPButtonBar class]] pathForResource:@"action_button.png"] size:CGSizeMake(22, 14)];
[button addItemWithTitle:nil];
[[button lastItem] setImage:image];
[button setImagePosition:CPImageOnly];
[button setValue:CGInsetMake(0, 0, 0, 0) forThemeAttribute:"content-inset"];
[button setPullsDown:YES];
return button;
}
+ (CPString)themeClass
@@ -25,47 +57,223 @@
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[[CPNull null]]
forKeys:[@"bezel-color"]];
return [CPDictionary dictionaryWithObjects:[CGInsetMake(0.0, 0.0, 0.0, 0.0), CGSizeMakeZero(), [CPNull null], [CPNull null], [CPNull null], [CPNull null]]
forKeys:[@"resize-control-inset", @"resize-control-size", @"resize-control-color", @"bezel-color", @"button-bezel-color", @"button-text-color"]];
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
_buttons = [];
[self setNeedsLayout];
}
return self;
}
- (void)awakeFromCib
{
var view = [self superview],
subview = self;
while (view)
{
if ([view isKindOfClass:[CPSplitView class]])
{
var viewIndex = [[view subviews] indexOfObject:subview];
[view setButtonBar:self forDividerAtIndex:viewIndex];
break;
}
subview = view;
view = [view superview];
}
}
- (void)setButtons:(CPArray)buttons
{
_buttons = [CPArray arrayWithArray:buttons];
for (var i = 0, count = [_buttons count]; i < count; i++)
[_buttons[i] setBordered:YES];
[self setNeedsLayout];
}
- (CPArray)buttons
{
return [CPArray arrayWithArray:_buttons];
}
- (void)setHasResizeControl:(BOOL)shouldHaveResizeControl
{
if (_hasResizeControl === shouldHaveResizeControl)
return;
_hasResizeControl = !!shouldHaveResizeControl;
[self setNeedsLayout];
}
- (BOOL)hasResizeControl
{
return _hasResizeControl;
}
- (void)setResizeControlIsLeftAligned:(BOOL)shouldBeLeftAligned
{
if (_resizeControlIsLeftAligned === shouldBeLeftAligned)
return;
_resizeControlIsLeftAligned = !!shouldBeLeftAligned;
[self setNeedsLayout];
}
- (BOOL)resizeControlIsLeftAligned
{
return _resizeControlIsLeftAligned;
}
- (CGRect)resizeControlFrame
{
var inset = [self currentValueForThemeAttribute:@"resize-control-inset"],
size = [self currentValueForThemeAttribute:@"resize-control-size"],
currentSize = [self bounds],
leftOrigin = _resizeControlIsLeftAligned ? 0 : currentSize.size.width - size.width - inset.right - inset.left;
return CGRectMake(leftOrigin, 0, size.width + inset.left + inset.right, size.height + inset.top + inset.bottom);
}
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
{
if (aName === "bezel-view")
return [self bounds];
if (aName === "resize-control-view")
{
var inset = [self currentValueForThemeAttribute:@"resize-control-inset"],
size = [self currentValueForThemeAttribute:@"resize-control-size"],
currentSize = [self bounds];
if (_resizeControlIsLeftAligned)
return CGRectMake(inset.left, inset.top, size.width, size.height);
else
return CGRectMake(currentSize.size.width - size.width - inset.right, inset.top, size.width, size.height);
}
return [super rectForEphemeralSubviewNamed:aName];
}
- (CPView)createEphemeralSubviewNamed:(CPString)aName
{
if (aName === "bezel-view")
{
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
if (aName === "resize-control-view")
return [[CPView alloc] initWithFrame:CGRectMakeZero()];
[view setHitTests:NO];
return view;
}
return [super createEphemeralSubviewNamed:aName];
}
- (void)layoutSubviews
{
var bezelView = [self layoutEphemeralSubviewNamed:@"bezel-view"
positioned:CPWindowBelow
relativeToEphemeralSubviewNamed:@""];
if (bezelView)
[bezelView setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
[self setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
var normalColor = [self valueForThemeAttribute:@"button-bezel-color" inState:CPThemeStateNormal],
highlightedColor = [self valueForThemeAttribute:@"button-bezel-color" inState:CPThemeStateHighlighted],
disabledColor = [self valueForThemeAttribute:@"button-bezel-color" inState:CPThemeStateDisabled],
textColor = [self valueForThemeAttribute:@"button-text-color" inState:CPThemeStateNormal];
var buttonsNotHidden = [CPArray arrayWithArray:_buttons],
count = [buttonsNotHidden count];
while (count--)
if ([buttonsNotHidden[count] isHidden])
[buttonsNotHidden removeObject:buttonsNotHidden[count]];
var currentButtonOffset = _resizeControlIsLeftAligned ? CGRectGetMaxX([self bounds]) + 1 : -1,
bounds = [self bounds],
height = CGRectGetHeight(bounds) - 1,
frameWidth = CGRectGetWidth(bounds),
resizeRect = _hasResizeControl ? [self rectForEphemeralSubviewNamed:"resize-control-view"] : CGRectMakeZero(),
resizeWidth = CGRectGetWidth(resizeRect),
availableWidth = frameWidth - resizeWidth - 1;
for (var i = 0, count = [buttonsNotHidden count]; i < count; i++)
{
var button = buttonsNotHidden[i],
width = CGRectGetWidth([button frame]);
if (availableWidth > width)
availableWidth -=width;
else
break;
if (_resizeControlIsLeftAligned)
{
[button setFrame:CGRectMake(currentButtonOffset - width, 1, width, height)];
currentButtonOffset -= width - 1;
}
else
{
[button setFrame:CGRectMake(currentButtonOffset, 1, width, height)];
currentButtonOffset += width - 1;
}
[button setValue:normalColor forThemeAttribute:@"bezel-color" inState:CPThemeStateNormal|CPThemeStateBordered];
[button setValue:highlightedColor forThemeAttribute:@"bezel-color" inState:CPThemeStateHighlighted|CPThemeStateBordered];
[button setValue:disabledColor forThemeAttribute:@"bezel-color" inState:CPThemeStateDisabled|CPThemeStateBordered];
[button setValue:textColor forThemeAttribute:@"text-color" inState:CPThemeStateBordered];
// FIXME shouldn't need this
[button setValue:normalColor forThemeAttribute:@"bezel-color" inState:CPThemeStateNormal|CPThemeStateBordered|CPPopUpButtonStatePullsDown];
[button setValue:highlightedColor forThemeAttribute:@"bezel-color" inState:CPThemeStateHighlighted|CPThemeStateBordered|CPPopUpButtonStatePullsDown];
[button setValue:disabledColor forThemeAttribute:@"bezel-color" inState:CPThemeStateDisabled|CPThemeStateBordered|CPPopUpButtonStatePullsDown];
[self addSubview:button];
}
if (_hasResizeControl)
{
var resizeControlView = [self layoutEphemeralSubviewNamed:@"resize-control-view"
positioned:CPWindowAbove
relativeToEphemeralSubviewNamed:nil];
[resizeControlView setAutoresizingMask: _resizeControlIsLeftAligned ? CPViewMaxXMargin : CPViewMinXMargin];
[resizeControlView setBackgroundColor:[self currentValueForThemeAttribute:@"resize-control-color"]];
}
}
- (void)addSubview:(CPView)aSubview
- (void)setFrameSize:(CGSize)aSize
{
[super addSubview:aSubview];
[aSubview setAutoresizingMask:CPViewMinXMargin];
[super setFrameSize:aSize];
[self setNeedsLayout];
}
@end
var CPButtonBarHasResizeControlKey = @"CPButtonBarHasResizeControlKey",
CPButtonBarResizeControlIsLeftAlignedKey = @"CPButtonBarResizeControlIsLeftAlignedKey",
CPButtonBarButtonsKey = @"CPButtonBarButtonsKey";
@implementation CPButtonBar (CPCoding)
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeBool:_hasResizeControl forKey:CPButtonBarHasResizeControlKey];
[aCoder encodeBool:_resizeControlIsLeftAligned forKey:CPButtonBarResizeControlIsLeftAlignedKey];
[aCoder encodeObject:_buttons forKey:CPButtonBarButtonsKey];
}
- (id)initWithCoder:(CPCoder)aCoder
{
if (self = [super initWithCoder:aCoder])
{
_buttons = [aCoder decodeObjectForKey:CPButtonBarButtonsKey] || [];
_hasResizeControl = [aCoder decodeBoolForKey:CPButtonBarHasResizeControlKey];
_resizeControlIsLeftAligned = [aCoder decodeBoolForKey:CPButtonBarResizeControlIsLeftAlignedKey];
}
return self;
}
@end
+23
View File
@@ -61,4 +61,27 @@
return self;
}
- (void)takeStateFromKeyPath:(CPString)aKeyPath ofObjects:(CPArray)objects
{
var count = objects.length,
value = [objects[0] valueForKeyPath:aKeyPath] ? CPOnState : CPOffState;
[self setAllowsMixedState:NO];
[self setState:value];
while (count-- > 1)
{
if (value !== ([objects[count] valueForKeyPath:aKeyPath] ? CPOnState : CPOffState))
{
[self setAllowsMixedState:YES];
[self setState:CPMixedState];
}
}
}
- (void)takeValueFromKeyPath:(CPString)aKeyPath ofObjects:(CPArray)objects
{
[self takeStateFromKeyPath:aKeyPath ofObjects:objects];
}
@end
+42 -12
View File
@@ -120,9 +120,13 @@
[super setBoundsOrigin:aPoint];
var superview = [self superview];
if([superview isKindOfClass:[CPScrollView class]])
var superview = [self superview],
// This is hack to avoid having to import CPScrollView.
// FIXME: Should CPScrollView be finding out about this on its own somehow?
scrollViewClass = objj_getClass("CPScrollView");
if([superview isKindOfClass:scrollViewClass])
[superview reflectScrolledClipView:self];
}
@@ -173,26 +177,52 @@
return;
// ... and we're in a scroll view of course.
var superview = [self superview];
if ([superview isKindOfClass:[CPScrollView class]])
var superview = [self superview],
// This is hack to avoid having to import CPScrollView.
// FIXME: Should CPScrollView be finding out about this on its own somehow?
scrollViewClass = objj_getClass("CPScrollView");
if ([superview isKindOfClass:scrollViewClass])
[superview reflectScrolledClipView:self];
}
- (BOOL)autoscroll:(CPEvent)anEvent
{
var bounds = [self bounds],
eventLocation = [self convertPoint:[anEvent locationInWindow] fromView:nil];
eventLocation = [self convertPoint:[anEvent locationInWindow] fromView:nil],
superview = [self superview],
deltaX = 0,
deltaY = 0;
if (CPRectContainsPoint(bounds, eventLocation))
if (CGRectContainsPoint(bounds, eventLocation))
return NO;
var newRect = CGRectMakeZero();
if (![superview isKindOfClass:[CPScrollView class]] || [superview hasVerticalScroller])
{
if (eventLocation.y < CGRectGetMinY(bounds))
deltaY = CGRectGetMinY(bounds) - eventLocation.y;
else if (eventLocation.y > CGRectGetMaxY(bounds))
deltaY = CGRectGetMaxY(bounds) - eventLocation.y;
if (deltaY < -bounds.size.height)
deltaY = -bounds.size.height;
if (deltaY > bounds.size.height)
deltaY = bounds.size.height;
}
newRect.origin = eventLocation;
newRect.size = CPSizeMake(10, 10);
if (![superview isKindOfClass:[CPScrollView class]] || [superview hasHorizontalScroller])
{
if (eventLocation.x < CGRectGetMinX(bounds))
deltaX = CGRectGetMinX(bounds) - eventLocation.x;
else if (eventLocation.x > CGRectGetMaxX(bounds))
deltaX = CGRectGetMaxX(bounds) - eventLocation.x;
if (deltaX < -bounds.size.width)
deltaX = -bounds.size.width;
if (deltaX > bounds.size.width)
deltaX = bounds.size.width;
}
return [_documentView scrollRectToVisible:newRect];
return [self scrollToPoint:CGPointMake(bounds.origin.x - deltaX, bounds.origin.y - deltaY)];
}
@end
+147 -105
View File
@@ -30,16 +30,16 @@
@import "CPCollectionViewItem.j"
/*!
/*!
@ingroup appkit
@class CPCollectionView
This class displays an array as a grid of objects, where each object is represented by a view.
The view is controlled by creating a CPCollectionViewItem and specifying its view, then
This class displays an array as a grid of objects, where each object is represented by a view.
The view is controlled by creating a CPCollectionViewItem and specifying its view, then
setting that item as the collection view prototype.
@par Delegate Methods
@delegate -(void)collectionViewDidChangeSelection:(CPCollectionView)collectionView;
Called when the selection in the collection view has changed.
@param collectionView the collection view who's selection changed
@@ -67,35 +67,35 @@
{
CPArray _content;
CPArray _items;
CPData _itemData;
CPCollectionViewItem _itemPrototype;
CPCollectionViewItem _itemForDragging;
CPMutableArray _cachedItems;
unsigned _maxNumberOfRows;
unsigned _maxNumberOfColumns;
CGSize _minItemSize;
CGSize _maxItemSize;
CPArray _backgroundColors;
float _tileWidth;
BOOL _isSelectable;
BOOL _allowsMultipleSelection;
BOOL _allowsEmptySelection;
CPIndexSet _selectionIndexes;
CGSize _itemSize;
float _horizontalMargin;
float _verticalMargin;
unsigned _numberOfRows;
unsigned _numberOfColumns;
id _delegate;
CPEvent _mouseDownEvent;
@@ -104,14 +104,14 @@
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
_items = [];
_content = [];
_cachedItems = [];
_itemSize = CGSizeMakeZero();
_minItemSize = CGSizeMakeZero();
_maxItemSize = CGSizeMakeZero();
@@ -120,12 +120,12 @@
_verticalMargin = 5.0;
_tileWidth = -1.0;
_selectionIndexes = [CPIndexSet indexSet];
_allowsEmptySelection = YES;
_isSelectable = YES;
}
return self;
}
@@ -196,8 +196,8 @@
// Setting the Content
/*!
Sets the content of the collection view to the content in \c anArray.
This array can be of any type, and each element will be passed to the \c -setRepresentedObject: method.
Sets the content of the collection view to the content in \c anArray.
This array can be of any type, and each element will be passed to the \c -setRepresentedObject: method.
It's the responsibility of your custom collection view item to interpret the object.
@param anArray the content array
*/
@@ -205,9 +205,9 @@
{
if (_content == anArray)
return;
_content = anArray;
[self reloadContent];
}
@@ -236,13 +236,13 @@
{
if (_isSelectable == isSelectable)
return;
_isSelectable = isSelectable;
if (!_isSelectable)
{
var index = CPNotFound;
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound)
[_items[index] setSelected:NO];
}
@@ -299,19 +299,19 @@
{
if (_selectionIndexes == anIndexSet || !_isSelectable)
return;
var index = CPNotFound;
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound)
[_items[index] setSelected:NO];
_selectionIndexes = anIndexSet;
var index = CPNotFound;
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound)
[_items[index] setSelected:YES];
if ([_delegate respondsToSelector:@selector(collectionViewDidChangeSelection:)])
[_delegate collectionViewDidChangeSelection:self]
}
@@ -326,10 +326,10 @@
/* @ignore */
- (void)reloadContent
{
{
// Remove current views
var count = _items.length;
while (count--)
{
[[_items[count] view] removeFromSuperview];
@@ -337,7 +337,7 @@
_cachedItems.push(_items[count]);
}
_items = [];
if (!_itemPrototype || !_content)
@@ -350,7 +350,7 @@
for (; index < count; ++index)
{
_items.push([self newItemForRepresentedObject:_content[index]]);
[self addSubview:[_items[index] view]];
}
@@ -365,49 +365,49 @@
- (void)tile
{
var width = CGRectGetWidth([self bounds]);
if (![_content count] || width == _tileWidth)
return;
// We try to fit as many views per row as possible. Any remaining space is then
// We try to fit as many views per row as possible. Any remaining space is then
// either proportioned out to the views (if their minSize != maxSize) or used as
// margin
var itemSize = CGSizeMakeCopy(_minItemSize);
_numberOfColumns = MAX(1.0, FLOOR(width / itemSize.width));
if (_maxNumberOfColumns > 0)
_numberOfColumns = MIN(_maxNumberOfColumns, _numberOfColumns);
var remaining = width - _numberOfColumns * itemSize.width,
itemsNeedSizeUpdate = NO;
if (remaining > 0 && itemSize.width < _maxItemSize.width)
itemSize.width = MIN(_maxItemSize.width, itemSize.width + FLOOR(remaining / _numberOfColumns));
// When we ONE column and a non-integral width, the FLOORing above can cause the item width to be smaller than the total width.
if (_maxNumberOfColumns == 1 && itemSize.width < _maxItemSize.width && itemSize.width < width)
itemSize.width = MIN(_maxItemSize.width, width);
if (!CGSizeEqualToSize(_itemSize, itemSize))
{
_itemSize = itemSize;
itemsNeedSizeUpdate = YES;
}
var index = 0,
count = _items.length;
if (_maxNumberOfColumns > 0 && _maxNumberOfRows > 0)
count = MIN(count, _maxNumberOfColumns * _maxNumberOfRows);
_numberOfRows = CEIL(count / _numberOfColumns);
_horizontalMargin = FLOOR((width - _numberOfColumns * itemSize.width) / (_numberOfColumns + 1));
var x = _horizontalMargin,
y = -itemSize.height;
for (; index < count; ++index)
{
if (index % _numberOfColumns == 0)
@@ -415,19 +415,28 @@
x = _horizontalMargin;
y += _verticalMargin + itemSize.height;
}
var view = [_items[index] view];
[view setFrameOrigin:CGPointMake(x, y)];
if (itemsNeedSizeUpdate)
[view setFrameSize:_itemSize];
x += itemSize.width + _horizontalMargin;
}
var superview = [self superview],
proposedHeight = y + itemSize.height + _verticalMargin;
if ([superview isKindOfClass:[CPClipView class]])
{
var superviewSize = [superview bounds].size;
proposedHeight = MAX(superviewSize.height, proposedHeight);
}
_tileWidth = width;
[self setFrameSize:CGSizeMake(width, y + itemSize.height + _verticalMargin)];
[self setFrameSize:CGSizeMake(width, proposedHeight)];
_tileWidth = -1.0;
}
@@ -445,9 +454,9 @@
{
if (_maxNumberOfRows == aMaxNumberOfRows)
return;
_maxNumberOfRows = aMaxNumberOfRows;
[self tile];
}
@@ -467,9 +476,9 @@
{
if (_maxNumberOfColumns == aMaxNumberOfColumns)
return;
_maxNumberOfColumns = aMaxNumberOfColumns;
[self tile];
}
@@ -506,9 +515,9 @@
{
if (CGSizeEqualToSize(_minItemSize, aSize))
return;
_minItemSize = CGSizeMakeCopy(aSize);
[self tile];
}
@@ -528,9 +537,9 @@
{
if (CGSizeEqualToSize(_maxItemSize, aSize))
return;
_maxItemSize = CGSizeMakeCopy(aSize);
[self tile];
}
@@ -590,6 +599,14 @@
- (void)mouseDragged:(CPEvent)anEvent
{
var locationInWindow = [anEvent locationInWindow],
mouseDownLocationInWindow = [_mouseDownEvent locationInWindow];
// FIXME: This is because Safari's drag hysteresis is 3px x 3px
if ((ABS(locationInWindow.x - mouseDownLocationInWindow.x) < 3) &&
(ABS(locationInWindow.y - mouseDownLocationInWindow.y) < 3))
return;
if (![_delegate respondsToSelector:@selector(collectionView:dragTypesForItemsAtIndexes:)])
return;
@@ -597,6 +614,10 @@
if (![_selectionIndexes count])
return;
if ([_delegate respondsToSelector:@selector(collectionView:canDragItemsAtIndexes:withEvent:)] &&
![_delegate collectionView:self canDragItemsAtIndexes:_selectionIndexes withEvent:_mouseDownEvent])
return;
// Set up the pasteboard
var dragTypes = [_delegate collectionView:self dragTypesForItemsAtIndexes:_selectionIndexes];
@@ -644,9 +665,9 @@
{
if (_verticalMargin == aVerticalMargin)
return;
_verticalMargin = aVerticalMargin;
[self tile];
}
@@ -676,47 +697,48 @@
return _delegate;
}
- (CPCollectionViewItem)itemAtIndex:(unsigned)anIndex
{
return [_items objectAtIndex:anIndex];
}
- (CGRect)frameForItemAtIndex:(unsigned)anIndex
{
return [[[self itemAtIndex:anIndex] view] frame];
}
- (CGRect)frameForItemsAtIndexes:(CPIndexSet)anIndexSet
{
var indexArray = [],
frame = CGRectNull;
[anIndexSet getIndexes:indexArray maxCount:-1 inIndexRange:nil];
var index = 0,
count = [indexArray count];
for (; index < count; ++index)
frame = CGRectUnion(frame, [self frameForItemAtIndex:indexArray[index]]);
return frame;
}
@end
@implementation CPCollectionView (KeyboardInteraction)
- (CGRect)rectForItemAtIndex:(int)index
{
// Don't re-compute anything just grab the current frame
// This allows subclasses to override tile without messing this up.
return [[_items[index] view] frame];
}
- (CGRect)rectForItemsAtIndexes:(CPIndexSet)indexSet
{
var indexArray = [],
rect = nil;
[indexSet getIndexes:indexArray maxCount:-1 inIndexRange:nil];
for (var i = 0, count = indexArray.length; i < count; ++i)
{
var index = indexArray[i];
if (rect == nil)
rect = [self rectForItemAtIndex:index];
else
rect = CGRectUnion(rect, [self rectForItemAtIndex:index]);
}
return rect;
}
- (void)_scrollToSelection
{
var rect = [self rectForItemsAtIndexes:[self selectionIndexes]];
if (rect)
[self scrollRectToVisible:rect];
var frame = [self frameForItemsAtIndexes:[self selectionIndexes]];
if (!CGRectIsNull(frame))
[self scrollRectToVisible:frame];
}
- (void)moveLeft:(id)sender
{
var index = [[self selectionIndexes] firstIndex];
if (index === CPNotFound)
if (index === CPNotFound)
index = [[self items] count];
index = MAX(index - 1, 0);
@@ -744,7 +766,7 @@
- (void)moveUp:(id)sender
{
var index = [[self selectionIndexes] firstIndex];
if (index == CPNotFound)
if (index == CPNotFound)
index = [[self items] count];
index = MAX(0, index - [self numberOfColumns]);
@@ -753,7 +775,7 @@
[self _scrollToSelection];
}
- (void)deleteBackwards:(id)sender
- (void)deleteBackward:(id)sender
{
if ([[self delegate] respondsToSelector:@selector(collectionView:shouldDeleteItemsAtIndexes:)])
{
@@ -775,6 +797,26 @@
@end
@implementation CPCollectionView (Deprecated)
- (CGRect)rectForItemAtIndex:(int)anIndex
{
_CPReportLenientDeprecation([self class], _cmd, @selector(frameForItemAtIndex:));
// Don't re-compute anything just grab the current frame
// This allows subclasses to override tile without messing this up.
return [self frameForItemAtIndex:anIndex];
}
- (CGRect)rectForItemsAtIndexes:(CPIndexSet)anIndexSet
{
_CPReportLenientDeprecation([self class], _cmd, @selector(frameForItemsAtIndexes:));
return [self frameForItemsAtIndexes:anIndexSet];
}
@end
var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
CPCollectionViewMaxItemSizeKey = @"CPCollectionViewMaxItemSizeKey",
CPCollectionViewVerticalMarginKey = @"CPCollectionViewVerticalMarginKey",
@@ -796,20 +838,20 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
_cachedItems = [];
_itemSize = CGSizeMakeZero();
_minItemSize = [aCoder decodeSizeForKey:CPCollectionViewMinItemSizeKey] || CGSizeMakeZero();
_maxItemSize = [aCoder decodeSizeForKey:CPCollectionViewMaxItemSizeKey] || CGSizeMakeZero();
_verticalMargin = [aCoder decodeFloatForKey:CPCollectionViewVerticalMarginKey];
_isSelectable = [aCoder decodeBoolForKey:CPCollectionViewSelectableKey];
[self setBackgroundColors:[aCoder decodeObjectForKey:CPCollectionViewBackgroundColorsKey]];
_tileWidth = -1.0;
_selectionIndexes = [CPIndexSet indexSet];
_allowsEmptySelection = YES;
}
@@ -822,12 +864,12 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
if (!CGSizeEqualToSize(_minItemSize, CGSizeMakeZero()))
[aCoder encodeSize:_minItemSize forKey:CPCollectionViewMinItemSizeKey];
if (!CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero()))
[aCoder encodeSize:_maxItemSize forKey:CPCollectionViewMaxItemSizeKey];
[aCoder encodeBool:_isSelectable forKey:CPCollectionViewSelectableKey];
[aCoder encodeFloat:_verticalMargin forKey:CPCollectionViewVerticalMarginKey];
[aCoder encodeObject:_backgroundColors forKey:CPCollectionViewBackgroundColorsKey];
+11 -57
View File
@@ -437,51 +437,16 @@ var cachedBlackColor,
if (self)
{
_components = components;
if (!CPFeatureIsCompatible(CPCSSRGBAFeature) && _components[3] != 1.0 && window.Base64 && window.CRC32)
{
var bytes = [0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x8,0x3,0x0,0x0,0x0,0x28,0xcb,0x34,0xbb,0x0,0x0,0x3,0x0,0x50,0x4c,0x54,0x45,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x17,0x89,0x99,0x55,0x0,0x0,0x0,0x1,0x74,0x52,0x4e,0x53,0x0,0x40,0xe6,0xd8,0x66,0x0,0x0,0x0,0x10,0x49,0x44,0x41,0x54,0x78,0xda,0x62,0x60,0x0,0x0,0x0,0x0,0xff,0xff,0x3,0x0,0x0,0x2,0x0,0x1,0x24,0x7f,0x24,0xf1,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82,0xff];
var r_off = 41;
var g_off = 42;
var b_off = 43;
var a_off = 821;
var plte_crc_off = 809;
var trns_crc_off = 822;
var plte_type_off = 37;
var trns_type_off = 817;
bytes[r_off] = Math.round(_components[0]*255);
bytes[g_off] = Math.round(_components[1]*255);
bytes[b_off] = Math.round(_components[2]*255);
bytes[a_off] = Math.round(_components[3]*255);
// calculate new CRCs
var new_plte_crc = integerToBytes(CRC32.getCRC(bytes, plte_type_off, 4+768), 4);
var new_trns_crc = integerToBytes(CRC32.getCRC(bytes, trns_type_off, 4+1), 4);
// overwrite old CRCs with new ones
for (var i = 0; i < 4; i++)
{
bytes[plte_crc_off+i] = new_plte_crc[i];
bytes[trns_crc_off+i] = new_trns_crc[i];
}
// Base64 encode, strip whitespace and build data URL
var base64image = Base64.encode(bytes); //.replace(/[\s]/g, "");
_cssString = "url(\"data:image/png;base64," + base64image + "\")";
}
else
{
var hasAlpha = CPFeatureIsCompatible(CPCSSRGBAFeature) && _components[3] != 1.0;
_cssString = (hasAlpha ? "rgba(" : "rgb(") +
parseInt(_components[0] * 255.0) + ", " +
parseInt(_components[1] * 255.0) + ", " +
parseInt(_components[2] * 255.0) +
(hasAlpha ? (", " + _components[3]) : "") + ")";
}
var hasAlpha = CPFeatureIsCompatible(CPCSSRGBAFeature) && _components[3] != 1.0;
_cssString = (hasAlpha ? "rgba(" : "rgb(") +
parseInt(_components[0] * 255.0) + ", " +
parseInt(_components[1] * 255.0) + ", " +
parseInt(_components[2] * 255.0) +
(hasAlpha ? (", " + _components[3]) : "") + ")";
}
return self;
}
@@ -494,6 +459,7 @@ var cachedBlackColor,
{
_patternImage = anImage;
_cssString = "url(\"" + [_patternImage filename] + "\")";
_components = [0.0, 0.0, 0.0, 1.0];
}
return self;
@@ -736,7 +702,7 @@ var CPColorComponentsKey = @"CPColorComponentsKey",
var hexCharacters = "0123456789ABCDEF";
// HACK: prevent these from becoming globals. workaround for obj-j "function foo(){}" behavior
var hexToRGB, integerToBytes, rgbToHex, byteToHex;
var hexToRGB, rgbToHex, byteToHex;
/*!
Used for the CPColor \c +colorWithHexString: implementation
@@ -764,18 +730,6 @@ function hexToRGB(hex)
return [red, green, blue, 1.0];
}
function integerToBytes(integer, length) {
if (!length)
length = (integer == 0) ? 1 : Math.round((Math.log(integer)/Math.log(2))/8+0.5);
var bytes = new Array(length);
for (var i = length-1; i >= 0; i--) {
bytes[i] = integer & 255;
integer = integer >> 8
}
return bytes;
}
function rgbToHex(r,g,b) {
return byteToHex(r) + byteToHex(g) + byteToHex(b);
}
+7 -1
View File
@@ -231,11 +231,17 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
- (void)mouseDown:(CPEvent)anEvent
{
if (![self isEnabled])
return;
[self drawBezelWithHighlight:YES];
}
- (void)mouseDragged:(CPEvent)anEvent
{
if (![self isEnabled])
return;
[self drawBezelWithHighlight:CGRectContainsPoint([self bounds], [self convertPoint:[anEvent locationInWindow] fromView:nil])];
}
@@ -243,7 +249,7 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
{
[self drawBezelWithHighlight:NO];
if (!CGRectContainsPoint([self bounds], [self convertPoint:[anEvent locationInWindow] fromView:nil]))
if (!CGRectContainsPoint([self bounds], [self convertPoint:[anEvent locationInWindow] fromView:nil]) || ![self isEnabled])
return;
[self activate:YES];
+1 -3
View File
@@ -65,8 +65,6 @@ CPInputTypeCanBeChangedFeature = 1 << 25;
CPHTML5DragAndDropSourceYOffBy1 = 1 << 26;
var USER_AGENT = "",
PLATFORM_ENGINE = CPUnknownBrowserEngine,
PLATFORM_FEATURES = 0;
@@ -75,7 +73,7 @@ var USER_AGENT = "",
PLATFORM_FEATURES |= CPInputTypeCanBeChangedFeature;
if (typeof window != "undfined" && typeof window.navigator != "undefined")
if (typeof window !== "undefined" && typeof window.navigator !== "undefined")
USER_AGENT = window.navigator.userAgent;
// Opera
+2 -2
View File
@@ -488,10 +488,10 @@ var CPDocumentUntitledCount = 0;
[_writeRequest setValue:@"close" forHTTPHeaderField:@"Connection"];
if (aSaveOperation == CPSaveOperation)
if (aSaveOperation === CPSaveOperation)
[_writeRequest setValue:@"true" forHTTPHeaderField:@"x-cappuccino-overwrite"];
if (aSaveOperation != CPSaveToOperation)
if (aSaveOperation !== CPSaveToOperation)
[self updateChangeCount:CPChangeCleared];
// FIXME: Oh man is this every looking for trouble, we need to handle login at the Cappuccino level, with HTTP Errors.
+96 -33
View File
@@ -40,29 +40,10 @@ CPDragOperationEvery = -1;
#define DRAGGING_WINDOW(anObject) ([anObject isKindOfClass:[CPWindow class]] ? anObject : [anObject window])
var CPDragServerPreviousEvent = nil,
CPDragServerAutoscrollInterval = nil;
/*
var CPDragServerAutoscroll = function()
{
[CPDragServerSource autoscroll:CPDragServerPreviousEvent];
}
var CPDragServerPreviousEvent = nil,
CPDragServerPeriodicUpdateInterval = 0.05;
if (CPDragServerAutoscrollInterval === nil)
{
if ([CPDragServerSource respondsToSelector:@selector(autoscroll:)])
CPDragServerAutoscrollInterval = setInterval(CPDragServerAutoscroll, 100);
}
CPDragServerPreviousEvent = anEvent;
if (CPDragServerAutoscrollInterval !== nil)
clearInterval(CPDragServerAutoscrollInterval);
CPDragServerAutoscrollInterval = nil;
*/
var CPSharedDragServer = nil;
var CPSharedDragServer = nil;
var CPDragServerSource = nil;
var CPDragServerDraggingInfo = nil;
@@ -127,7 +108,7 @@ var CPDragServerDraggingInfo = nil;
@end
var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
CPDraggingSource_draggedImage_endAt_operation_ = 1 << 1,
CPDraggingSource_draggedImage_endedAt_operation_ = 1 << 1,
CPDraggingSource_draggedView_movedTo_ = 1 << 2,
CPDraggingSource_draggedView_endedAt_operation_ = 1 << 3;
@@ -150,10 +131,13 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
CGPoint _draggingLocation;
id _draggingDestination;
BOOL _draggingDestinationWantsPeriodicUpdates;
CGPoint _startDragLocation;
BOOL _shouldSlideBack;
unsigned _dragOperation;
CPTimer _draggingUpdateTimer;
}
/*
@@ -234,6 +218,9 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
- (CPDragOperation)draggingUpdatedInPlatformWindow:(CPPlatformWindow)aPlatformWindow location:(CGPoint)aLocation
{
[_draggingUpdateTimer invalidate];
_draggingUpdateTimer = nil;
var dragOperation = CPDragOperationCopy;
// We have to convert base to bridge since the drag event comes from the source window, not the drag window.
var draggingDestination = [aPlatformWindow _dragHitTest:aLocation pasteboard:[CPDragServerDraggingInfo draggingPasteboard]];
@@ -243,31 +230,95 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
if(draggingDestination !== _draggingDestination)
{
if (_draggingDestination && [_draggingDestination respondsToSelector:@selector(draggingExited:)])
if ([_draggingDestination respondsToSelector:@selector(draggingExited:)])
[_draggingDestination draggingExited:CPDragServerDraggingInfo];
_draggingDestination = draggingDestination;
if (_draggingDestination && [_draggingDestination respondsToSelector:@selector(draggingEntered:)])
if ([_draggingDestination respondsToSelector:@selector(wantsPeriodicDraggingUpdates)])
_draggingDestinationWantsPeriodicUpdates = [_draggingDestination wantsPeriodicDraggingUpdates];
else
_draggingDestinationWantsPeriodicUpdates = YES;
if ([_draggingDestination respondsToSelector:@selector(draggingEntered:)])
dragOperation = [_draggingDestination draggingEntered:CPDragServerDraggingInfo];
}
else if (_draggingDestination && [_draggingDestination respondsToSelector:@selector(draggingUpdated:)])
else if ([_draggingDestination respondsToSelector:@selector(draggingUpdated:)])
dragOperation = [_draggingDestination draggingUpdated:CPDragServerDraggingInfo];
if (!_draggingDestination)
dragOperation = CPDragOperationNone;
else
{
if (_draggingDestinationWantsPeriodicUpdates)
_draggingUpdateTimer = [CPTimer scheduledTimerWithTimeInterval:CPDragServerPeriodicUpdateInterval
target:self
selector:@selector(_sendPeriodicDraggingUpdate:)
userInfo:[CPDictionary dictionaryWithJSObject:{platformWindow:aPlatformWindow, location:aLocation}]
repeats:NO];
var scrollView = [_draggingDestination isKindOfClass:[CPView class]] ? [_draggingDestination enclosingScrollView] : nil;
if (scrollView)
{
var contentView = [scrollView contentView],
bounds = [contentView bounds],
insetBounds = CGRectInset(bounds, 10, 10)
eventLocation = [contentView convertPoint:_draggingLocation fromView:nil],
deltaX = 0,
deltaY = 0;
if (!CGRectContainsPoint(insetBounds, eventLocation))
{
if ([scrollView hasVerticalScroller])
{
if (eventLocation.y < CGRectGetMinY(insetBounds))
deltaY = CGRectGetMinY(insetBounds) - eventLocation.y;
else if (eventLocation.y > CGRectGetMaxY(insetBounds))
deltaY = CGRectGetMaxY(insetBounds) - eventLocation.y;
if (deltaY < -insetBounds.size.height)
deltaY = -insetBounds.size.height;
if (deltaY > insetBounds.size.height)
deltaY = insetBounds.size.height;
}
if ([scrollView hasHorizontalScroller])
{
if (eventLocation.x < CGRectGetMinX(insetBounds))
deltaX = CGRectGetMinX(insetBounds) - eventLocation.x;
else if (eventLocation.x > CGRectGetMaxX(insetBounds))
deltaX = CGRectGetMaxX(insetBounds) - eventLocation.x;
if (deltaX < -insetBounds.size.width)
deltaX = -insetBounds.size.width;
if (deltaX > insetBounds.size.width)
deltaX = insetBounds.size.width;
}
[contentView scrollToPoint:CGPointMake(bounds.origin.x - deltaX, bounds.origin.y - deltaY)];
}
}
}
return dragOperation;
}
- (void)_sendPeriodicDraggingUpdate:(CPTimer)aTimer
{
var userInfo = [aTimer userInfo];
_dragOperation = [self draggingUpdatedInPlatformWindow:[userInfo objectForKey:@"platformWindow"]
location:[userInfo objectForKey:@"location"]];
}
- (void)draggingEndedInPlatformWindow:(CPPlatformWindow)aPlatformWindow globalLocation:(CGPoint)aLocation operation:(CPDragOperation)anOperation
{
[_draggingUpdateTimer invalidate];
_draggingUpdateTimer = nil;
[_draggedView removeFromSuperview];
if (![CPPlatform supportsDragAndDrop])
[_draggedWindow orderOut:self];
if (_implementedDraggingSourceMethods & CPDraggingSource_draggedImage_endAt_operation_)
if (_implementedDraggingSourceMethods & CPDraggingSource_draggedImage_endedAt_operation_)
[_draggingSource draggedImage:[_draggedView image] endedAt:aLocation operation:anOperation];
else if (_implementedDraggingSourceMethods & CPDraggingSource_draggedView_endedAt_operation_)
[_draggingSource draggedView:_draggedView endedAt:aLocation operation:anOperation];
@@ -342,8 +393,8 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
if ([_draggingSource respondsToSelector:@selector(draggedImage:movedTo:)])
_implementedDraggingSourceMethods |= CPDraggingSource_draggedImage_movedTo_;
if ([_draggingSource respondsToSelector:@selector(draggedImage:endAt:operation:)])
_implementedDraggingSourceMethods |= CPDraggingSource_draggedImage_endAt_operation_;
if ([_draggingSource respondsToSelector:@selector(draggedImage:endedAt:operation:)])
_implementedDraggingSourceMethods |= CPDraggingSource_draggedImage_endedAt_operation_;
}
else
{
@@ -404,13 +455,25 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
// Stop tracking events.
return;
}
[self draggingSourceUpdatedWithGlobalLocation:platformWindowLocation];
_dragOperation = [self draggingUpdatedInPlatformWindow:platformWindow location:platformWindowLocation];
else if (type === CPKeyDown)
{
var keyCode = [anEvent keyCode];
if (keyCode === CPEscapeKeyCode)
{
_dragOperation = CPDragOperationNone;
[self draggingEndedInPlatformWindow:platformWindow globalLocation:CGPointMakeZero() operation:_dragOperation];
return;
}
}
else
{
[self draggingSourceUpdatedWithGlobalLocation:platformWindowLocation];
_dragOperation = [self draggingUpdatedInPlatformWindow:platformWindow location:platformWindowLocation];
}
// If we're not a mouse up, then we're going to want to grab the next event.
[CPApp setTarget:self selector:@selector(trackDragging:)
forNextEventMatchingMask:CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask
forNextEventMatchingMask:CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPKeyDownMask
untilDate:nil inMode:0 dequeue:NO];
}
+5 -2
View File
@@ -128,7 +128,7 @@ var _CPEventPeriodicEventPeriod = 0,
BOOL _isARepeat;
unsigned _keyCode;
DOMEvent _DOMEvent;
float _deltaX;
float _deltaY;
float _deltaZ;
@@ -345,7 +345,10 @@ var _CPEventPeriodicEventPeriod = 0,
*/
- (int)buttonNumber
{
return _buttonNumber;
if (_type === CPRightMouseDown || _type === CPRightMouseUp || _type === CPRightMouseDragged)
return 1;
return 0;
}
/*!
+1 -1
View File
@@ -51,7 +51,7 @@ var CPSharedFontManager = nil,
// Changing the Default Font Conversion Classes
/*!
Sets the class that will be used to create the applcation's
Sets the class that will be used to create the application's
font manager.
*/
+ (void)setFontManagerFactory:(Class)aClass
+3
View File
@@ -370,7 +370,10 @@ var LEFT_SHADOW_INSET = 3.0,
var images = [CPKeyedUnarchiver unarchiveObjectWithData:[[aSender draggingPasteboard] dataForType:CPImagesPboardType]];
if ([images count])
{
[self setImage:images[0]];
[self sendAction:[self action] to:[self target]];
}
}
@end
+2 -2
View File
@@ -227,8 +227,8 @@ var SelectionColor = nil,
CGContextClosePath(context);
CGContextSetShadowWithColor(context, CGSizeMake(0.0, 1.0), 1.1, _shadowColor);
CGContextSetFillColor(context, _color);
CGContextSetShadowWithColor(context, CGSizeMake(0.0, 1.0), 1.1, _shadowColor || [CPColor whiteColor]);
CGContextSetFillColor(context, _color || [CPColor blackColor]);
CGContextFillPath(context);
}
+17
View File
@@ -703,6 +703,23 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
[self sendAction:[self action] to:[self target]];
}
- (void)takeValueFromKeyPath:(CPString)aKeyPath ofObjects:(CPArray)objects
{
var count = objects.length,
value = [objects[0] valueForKeyPath:aKeyPath];
[self selectItemWithTag:value];
[self setEnabled:YES];
while (count-- > 1)
{
if (value !== [objects[count] valueForKeyPath:aKeyPath])
{
[[self selectedItem] setState:CPOffState];
}
}
}
@end
var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
+18
View File
@@ -152,6 +152,15 @@ CPDownArrowKeyCode = 40;
[_nextResponder performSelector:_cmd withObject:anEvent];
}
/*!
Notifies the receiver that the user has clicked the right mouse down in its area.
@param anEvent contains information about the right click
*/
- (void)rightMouseDown:(CPEvent)anEvent
{
[_nextResponder performSelector:_cmd withObject:anEvent];
}
/*!
Notifies the receiver that the user has initiated a drag
over it. A drag is a mouse movement while the left button is down.
@@ -171,6 +180,15 @@ CPDownArrowKeyCode = 40;
[_nextResponder performSelector:_cmd withObject:anEvent];
}
/*!
Notifies the receiver that the user has released the right mouse button.
@param anEvent contains information about the release
*/
- (void)rightMouseUp:(CPEvent)anEvent
{
[_nextResponder performSelector:_cmd withObject:anEvent];
}
/*!
Notifies the receiver that the user has moved the mouse (with no buttons down).
@param anEvent contains information about the movement
+5 -1
View File
@@ -1,8 +1,8 @@
@import <Foundation/CPObject.j>
#import "CoreGraphics/CGGeometry.h"
#import "Platform/Platform.h"
@implementation CPScreen : CPObject
{
@@ -10,7 +10,11 @@
- (CGRect)visibleFrame
{
#if PLATFORM(DOM)
return _CGRectMake(window.screen.availLeft, window.screen.availTop, window.screen.availWidth, window.screen.availHeight);
#else
return _CGRectMakeZero();
#endif
}
@end
+31 -10
View File
@@ -445,9 +445,7 @@
- (CPView)_headerView
{
var headerClipViewSubviews = [_headerClipView subviews];
return [headerClipViewSubviews count] ? headerClipViewSubviews[0] : nil;
return [_headerClipView documentView];
}
- (CGRect)_cornerViewFrame
@@ -670,15 +668,32 @@
*/
- (void)scrollWheel:(CPEvent)anEvent
{
var documentFrame = [[self documentView] frame],
contentBounds = [_contentView bounds];
[self _respondToScrollWheelEventWithDeltaX:[anEvent deltaX] * _horizontalLineScroll
deltaY:[anEvent deltaY] * _verticalLineScroll];
}
- (void)_respondToScrollWheelEventWithDeltaX:(float)deltaX deltaY:(float)deltaY
{
var documentFrame = [[self documentView] frame],
contentBounds = [_contentView bounds],
contentFrame = [_contentView frame],
enclosingScrollView = [self enclosingScrollView],
extraX = 0,
extraY = 0;
// We want integral bounds!
contentBounds.origin.x = ROUND(contentBounds.origin.x + [anEvent deltaX] * _horizontalLineScroll);
contentBounds.origin.y = ROUND(contentBounds.origin.y + [anEvent deltaY] * _verticalLineScroll);
contentBounds.origin.x = ROUND(contentBounds.origin.x + deltaX);
contentBounds.origin.y = ROUND(contentBounds.origin.y + deltaY);
[_contentView scrollToPoint:contentBounds.origin];
[_headerClipView scrollToPoint:CGPointMake(contentBounds.origin.x, 0.0)];
var constrainedOrigin = [_contentView constrainScrollPoint:CGPointCreateCopy(contentBounds.origin)];
extraX = ((contentBounds.origin.x - constrainedOrigin.x) / _horizontalLineScroll) * [enclosingScrollView horizontalLineScroll];
extraY = ((contentBounds.origin.y - constrainedOrigin.y) / _verticalLineScroll) * [enclosingScrollView verticalLineScroll];
[_contentView scrollToPoint:constrainedOrigin];
[_headerClipView scrollToPoint:CGPointMake(constrainedOrigin.x, 0.0)];
if (extraX || extraY)
[enclosingScrollView _respondToScrollWheelEventWithDeltaX:extraX deltaY:extraY];
}
- (void)keyDown:(CPEvent)anEvent
@@ -759,7 +774,13 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
_contentView = [aCoder decodeObjectForKey:CPScrollViewContentViewKey];
_headerClipView = [aCoder decodeObjectForKey:CPScrollViewHeaderClipViewKey];
if (!_headerClipView)
{
_headerClipView = [[CPClipView alloc] init];
[self addSubview:_headerClipView];
}
_verticalScroller = [aCoder decodeObjectForKey:CPScrollViewVScrollerKey];
_horizontalScroller = [aCoder decodeObjectForKey:CPScrollViewHScrollerKey];
+2 -3
View File
@@ -235,7 +235,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
*/
- (void)checkSpaceForParts
{
var bounds = [self bounds];
var bounds = [self bounds];
// Assume we won't be needing the arrows.
if (_knobProportion === 1.0)
@@ -290,8 +290,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
_partRects[CPScrollerDecrementLine] = _CGRectMakeZero();
_partRects[CPScrollerKnobSlot] = _CGRectMake(trackInset.left, 0, width - trackInset.left - trackInset.right, height);
}
}
}
else
{
var decrementLineSize = [self currentValueForThemeAttribute:"decrement-line-size"],
+19 -15
View File
@@ -63,10 +63,10 @@ var CPSearchFieldSearchImage = nil,
return;
var bundle = [CPBundle bundleForClass:self];
CPSearchFieldSearchImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldSearch.png"]];
CPSearchFieldFindImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldFind.png"]];
CPSearchFieldCancelImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancel.png"]];
CPSearchFieldCancelPressedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancelPressed.png"]];
CPSearchFieldSearchImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldSearch.png"] size:CGSizeMake(25, 22)];
CPSearchFieldFindImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldFind.png"] size:CGSizeMake(25, 22)];
CPSearchFieldCancelImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancel.png"] size:CGSizeMake(22, 22)];
CPSearchFieldCancelPressedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancelPressed.png"] size:CGSizeMake(22, 22)];
}
- (id)initWithFrame:(CGRect)frame
@@ -97,13 +97,13 @@ var CPSearchFieldSearchImage = nil,
[self setEditable:YES];
[self setDelegate:self];
_cancelButton = [[CPButton alloc] initWithFrame:CPMakeRect(frame.size.width - 27,(frame.size.height-22)/2,22,22)];
_cancelButton = [[CPButton alloc] initWithFrame:CGRectMake(frame.size.width - 27,(frame.size.height-22)/2,22,22)];
[self resetCancelButton];
[_cancelButton setHidden:YES];
[_cancelButton setAutoresizingMask:CPViewMinXMargin];
[self addSubview:_cancelButton];
_searchButton = [[CPButton alloc] initWithFrame:CPMakeRect(5,(frame.size.height-25)/2,25,25)];
_searchButton = [[CPButton alloc] initWithFrame:CGRectMake(5,(frame.size.height-25)/2,25,25)];
[self resetSearchButton];
[self addSubview:_searchButton];
}
@@ -664,9 +664,7 @@ var CPSearchFieldSearchImage = nil,
@end
var CPSearchButtonKey = @"CPSearchButtonKey",
CPCancelButtonKey = @"CPCancelButtonKey",
CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
CPSendsWholeSearchStringKey = @"CPSendsWholeSearchStringKey",
CPSendsSearchStringImmediatelyKey = @"CPSendsSearchStringImmediatelyKey",
CPMaximumRecentsKey = @"CPMaximumRecentsKey",
@@ -676,10 +674,16 @@ var CPSearchButtonKey = @"CPSearchButtonKey",
- (void)encodeWithCoder:(CPCoder)coder
{
[super encodeWithCoder:coder];
[coder encodeObject:_searchButton forKey:CPSearchButtonKey];
[coder encodeObject:_cancelButton forKey:CPCancelButtonKey];
[_searchButton removeFromSuperview];
[_cancelButton removeFromSuperview];
[super encodeWithCoder:coder];
if (_searchButton)
[self addSubview:_searchButton];
if (_cancelButton)
[self addSubview:_cancelButton];
[coder encodeBool:_sendsWholeSearchString forKey:CPSendsWholeSearchStringKey];
[coder encodeBool:_sendsSearchStringImmediately forKey:CPSendsSearchStringImmediatelyKey];
[coder encodeInt:_maximumRecents forKey:CPMaximumRecentsKey];
@@ -694,8 +698,8 @@ var CPSearchButtonKey = @"CPSearchButtonKey",
{
if (self = [super initWithCoder:coder])
{
_searchButton = [coder decodeObjectForKey:CPSearchButtonKey];
_cancelButton = [coder decodeObjectForKey:CPCancelButtonKey];
[self _initWithFrame:[self frame]];
_recentsAutosaveName = [coder decodeObjectForKey:CPRecentsAutosaveNameKey];
_sendsWholeSearchString = [coder decodeBoolForKey:CPSendsWholeSearchStringKey];
_sendsSearchStringImmediately = [coder decodeBoolForKey:CPSendsSearchStringImmediatelyKey];
+12
View File
@@ -396,6 +396,18 @@ CPCircularSlider = 1;
_sendActionOn &= ~CPLeftMouseDraggedMask;
}
- (void)takeValueFromKeyPath:(CPString)aKeyPath ofObjects:(CPArray)objects
{
var count = objects.length,
value = [objects[0] valueForKeyPath:aKeyPath];
[self setObjectValue:value];
while (count-- > 1)
if (value !== ([objects[count] valueForKeyPath:aKeyPath]))
return [self setFloatValue:1.0];
}
@end
var CPSliderMinValueKey = "CPSliderMinValueKey",
+193 -59
View File
@@ -20,6 +20,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPButtonBar.j"
@import "CPImage.j"
@import "CPView.j"
@@ -43,18 +44,20 @@ var CPSplitViewHorizontalImage = nil,
id _delegate;
BOOL _isVertical;
BOOL _isPaneSplitter;
int _currentDivider;
float _initialOffset;
CPString _originComponent;
CPString _sizeComponent;
CPArray _DOMDividerElements;
CPString _dividerImagePath;
int _drawingDivider;
BOOL _needsResizeSubviews;
CPArray _buttonBars;
}
/*
@@ -77,10 +80,11 @@ var CPSplitViewHorizontalImage = nil,
_currentDivider = CPNotFound;
_DOMDividerElements = [];
_buttonBars = [];
[self _setVertical:YES];
}
return self;
}
@@ -98,7 +102,7 @@ var CPSplitViewHorizontalImage = nil,
{
if (![self _setVertical:shouldBeVertical])
return;
// Just re-adjust evenly.
var frame = [self frame],
dividerThickness = [self dividerThickness];
@@ -125,13 +129,13 @@ var CPSplitViewHorizontalImage = nil,
- (BOOL)_setVertical:(BOOL)shouldBeVertical
{
var changed = (_isVertical != shouldBeVertical);
_isVertical = shouldBeVertical;
_originComponent = [self isVertical] ? "x" : "y";
_sizeComponent = [self isVertical] ? "width" : "height";
_dividerImagePath = [self isVertical] ? [CPSplitViewVerticalImage filename] : [CPSplitViewHorizontalImage filename];
return changed;
}
@@ -150,7 +154,7 @@ var CPSplitViewHorizontalImage = nil,
if(_DOMDividerElements[_drawingDivider])
[self _setupDOMDivider]
// The divider changes size when pane splitter mode is toggled, so the
// The divider changes size when pane splitter mode is toggled, so the
// subviews need to change size too.
_needsResizeSubviews = YES;
[self setNeedsDisplay:YES];
@@ -209,18 +213,13 @@ var CPSplitViewHorizontalImage = nil,
{
_DOMDividerElements[_drawingDivider] = document.createElement("div");
if(_isVertical)
_DOMDividerElements[_drawingDivider].style.cursor = [[CPCursor resizeLeftRightCursor] _cssString];
else
_DOMDividerElements[_drawingDivider].style.cursor = [[CPCursor resizeUpDownCursor] _cssString];
_DOMDividerElements[_drawingDivider].style.position = "absolute";
_DOMDividerElements[_drawingDivider].style.backgroundRepeat = "repeat";
CPDOMDisplayServerAppendChild(_DOMElement, _DOMDividerElements[_drawingDivider]);
[self _setupDOMDivider];
}
}
CPDOMDisplayServerSetStyleLeftTop(_DOMDividerElements[_drawingDivider], NULL, _CGRectGetMinX(aRect), _CGRectGetMinY(aRect));
CPDOMDisplayServerSetStyleSize(_DOMDividerElements[_drawingDivider], _CGRectGetWidth(aRect), _CGRectGetHeight(aRect));
@@ -256,7 +255,7 @@ var CPSplitViewHorizontalImage = nil,
var subviews = [self subviews],
count = subviews.length,
oldSize = CGSizeMakeZero();
if ([self isVertical])
{
oldSize.width += [self dividerThickness] * (count - 1);
@@ -279,15 +278,25 @@ var CPSplitViewHorizontalImage = nil,
var frame = [_subviews[anIndex] frame],
startPosition = frame.origin[_originComponent] + frame.size[_sizeComponent],
effectiveRect = [self effectiveRectOfDividerAtIndex:anIndex],
buttonBar = _buttonBars[anIndex],
buttonBarRect = null,
additionalRect = null;
if (buttonBar != null)
{
buttonBarRect = [buttonBar resizeControlFrame];
buttonBarRect.origin = [self convertPoint:buttonBarRect.origin fromView:buttonBar];
}
if ([_delegate respondsToSelector:@selector(splitView:effectiveRect:forDrawnRect:ofDividerAtIndex:)])
effectiveRect = [_delegate splitView:self effectiveRect:effectiveRect forDrawnRect:effectiveRect ofDividerAtIndex:anIndex];
if ([_delegate respondsToSelector:@selector(splitView:additionalEffectiveRectOfDividerAtIndex:)])
additionalRect = [_delegate splitView:self additionalEffectiveRectOfDividerAtIndex:anIndex];
return CGRectContainsPoint(effectiveRect, aPoint) || (additionalRect && CGRectContainsPoint(additionalRect, aPoint));
return CGRectContainsPoint(effectiveRect, aPoint) ||
(additionalRect && CGRectContainsPoint(additionalRect, aPoint)) ||
(buttonBarRect && CGRectContainsPoint(buttonBarRect, aPoint));
}
- (CPView)hitTest:(CGPoint)aPoint
@@ -303,7 +312,7 @@ var CPSplitViewHorizontalImage = nil,
if ([self cursorAtPoint:point hitDividerAtIndex:i])
return self;
}
return [super hitTest:aPoint];
}
@@ -320,12 +329,13 @@ var CPSplitViewHorizontalImage = nil,
if (_currentDivider != CPNotFound)
{
_currentDivider = CPNotFound;
[self _updateResizeCursor:anEvent];
[self _postNotificationDidResize];
}
return;
}
if (type == CPLeftMouseDown)
{
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
@@ -342,7 +352,7 @@ var CPSplitViewHorizontalImage = nil,
if ([anEvent clickCount] == 2 &&
[_delegate respondsToSelector:@selector(splitView:canCollapseSubview:)] &&
[_delegate respondsToSelector:@selector(splitView:shouldCollapseSubview:forDoubleClickOnDividerAtIndex:)])
{
{
var minPosition = [self minPossiblePositionOfDividerAtIndex:i],
maxPosition = [self maxPossiblePositionOfDividerAtIndex:i];
@@ -374,14 +384,16 @@ var CPSplitViewHorizontalImage = nil,
if (_currentDivider === CPNotFound)
return;
}
else if (type == CPLeftMouseDragged && _currentDivider != CPNotFound)
{
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
[self setPosition:(point[_originComponent] + _initialOffset) ofDividerAtIndex:_currentDivider];
// Cursor might change if we reach a resize limit.
[self _updateResizeCursor:anEvent];
}
[CPApp setTarget:self selector:@selector(trackDivider:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
}
@@ -391,13 +403,81 @@ var CPSplitViewHorizontalImage = nil,
[self trackDivider:anEvent];
}
- (void)viewDidMoveToWindow
{
// Enable split view resize cursors. Commented out pending CPTrackingArea implementation.
//[[self window] setAcceptsMouseMovedEvents:YES];
}
- (void)mouseEntered:(CPEvent)anEvent
{
// Tracking code handles cursor by itself.
if (_currentDivider == CPNotFound)
[self _updateResizeCursor:anEvent];
}
- (void)mouseMoved:(CPEvent)anEvent
{
if (_currentDivider == CPNotFound)
[self _updateResizeCursor:anEvent];
}
- (void)mouseExited:(CPEvent)anEvent
{
if (_currentDivider == CPNotFound)
// FIXME: we should use CPCursor push/pop (if previous currentCursor != arrow).
[[CPCursor arrowCursor] set];
}
- (void)_updateResizeCursor:(CPEvent)anEvent
{
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
if ([anEvent type] === CPLeftMouseUp && ![[self window] acceptsMouseMovedEvents])
{
[[CPCursor arrowCursor] set];
return;
}
for (var i = 0, count = [_subviews count] - 1; i < count; i++)
{
// If we are currently tracking, keep the resize cursor active even outside of hit areas.
if (_currentDivider === i || (_currentDivider == CPNotFound && [self cursorAtPoint:point hitDividerAtIndex:i]))
{
var frame = [_subviews[i] frame],
startPosition = frame.origin[_originComponent] + frame.size[_sizeComponent],
canShrink = [self _realPositionForPosition:startPosition-1 ofDividerAtIndex:i] < startPosition,
canGrow = [self _realPositionForPosition:startPosition+1 ofDividerAtIndex:i] > startPosition,
cursor = [CPCursor arrowCursor];
if (_isVertical && canShrink && canGrow)
cursor = [CPCursor resizeLeftRightCursor];
else if (_isVertical && canShrink)
cursor = [CPCursor resizeLeftCursor];
else if (_isVertical && canGrow)
cursor = [CPCursor resizeRightCursor];
else if (canShrink && canGrow)
cursor = [CPCursor resizeUpDownCursor];
else if (canShrink)
cursor = [CPCursor resizeUpCursor];
else if (canGrow)
cursor = [CPCursor resizeDownCursor];
[cursor set];
return;
}
}
[[CPCursor arrowCursor] set];
}
- (float)maxPossiblePositionOfDividerAtIndex:(int)dividerIndex
{
var frame = [_subviews[dividerIndex + 1] frame];
if (dividerIndex + 1 < [_subviews count] - 1)
return frame.origin[_originComponent] + frame.size[_sizeComponent] - [self dividerThickness];
else
else
return [self frame].size[_sizeComponent] - [self dividerThickness];
}
@@ -406,17 +486,15 @@ var CPSplitViewHorizontalImage = nil,
if (dividerIndex > 0)
{
var frame = [_subviews[dividerIndex - 1] frame];
return frame.origin[_originComponent] + frame.size[_sizeComponent] + [self dividerThickness];
}
else
else
return 0;
}
- (void)setPosition:(float)position ofDividerAtIndex:(int)dividerIndex
- (int)_realPositionForPosition:(float)position ofDividerAtIndex:(int)dividerIndex
{
[self _adjustSubviewsWithCalculatedSize];
// not sure where this should override other positions?
if ([_delegate respondsToSelector:@selector(splitView:constrainSplitPosition:ofSubviewAt:)])
position = [_delegate splitView:self constrainSplitPosition:position ofSubviewAt:dividerIndex];
@@ -425,47 +503,56 @@ var CPSplitViewHorizontalImage = nil,
proposedMin = [self minPossiblePositionOfDividerAtIndex:dividerIndex],
actualMax = proposedMax,
actualMin = proposedMin;
if([_delegate respondsToSelector:@selector(splitView:constrainMinCoordinate:ofSubviewAt:)])
actualMin = [_delegate splitView:self constrainMinCoordinate:proposedMin ofSubviewAt:dividerIndex];
if([_delegate respondsToSelector:@selector(splitView:constrainMaxCoordinate:ofSubviewAt:)])
actualMax = [_delegate splitView:self constrainMaxCoordinate:proposedMax ofSubviewAt:dividerIndex];
var frame = [self frame],
viewA = _subviews[dividerIndex],
frameA = [viewA frame],
viewB = _subviews[dividerIndex + 1],
frameB = [viewB frame];
var viewA = _subviews[dividerIndex],
realPosition = MAX(MIN(position, actualMax), actualMin);
var realPosition = MAX(MIN(position, actualMax), actualMin);
if (position < proposedMin + (actualMin - proposedMin) / 2)
if ([_delegate respondsToSelector:@selector(splitView:canCollapseSubview:)])
if ([_delegate splitView:self canCollapseSubview:viewA])
realPosition = proposedMin;
return realPosition;
}
- (void)setPosition:(float)position ofDividerAtIndex:(int)dividerIndex
{
[self _adjustSubviewsWithCalculatedSize];
var realPosition = [self _realPositionForPosition:position ofDividerAtIndex:dividerIndex];
var viewA = _subviews[dividerIndex],
frameA = [viewA frame],
viewB = _subviews[dividerIndex + 1],
frameB = [viewB frame];
frameA.size[_sizeComponent] = realPosition - frameA.origin[_originComponent];
[_subviews[dividerIndex] setFrame:frameA];
frameB.size[_sizeComponent] = frameB.origin[_originComponent] + frameB.size[_sizeComponent] - realPosition - [self dividerThickness];
frameB.origin[_originComponent] = realPosition + [self dividerThickness];
[_subviews[dividerIndex + 1] setFrame:frameB];
[self setNeedsDisplay:YES];
}
- (void)setFrameSize:(CGSize)aSize
{
[self _adjustSubviewsWithCalculatedSize];
[super setFrameSize:aSize];
[self setNeedsDisplay:YES];
}
- (void)resizeSubviewsWithOldSize:(CPSize)oldSize
{
{
if ([_delegate respondsToSelector:@selector(splitView:resizeSubviewsWithOldSize:)])
{
[_delegate splitView:self resizeSubviewsWithOldSize:oldSize];
@@ -473,7 +560,7 @@ var CPSplitViewHorizontalImage = nil,
}
[self _postNotificationWillResize];
var index = 0,
count = [_subviews count],
bounds = [self bounds],
@@ -524,7 +611,7 @@ var CPSplitViewHorizontalImage = nil,
else if (totalSizableSpace && !isSizable)
viewFrame.size[_sizeComponent] = [view frame].size[_sizeComponent];
bounds.origin[_originComponent] += viewFrame.size[_sizeComponent] + dividerThickness;
bounds.origin[_originComponent] += viewFrame.size[_sizeComponent] + dividerThickness;
[view setFrame:viewFrame];
}
@@ -538,7 +625,7 @@ var CPSplitViewHorizontalImage = nil,
[[CPNotificationCenter defaultCenter] removeObserver:_delegate name:CPSplitViewDidResizeSubviewsNotification object:self];
if ([_delegate respondsToSelector:@selector(splitViewWillResizeSubviews:)])
[[CPNotificationCenter defaultCenter] removeObserver:_delegate name:CPSplitViewWillResizeSubviewsNotification object:self];
_delegate = delegate;
if ([_delegate respondsToSelector:@selector(splitViewDidResizeSubviews:)])
@@ -553,6 +640,47 @@ var CPSplitViewHorizontalImage = nil,
object:self];
}
/*!
Set the button bar who's resize control should act as a control for this splitview.
Each divider can have at most one button bar assigned to it, and that button bar must be
a subview of one of the split view's subviews.
Calling this method with nil as the button bar will remove any currently assigned button bar
for the divider at that index. Indexes will not be adjusted as new subviews are added, so you
should usually call this method after adding all the desired subviews to the split view.
This method will automatically configure the hasResizeControl and resizeControlIsLeftAligned
parameters of the button bar, and will override any currently set values.
*/
- (void)setButtonBar:(CPButtonBar)aButtonBar forDividerAtIndex:(unsigned)dividerIndex
{
if (!aButtonBar)
{
_buttonBars[dividerIndex] = nil;
return;
}
var view = [aButtonBar superview],
subview = aButtonBar;
while (view && view !== self)
{
subview = view;
view = [view superview];
}
if (view !== self)
[CPException raise:CPInvalidArgumentException
reason:@"CPSplitView button bar must be a subview of the split view."];
var viewIndex = [[self subviews] indexOfObject:subview];
[aButtonBar setHasResizeControl:YES];
[aButtonBar setResizeControlIsLeftAligned:dividerIndex < viewIndex];
_buttonBars[dividerIndex] = aButtonBar;
}
- (void)_postNotificationWillResize
{
[[CPNotificationCenter defaultCenter] postNotificationName:CPSplitViewWillResizeSubviewsNotification object:self];
@@ -567,7 +695,8 @@ var CPSplitViewHorizontalImage = nil,
var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
CPSplitViewIsVerticalKey = "CPSplitViewIsVerticalKey",
CPSplitViewIsPaneSplitterKey = "CPSplitViewIsPaneSplitterKey";
CPSplitViewIsPaneSplitterKey = "CPSplitViewIsPaneSplitterKey",
CPSplitViewButtonBarsKey = "CPSplitViewButtonBarsKey";
@implementation CPSplitView (CPCoding)
@@ -578,19 +707,21 @@ var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
_currentDivider = CPNotFound;
_DOMDividerElements = [];
_buttonBars = [aCoder decodeObjectForKey:CPSplitViewButtonBarsKey] || [];
_delegate = [aCoder decodeObjectForKey:CPSplitViewDelegateKey];;
_delegate = [aCoder decodeObjectForKey:CPSplitViewDelegateKey];
_isPaneSplitter = [aCoder decodeBoolForKey:CPSplitViewIsPaneSplitterKey];
[self _setVertical:[aCoder decodeBoolForKey:CPSplitViewIsVerticalKey]];
}
return self;
}
@@ -601,9 +732,12 @@ var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
//FIXME how should we handle this?
//[aCoder encodeObject:_buttonBars forKey:CPSplitViewButtonBarsKey];
[aCoder encodeConditionalObject:_delegate forKey:CPSplitViewDelegateKey];
[aCoder encodeBool:_isVertical forKey:CPSplitViewIsVerticalKey];
[aCoder encodeBool:_isPaneSplitter forKey:CPSplitViewIsPaneSplitterKey];
}
+15 -17
View File
@@ -158,21 +158,24 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
CPTableView _tableView @accessors(property=tableView);
}
- (void)initWithFrame:(CGRect)aFrame
- (void)_init
{
_resizedColumn = -1;
_draggedColumn = -1;
_pressedColumn = -1;
_draggedDistance = 0.0;
_lastLocation = nil;
_columnOldWidth = nil;
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 22.0))]];
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
_resizedColumn = -1;
_draggedColumn = -1;
_pressedColumn = -1;
_draggedDistance = 0.0;
_lastLocation = nil;
_columnOldWidth = nil;
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 22.0))]];
}
[self _init];
return self;
}
@@ -479,12 +482,7 @@ var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey";
{
if (self = [super initWithCoder:aCoder])
{
_resizedColumn = -1;
_draggedColumn = -1;
_pressedColumn = -1;
_draggedDistance = 0.0;
_lastLocation = nil;
_columnOldWidth = nil;
[self _init];
_tableView = [aCoder decodeObjectForKey:CPTableHeaderViewTableViewKey];
}
+87 -119
View File
@@ -194,15 +194,17 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
SEL _doubleAction;
unsigned _columnAutoResizingStyle;
int _lastTrackedRowIndex;
CGPoint _originalMouseDownPoint;
BOOL _verticalMotionCanDrag;
unsigned _destinationDragStyle;
BOOL _isSelectingSession;
CPIndexSet _draggedRowIndexes;
_dropOperationDrawingView _dropOperationFeedbackView;
CPDragOperation _dragOperationDefaultMask;
int _retargetedDropRow;
CPDragOperation _retargetedDropOperation;
_CPDropOperationDrawingView _dropOperationFeedbackView;
CPDragOperation _dragOperationDefaultMask;
int _retargetedDropRow;
CPDragOperation _retargetedDropOperation;
BOOL _disableAutomaticResizing @accessors(property=disableAutomaticResizing);
BOOL _lastColumnShouldSnap;
@@ -230,7 +232,6 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
_allowsEmptySelection = YES;
_allowsColumnSelection = NO;
_disableAutomaticResizing = NO;
_tableViewFlags = 0;
//Setting Display Attributes
_selectionHighlightStyle = CPTableViewSelectionHighlightStyleRegular;
@@ -243,32 +244,17 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
_dirtyTableColumnRangeIndex = CPNotFound;
_numberOfHiddenColumns = 0;
_objectValues = { };
_dataViewsForTableColumns = { };
_dataViews= [];
_numberOfRows = 0;
_exposedRows = [CPIndexSet indexSet];
_exposedColumns = [CPIndexSet indexSet];
_cachedDataViews = { };
_intercellSpacing = _CGSizeMake(0.0, 0.0);
_rowHeight = 23.0;
[self setGridColor:[CPColor colorWithHexString:@"dce0e2"]];
[self setGridStyleMask:CPTableViewGridNone];
_headerView = [[CPTableHeaderView alloc] initWithFrame:CGRectMake(0, 0, [self bounds].size.width, _rowHeight)];
[_headerView setTableView:self];
_cornerView = [[_CPCornerView alloc] initWithFrame:CGRectMake(0, 0, [CPScroller scrollerWidth], CGRectGetHeight([_headerView frame]))];
_lastSelectedRow = -1;
_selectedColumnIndexes = [CPIndexSet indexSet];
_selectedRowIndexes = [CPIndexSet indexSet];
_currentHighlightedTableColumn = nil;
_sortDescriptors = [CPArray array];
_draggedRowIndexes = [CPIndexSet indexSet];
_verticalMotionCanDrag = YES;
_isSelectingSession = NO;
@@ -276,16 +262,9 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
_retargetedDropOperation = nil;
_dragOperationDefaultMask = nil;
_destinationDragStyle = CPTableViewDraggingDestinationFeedbackStyleRegular;
_dropOperationFeedbackView = [[_dropOperationDrawingView alloc] initWithFrame:_CGRectMakeZero()];
[self addSubview:_dropOperationFeedbackView];
[_dropOperationFeedbackView setHidden:YES];
[_dropOperationFeedbackView setTableView:self];
_tableDrawView = [[_CPTableDrawView alloc] initWithTableView:self];
[_tableDrawView setBackgroundColor:[CPColor clearColor]];
[self addSubview:_tableDrawView];
[self setBackgroundColor:[CPColor whiteColor]];
[self _init];
}
return self;
@@ -294,8 +273,42 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
// FIX ME: we have a lot of redundent init stuff in initWithFrame: and initWithCoder: we should move it all into here.
- (void)_init
{
_tableViewFlags = 0;
_selectedColumnIndexes = [CPIndexSet indexSet];
_selectedRowIndexes = [CPIndexSet indexSet];
_dropOperationFeedbackView = [[_CPDropOperationDrawingView alloc] initWithFrame:_CGRectMakeZero()];
[_dropOperationFeedbackView setTableView:self];
_lastColumnShouldSnap = NO;
_backgroundColor = [CPColor whiteColor];
if (!_alternatingRowBackgroundColors)
_alternatingRowBackgroundColors = [[CPColor whiteColor], [CPColor colorWithHexString:@"e4e7ff"]];
_tableColumnRanges = [];
_dirtyTableColumnRangeIndex = 0;
_numberOfHiddenColumns = 0;
_objectValues = { };
_dataViewsForTableColumns = { };
_dataViews= [];
_numberOfRows = 0;
_exposedRows = [CPIndexSet indexSet];
_exposedColumns = [CPIndexSet indexSet];
_cachedDataViews = { };
_tableDrawView = [[_CPTableDrawView alloc] initWithTableView:self];
[_tableDrawView setBackgroundColor:[CPColor clearColor]];
[self addSubview:_tableDrawView];
if (!_headerView)
_headerView = [[CPTableHeaderView alloc] initWithFrame:CGRectMake(0, 0, [self bounds].size.width, _rowHeight)];
[_headerView setTableView:self];
if (!_cornerView)
_cornerView = [[_CPCornerView alloc] initWithFrame:CGRectMake(0, 0, [CPScroller scrollerWidth], CGRectGetHeight([_headerView frame]))];
// Gradients for the source list
_sourceListActiveGradient = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), [89.0/255.0, 153.0/255.0, 209.0/255.0,1.0, 33.0/255.0, 94.0/255.0, 208.0/255.0,1.0], [0,1], 2);
@@ -1762,63 +1775,44 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
return YES;
}
- (CPImage)dragImageForRowsWithIndexes:(CPIndexSet)dragRows
tableColumns:(CPArray)theTableColumns
event:(CPEvent)dragEvent
offset:(CPPointPointer)dragImageOffset
- (CPImage)dragImageForRowsWithIndexes:(CPIndexSet)dragRows tableColumns:(CPArray)theTableColumns event:(CPEvent)dragEvent offset:(CPPointPointer)dragImageOffset
{
return [[CPImage alloc] initWithContentsOfFile:@"Frameworks/AppKit/Resources/GenericFile.png" size:CGSizeMake(32,32)];
}
- (CPView)dragViewForRowsWithIndexes:(CPIndexSet)theDraggedRows
tableColumns:(CPArray)theTableColumns
event:(CPEvent)theDragEvent
offset:(CPPoint)dragViewOffset
- (CPView)dragViewForRowsWithIndexes:(CPIndexSet)theDraggedRows tableColumns:(CPArray)theTableColumns event:(CPEvent)theDragEvent offset:(CPPoint)dragViewOffset
{
var bounds = [self bounds],
view = [[CPView alloc] initWithFrame:bounds];
[view setBackgroundColor:[CPColor clearColor]];
[view setAlphaValue:0.7];
// We have to fetch all the data views for the selected rows and columns
// After that we can copy these add them to a transparent drag view and use that drag view
// to make it appear we are dragging images of those rows (as you would do in regular Cocoa)
var firstExposedColumn = [_exposedColumns firstIndex],
firstExposedRow = [_exposedRows firstIndex],
exposedColumnsLength = [_exposedColumns lastIndex] - firstExposedColumn + 1,
exposedRowsLength = [_exposedRows lastIndex] - firstExposedRow + 1,
columns = [],
rows = [];
[_exposedColumns getIndexes:columns maxCount:-1 inIndexRange:CPMakeRange(firstExposedColumn, exposedColumnsLength)];
[theDraggedRows getIndexes:rows maxCount:-1 inIndexRange:CPMakeRange(firstExposedRow, exposedRowsLength)];
var columnIndex = [columns count];
var columnIndex = [theTableColumns count];
while (columnIndex--)
{
var column = columns[columnIndex],
tableColumn = [_tableColumns objectAtIndex:column],
rowIndex = [rows count];
while (rowIndex--)
var tableColumn = [theTableColumns objectAtIndex:columnIndex],
row = [theDraggedRows firstIndex];
while (row !== CPNotFound)
{
var row = rows[rowIndex];
var dataView = [self _newDataViewForRow:row tableColumn:tableColumn];
[dataView setBackgroundColor:[CPColor clearColor]];
[dataView setFrame:[self frameOfDataViewAtColumn:column row:row]];
[dataView setFrame:[self frameOfDataViewAtColumn:columnIndex row:row]];
[dataView setObjectValue:[self _objectValueForTableColumn:tableColumn row:row]];
[view addSubview:dataView];
row = [theDraggedRows indexGreaterThanIndex:row];
}
}
var dragPoint = [self convertPoint:[theDragEvent locationInWindow] fromView:nil];
dragViewOffset.x = CGRectGetWidth(bounds)/2 - dragPoint.x;
dragViewOffset.y = CGRectGetHeight(bounds)/2 - dragPoint.y;
return view;
}
@@ -1840,7 +1834,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
var numberOfRows = [self numberOfRows] + 1;
var reason = @"Attempt to set dropRow=" + row +
" dropOperation=CPTableViewDropOn when [0 - " + numberOfRows + "] is valid range of rows."
[[CPException exceptionWithName:@"Error" reason:reason userInfo:nil] raise];
}
@@ -1896,7 +1890,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
return;
_sortDescriptors = newSortDescriptors;
[self _sendDataSourceSortDescriptorsDidChange:oldSortDescriptors];
}
@@ -2218,14 +2212,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
- (void)drawBackgroundInClipRect:(CGRect)aRect
{
if (!_usesAlternatingRowBackgroundColors)
{
var context = [[CPGraphicsContext currentContext] graphicsPort];
CGContextSetFillColor(context, _backgroundColor);
CGContextFillRect(context, aRect);
return;
}
var rowColors = [self alternatingRowBackgroundColors],
@@ -2459,10 +2446,9 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
for(var c = firstExposedColumn; c < exposedColumnCount; c++)
{
//console.log(columnIndexes);
var colRect = [self rectOfColumn:exposedColumnIndexes[c]],
colX = CGRectGetMaxX(colRect) + 0.5;
//console.log(colX);
CGContextMoveToPoint(context, colX, minY);
CGContextAddLineToPoint(context, colX, maxY);
}
@@ -2586,7 +2572,10 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
{
// Prevent CPControl from eating the mouse events when we are in a drag session
if (![_draggedRowIndexes count])
{
[self autoscroll:anEvent];
[super trackMouse:anEvent];
}
else
[CPApp sendEvent:anEvent];
}
@@ -2654,8 +2643,11 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
}
_isSelectingSession = YES;
if(row >= 0)
if(row >= 0 && row !== _lastTrackedRowIndex)
{
_lastTrackedRowIndex = row;
[self _updateSelectionWithMouseAtRow:row];
}
if ((_implementedDataSourceMethods & CPTableViewDataSource_tableView_setObjectValue_forTableColumn_row_)
&& !_trackingPointMovedOutOfClickSlop)
@@ -2765,7 +2757,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
*/
- (void)draggingExited:(id)sender
{
[_dropOperationFeedbackView setHidden:YES];
[_dropOperationFeedbackView removeFromSuperview];
}
/*
@@ -2781,7 +2773,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
_retargetedDropOperation = nil;
_retargetedDropRow = nil;
_draggedRowIndexes = [CPIndexSet indexSet];
[_dropOperationFeedbackView setHidden:YES];
[_dropOperationFeedbackView removeFromSuperview];
}
/*
@ignore
@@ -2896,14 +2888,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
[_dropOperationFeedbackView setFrame:rect];
[_dropOperationFeedbackView setCurrentRow:row];
[self addSubview:_dropOperationFeedbackView];
// FIXME : Maybe we should do this in a timer outside this method.
// Problem: we don't know when the scroll ends or when the next -draggingUpdated is called.
if (row > 0 && location.y - CGRectGetMinY(exposedClipRect) < _rowHeight)
[self scrollRowToVisible:row - 1];
else if (row < numberOfRows && CGRectGetMaxY(exposedClipRect) - location.y < _rowHeight)
[self scrollRowToVisible:row + 1];
return dragOperation;
}
@@ -2914,7 +2899,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
{
// FIX ME: is there anything else that needs to happen here?
// actual validation is called in dragginUpdated:
[_dropOperationFeedbackView setHidden:YES];
[_dropOperationFeedbackView removeFromSuperview];
return (_implementedDataSourceMethods & CPTableViewDataSource_tableView_validateDrop_proposedRow_proposedDropOperation_);
}
@@ -3071,7 +3056,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
- (void)keyDown:(CPEvent)anEvent
{
[self interpretKeyEvents:[CPArray arrayWithObject:anEvent]];
[self interpretKeyEvents:[anEvent]];
}
- (void)moveDown:(id)sender
@@ -3190,6 +3175,7 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey",
CPTableViewGridColorKey = @"CPTableViewGridColorKey",
CPTableViewGridStyleMaskKey = @"CPTableViewGridStyleMaskKey",
CPTableViewUsesAlternatingBackgroundKey = @"CPTableViewUsesAlternatingBackgroundKey",
CPTableViewAlternatingRowColorsKey = @"CPTableViewAlternatingRowColorsKey",
CPTableViewHeaderViewKey = @"CPTableViewHeaderViewKey",
CPTableViewCornerViewKey = @"CPTableViewCornerViewKey";
@@ -3208,50 +3194,31 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey",
_allowsEmptySelection = [aCoder decodeBoolForKey:CPTableViewEmptySelectionKey];
_allowsColumnSelection = [aCoder decodeBoolForKey:CPTableViewColumnSelectionKey];
_tableViewFlags = 0;
//Setting Display Attributes
_selectionHighlightStyle = CPTableViewSelectionHighlightStyleRegular;
_usesAlternatingRowBackgroundColors = [aCoder decodeBoolForKey:CPTableViewUsesAlternatingBackgroundKey];
[self setAlternatingRowBackgroundColors:[[CPColor whiteColor], [CPColor colorWithHexString:@"e4e7ff"]]];
_tableColumns = [aCoder decodeObjectForKey:CPTableViewTableColumnsKey];
_tableColumns = [aCoder decodeObjectForKey:CPTableViewTableColumnsKey] || [];
[_tableColumns makeObjectsPerformSelector:@selector(setTableView:) withObject:self];
_tableColumnRanges = [];
_dirtyTableColumnRangeIndex = 0;
_numberOfHiddenColumns = 0;
_objectValues = { };
_dataViewsForTableColumns = { };
_dataViews= [];
_numberOfRows = 0;
_exposedRows = [CPIndexSet indexSet];
_exposedColumns = [CPIndexSet indexSet];
_cachedDataViews = { };
_rowHeight = [aCoder decodeFloatForKey:CPTableViewRowHeightKey];
if ([aCoder containsValueForKey:CPTableViewIntercellSpacingKey])
_intercellSpacing = [aCoder decodeSizeForKey:CPTableViewIntercellSpacingKey];
if ([aCoder containsValueForKey:CPTableViewRowHeightKey])
_rowHeight = [aCoder decodeFloatForKey:CPTableViewRowHeightKey];
else
_intercellSpacing = _CGSizeMake(0.0, 0.0);
_rowHeight = 23.0;
_intercellSpacing = [aCoder decodeSizeForKey:CPTableViewIntercellSpacingKey] || _CGSizeMake(0.0, 0.0);
_gridColor = [aCoder decodeObjectForKey:CPTableViewGridColorKey] || [CPColor grayColor];
_gridStyleMask = [aCoder decodeIntForKey:CPTableViewGridStyleMaskKey] || CPTableViewGridNone;
_alternatingRowBackgroundColors = [aCoder decodeObjectForKey:CPTableViewAlternatingRowColorsKey];
_usesAlternatingRowBackgroundColors = [aCoder decodeObjectForKey:CPTableViewUsesAlternatingBackgroundKey]
_headerView = [aCoder decodeObjectForKey:CPTableViewHeaderViewKey];
_cornerView = [aCoder decodeObjectForKey:CPTableViewCornerViewKey];
_selectedColumnIndexes = [CPIndexSet indexSet];
_selectedRowIndexes = [CPIndexSet indexSet];
_dataSource = [aCoder decodeObjectForKey:CPTableViewDataSourceKey];
_delegate = [aCoder decodeObjectForKey:CPTableViewDelegateKey];
_tableDrawView = [[_CPTableDrawView alloc] initWithTableView:self];
[_tableDrawView setBackgroundColor:[CPColor clearColor]];
[self addSubview:_tableDrawView];
[self _init];
[self viewWillMoveToSuperview:[self superview]];
@@ -3282,6 +3249,7 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey",
[aCoder encodeInt:_gridStyleMask forKey:CPTableViewGridStyleMaskKey];
[aCoder encodeBool:_usesAlternatingRowBackgroundColors forKey:CPTableViewUsesAlternatingBackgroundKey];
[aCoder encodeObject:_alternatingRowBackgroundColors forKey:CPTableViewAlternatingRowColorsKey]
[aCoder encodeObject:_cornerView forKey:CPTableViewCornerViewKey];
[aCoder encodeObject:_headerView forKey:CPTableViewHeaderViewKey];
@@ -3326,7 +3294,7 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey",
@end
@implementation _dropOperationDrawingView : CPView
@implementation _CPDropOperationDrawingView : CPView
{
unsigned dropOperation @accessors;
CPTableView tableView @accessors;
+20 -4
View File
@@ -813,7 +813,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
if (![CPPlatform isBrowser])
{
[self copy:sender];
[self deleteBackwards:sender];
[self deleteBackward:sender];
}
}
@@ -826,7 +826,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
if (![[pasteboard types] containsObject:CPStringPboardType])
return;
[self deleteBackwards:sender];
[self deleteBackward:sender];
var selectedRange = [self selectedRange],
stringValue = [self stringValue],
@@ -912,7 +912,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[self selectText:sender];
}
- (void)deleteBackwards:(id)sender
- (void)deleteBackward:(id)sender
{
var selectedRange = [self selectedRange],
stringValue = [self stringValue],
@@ -997,7 +997,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
return bounds;
}
- (CGRect)bezelRectForBounds:(CFRect)bounds
- (CGRect)bezelRectForBounds:(CGRect)bounds
{
var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"];
@@ -1087,6 +1087,22 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
}
}
- (void)takeValueFromKeyPath:(CPString)aKeyPath ofObjects:(CPArray)objects
{
var count = objects.length,
value = [objects[0] valueForKeyPath:aKeyPath];
[self setStringValue:value];
[self setPlaceholderString:@""];
while (count-- > 1)
if (value !== [objects[count] valueForKeyPath:aKeyPath])
{
[self setPlaceholderString:@"Multiple Values"];
[self setStringValue:@""];
}
}
@end
var secureStringForString = function(aString)
+3 -4
View File
@@ -449,6 +449,9 @@ CPToolbarItemVisibilityPriorityUser
- (void)validate
{
var action = [self action],
target = [self target];
// View items do not do any target-action analysis.
if (_view)
{
@@ -458,13 +461,9 @@ CPToolbarItemVisibilityPriorityUser
return;
}
var action = [self action];
if (!action)
return [self setEnabled:NO];
var target = [self target];
if (target && ![target respondsToSelector:action])
return [self setEnabled:NO];
+115 -45
View File
@@ -94,7 +94,8 @@ var DOMElementPrototype = nil,
BackgroundTrivialColor = 0,
BackgroundVerticalThreePartImage = 1,
BackgroundHorizontalThreePartImage = 2,
BackgroundNinePartImage = 3;
BackgroundNinePartImage = 3,
BackgroundTransparentColor = 4;
#endif
var CPViewFlags = { },
@@ -139,6 +140,7 @@ var CPViewFlags = { },
BOOL _isHidden;
BOOL _hitTests;
BOOL _clipsToBounds;
BOOL _postsFrameChangedNotifications;
BOOL _postsBoundsChangedNotifications;
@@ -243,6 +245,11 @@ var CPViewFlags = { },
return [CPSet setWithObjects:@"boundsOrigin", @"boundsSize"];
}
+ (CPMenu)defaultMenu
{
return nil;
}
- (id)init
{
return [self initWithFrame:CGRectMakeZero()];
@@ -272,6 +279,7 @@ var CPViewFlags = { },
_autoresizingMask = CPViewNotSizable;
_autoresizesSubviews = YES;
_clipsToBounds = YES;
_opacity = 1.0;
_isHidden = NO;
@@ -668,7 +676,7 @@ var CPViewFlags = { },
return _tag;
}
- (void)viewWithTag:(CPInteger)aTag
- (CPView)viewWithTag:(CPInteger)aTag
{
if ([self tag] == aTag)
return self;
@@ -830,28 +838,33 @@ var CPViewFlags = { },
if (_backgroundType !== BackgroundTrivialColor)
{
var images = [[_backgroundColor patternImage] imageSlices];
if (_backgroundType === BackgroundVerticalThreePartImage)
if (_backgroundType === BackgroundTransparentColor)
{
CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], size.width, size.height - _DOMImageSizes[0].height - _DOMImageSizes[2].height);
CPDOMDisplayServerSetStyleSize(_DOMImageParts[0], size.width, size.height);
}
else if (_backgroundType === BackgroundHorizontalThreePartImage)
else
{
CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], size.width - _DOMImageSizes[0].width - _DOMImageSizes[2].width, size.height);
}
var images = [[_backgroundColor patternImage] imageSlices];
else if (_backgroundType === BackgroundNinePartImage)
{
var width = size.width - _DOMImageSizes[0].width - _DOMImageSizes[2].width,
height = size.height - _DOMImageSizes[0].height - _DOMImageSizes[6].height;
if (_backgroundType === BackgroundVerticalThreePartImage)
{
CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], size.width, size.height - _DOMImageSizes[0].height - _DOMImageSizes[2].height);
}
else if (_backgroundType === BackgroundHorizontalThreePartImage)
{
CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], size.width - _DOMImageSizes[0].width - _DOMImageSizes[2].width, size.height);
}
else if (_backgroundType === BackgroundNinePartImage)
{
var width = size.width - _DOMImageSizes[0].width - _DOMImageSizes[2].width,
height = size.height - _DOMImageSizes[0].height - _DOMImageSizes[6].height;
CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], width, _DOMImageSizes[0].height);
CPDOMDisplayServerSetStyleSize(_DOMImageParts[3], _DOMImageSizes[3].width, height);
CPDOMDisplayServerSetStyleSize(_DOMImageParts[4], width, height);
CPDOMDisplayServerSetStyleSize(_DOMImageParts[5], _DOMImageSizes[5].width, height);
CPDOMDisplayServerSetStyleSize(_DOMImageParts[7], width, _DOMImageSizes[7].height);
CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], width, _DOMImageSizes[0].height);
CPDOMDisplayServerSetStyleSize(_DOMImageParts[3], _DOMImageSizes[3].width, height);
CPDOMDisplayServerSetStyleSize(_DOMImageParts[4], width, height);
CPDOMDisplayServerSetStyleSize(_DOMImageParts[5], _DOMImageSizes[5].width, height);
CPDOMDisplayServerSetStyleSize(_DOMImageParts[7], width, _DOMImageSizes[7].height);
}
}
}
#endif
@@ -1183,6 +1196,23 @@ var CPViewFlags = { },
return _isHidden;
}
- (void)setClipsToBounds:(BOOL)shouldClip
{
if (_clipsToBounds === shouldClip)
return;
_clipsToBounds = shouldClip;
#if PLATFORM(DOM)
_DOMElement.style.overflow = _clipsToBounds ? "hidden" : "visible";
#endif
}
- (BOOL)clipsToBounds
{
return _clipsToBounds;
}
/*!
Sets the opacity of the receiver. The value must be in the range of 0.0 to 1.0, where 0.0 is
completely transparent and 1.0 is completely opaque.
@@ -1199,7 +1229,7 @@ var CPViewFlags = { },
if (CPFeatureIsCompatible(CPOpacityRequiresFilterFeature))
{
if (anAlphaValue == 1.0)
if (anAlphaValue === 1.0)
try { _DOMElement.style.removeAttribute("filter") } catch (anException) { }
else
_DOMElement.style.filter = "alpha(opacity=" + anAlphaValue * 100 + ")";
@@ -1309,6 +1339,22 @@ var CPViewFlags = { },
[super mouseDown:anEvent];
}
- (void)rightMouseDown:(CPEvent)anEvent
{
var menu = [self menuForEvent:anEvent];
if (menu)
[CPMenu popUpContextMenu:menu withEvent:anEvent forView:self];
else if ([[self nextResponder] isKindOfClass:CPView])
[super rightMouseDown:anEvent];
else
[[[anEvent window] platformWindow] _propagateContextMenuDOMEvent:YES];
}
- (CPMenu)menuForEvent:(CPEvent)anEvent
{
return [self menu] || [[self class] defaultMenu];
}
/*!
Sets the background color of the receiver.
@param aColor the new color for the receiver's background
@@ -1317,56 +1363,72 @@ var CPViewFlags = { },
{
if (_backgroundColor == aColor)
return;
_backgroundColor = aColor;
#if PLATFORM(DOM)
var patternImage = [_backgroundColor patternImage],
colorExists = _backgroundColor && ([_backgroundColor patternImage] || [_backgroundColor alphaComponent] > 0.0),
colorHasAlpha = colorExists && [_backgroundColor alphaComponent] < 1.0,
supportsRGBA = CPFeatureIsCompatible(CPCSSRGBAFeature),
colorNeedsDOMElement = colorHasAlpha && !supportsRGBA,
amount = 0;
if ([patternImage isThreePartImage])
{
_backgroundType = [patternImage isVertical] ? BackgroundVerticalThreePartImage : BackgroundHorizontalThreePartImage;
amount = 3 - _DOMImageParts.length;
}
else if ([patternImage isNinePartImage])
{
_backgroundType = BackgroundNinePartImage;
amount = 9 - _DOMImageParts.length;
amount = 9 - _DOMImageParts.length;
}
else
{
_backgroundType = BackgroundTrivialColor;
amount = 0 - _DOMImageParts.length;
_backgroundType = colorNeedsDOMElement ? BackgroundTransparentColor : BackgroundTrivialColor;
amount = (colorNeedsDOMElement ? 1 : 0) - _DOMImageParts.length;
}
if (amount > 0)
{
while (amount--)
{
var DOMElement = DOMElementPrototype.cloneNode(false);
DOMElement.style.zIndex = -1000;
_DOMImageParts.push(DOMElement);
_DOMElement.appendChild(DOMElement);
}
}
else
{
amount = -amount;
while (amount--)
_DOMElement.removeChild(_DOMImageParts.pop());
}
if (_backgroundType == BackgroundTrivialColor)
// Opera doesn't like DOM properties set to nil.
// https://trac.280north.com/ticket/7
_DOMElement.style.background = _backgroundColor ? [_backgroundColor cssString] : "";
if (_backgroundType === BackgroundTrivialColor || _backgroundType === BackgroundTransparentColor)
{
var colorCSS = colorExists ? [_backgroundColor cssString] : "";
if (colorNeedsDOMElement)
{
_DOMElement.style.background = "";
_DOMImageParts[0].style.background = [_backgroundColor cssString];
if (CPFeatureIsCompatible(CPOpacityRequiresFilterFeature))
_DOMImageParts[0].style.filter = "alpha(opacity=" + [_backgroundColor alphaComponent] * 100 + ")";
else
_DOMImageParts[0].style.opacity = [_backgroundColor alphaComponent];
var size = [self bounds].size;
CPDOMDisplayServerSetStyleSize(_DOMImageParts[0], size.width, size.height);
}
else
_DOMElement.style.background = colorCSS;
}
else
{
var slices = [patternImage imageSlices],
@@ -1377,23 +1439,31 @@ var CPViewFlags = { },
{
var image = slices[count],
size = _DOMImageSizes[count] = image ? [image size] : _CGSizeMakeZero();
CPDOMDisplayServerSetStyleSize(_DOMImageParts[count], size.width, size.height);
_DOMImageParts[count].style.background = image ? "url(\"" + [image filename] + "\")" : "";
if (!supportsRGBA)
{
if (CPFeatureIsCompatible(CPOpacityRequiresFilterFeature))
try { _DOMImageParts[count].style.removeAttribute("filter") } catch (anException) { }
else
_DOMImageParts[count].style.opacity = 1.0;
}
}
if (_backgroundType == BackgroundNinePartImage)
{
var width = frameSize.width - _DOMImageSizes[0].width - _DOMImageSizes[2].width,
height = frameSize.height - _DOMImageSizes[0].height - _DOMImageSizes[6].height;
CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], width, _DOMImageSizes[0].height);
CPDOMDisplayServerSetStyleSize(_DOMImageParts[3], _DOMImageSizes[3].width, height);
CPDOMDisplayServerSetStyleSize(_DOMImageParts[4], width, height);
CPDOMDisplayServerSetStyleSize(_DOMImageParts[5], _DOMImageSizes[5].width, height);
CPDOMDisplayServerSetStyleSize(_DOMImageParts[7], width, _DOMImageSizes[7].height);
CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[0], NULL, 0.0, 0.0);
CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[1], NULL, _DOMImageSizes[0].width, 0.0);
CPDOMDisplayServerSetStyleRightTop(_DOMImageParts[2], NULL, 0.0, 0.0);
@@ -1407,7 +1477,7 @@ var CPViewFlags = { },
else if (_backgroundType == BackgroundVerticalThreePartImage)
{
CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], frameSize.width, frameSize.height - _DOMImageSizes[0].height - _DOMImageSizes[2].height);
CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[0], NULL, 0.0, 0.0);
CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[1], NULL, 0.0, _DOMImageSizes[0].height);
CPDOMDisplayServerSetStyleLeftBottom(_DOMImageParts[2], NULL, 0.0, 0.0);
@@ -1415,7 +1485,7 @@ var CPViewFlags = { },
else if (_backgroundType == BackgroundHorizontalThreePartImage)
{
CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], frameSize.width - _DOMImageSizes[0].width - _DOMImageSizes[2].width, frameSize.height);
CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[0], NULL, 0.0, 0.0);
CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[1], NULL, _DOMImageSizes[0].width, 0.0);
CPDOMDisplayServerSetStyleRightTop(_DOMImageParts[2], NULL, 0.0, 0.0);
+81 -27
View File
@@ -372,6 +372,15 @@ CPTexturedBackgroundWindowMask
[self setPlatformWindow:[CPPlatformWindow primaryPlatformWindow]];
else
{
// give zero sized borderless bridge windows a default size if we're not in the browser so they show up in NativeHost.
if ((aStyleMask & CPBorderlessBridgeWindowMask) && aContentRect.size.width === 0 && aContentRect.size.height === 0)
{
var visibleFrame = [[[CPScreen alloc] init] visibleFrame];
_frame.size.height = MIN(768.0, visibleFrame.size.height);
_frame.size.width = MIN(1024.0, visibleFrame.size.width);
_frame.origin.x = (visibleFrame.size.width - _frame.size.width) / 2;
_frame.origin.y = (visibleFrame.size.height - _frame.size.height) / 2;
}
[self setPlatformWindow:[[CPPlatformWindow alloc] initWithContentRect:_frame]];
[self platformWindow]._only = self;
}
@@ -472,9 +481,6 @@ CPTexturedBackgroundWindowMask
- (void)awakeFromCib
{
if (_initialFirstResponder)
[self makeFirstResponder:_initialFirstResponder];
_keyViewLoopIsDirty = ![self _hasKeyViewLoop];
}
@@ -738,6 +744,15 @@ CPTexturedBackgroundWindowMask
{
[_platformWindow orderFront:self];
[_platformWindow order:CPWindowAbove window:self relativeTo:nil];
if (_firstResponder === self || !_firstResponder)
[self makeFirstResponder:[self initialFirstResponder]];
if (!CPApp._keyWindow)
[self makeKeyWindow];
if (!CPApp._mainWindow)
[self makeMainWindow];
}
/*
@@ -877,6 +892,23 @@ CPTexturedBackgroundWindowMask
return _contentView;
}
/*!
Applies an alpha value to the window.
@param aValue the alpha value to apply
*/
- (void)setAlphaValue:(float)aValue
{
[_windowView setAlphaValue:aValue];
}
/*!
Returns the alpha value of the window.
*/
- (float)alphaValue
{
return [_windowView alphaValue];
}
/*!
Sets the window's background color.
@param aColor the new color for the background
@@ -1161,6 +1193,16 @@ CPTexturedBackgroundWindowMask
return YES;
}
- (id)initialFirstResponder
{
return _initialFirstResponder;
}
- (void)setInitialFirstResponder:(id)aResponder
{
_initialFirstResponder = aResponder;
}
/*!
Attempts to make the \c aResponder the first responder. Before trying
to make it the first responder, the receiver will ask the current first responder
@@ -1170,7 +1212,7 @@ CPTexturedBackgroundWindowMask
*/
- (BOOL)makeFirstResponder:(CPResponder)aResponder
{
if (_firstResponder == aResponder)
if (_firstResponder === aResponder)
return YES;
if(![_firstResponder resignFirstResponder])
@@ -1331,44 +1373,58 @@ CPTexturedBackgroundWindowMask
case CPScrollWheel: return [[_windowView hitTest:point] scrollWheel:anEvent];
case CPLeftMouseUp: if (!_leftMouseDownView)
return [[_windowView hitTest:point] mouseUp:anEvent];
case CPLeftMouseUp:
case CPRightMouseUp: var hitTestedView = _leftMouseDownView,
selector = type == CPRightMouseUp ? @selector(rightMouseUp:) : @selector(mouseUp:);
[_leftMouseDownView mouseUp:anEvent]
if (!hitTestedView)
hitTestedView = [_windowView hitTest:point];
[hitTestedView performSelector:selector withObject:anEvent];
_leftMouseDownView = nil;
return;
case CPLeftMouseDown: _leftMouseDownView = [_windowView hitTest:point];
case CPLeftMouseDown:
case CPRightMouseDown: _leftMouseDownView = [_windowView hitTest:point];
if (_leftMouseDownView != _firstResponder && [_leftMouseDownView acceptsFirstResponder])
[self makeFirstResponder:_leftMouseDownView];
[CPApp activateIgnoringOtherApps:YES];
var theWindow = [anEvent window];
var theWindow = [anEvent window],
selector = type == CPRightMouseDown ? @selector(rightMouseDown:) : @selector(mouseDown:);
if ([theWindow isKeyWindow] || [theWindow becomesKeyOnlyIfNeeded] && ![_leftMouseDownView needsPanelToBecomeKey])
return [_leftMouseDownView mouseDown:anEvent];
return [_leftMouseDownView performSelector:selector withObject:anEvent];
else
{
// FIXME: delayed ordering?
[self makeKeyAndOrderFront:self];
if ([_leftMouseDownView acceptsFirstMouse:anEvent])
return [_leftMouseDownView mouseDown:anEvent]
return [_leftMouseDownView performSelector:selector withObject:anEvent];
}
break;
case CPLeftMouseDragged: if (!_leftMouseDownView)
case CPLeftMouseDragged:
case CPRightMouseDragged: if (!_leftMouseDownView)
return [[_windowView hitTest:point] mouseDragged:anEvent];
return [_leftMouseDownView mouseDragged:anEvent];
case CPRightMouseUp: return [_rightMouseDownView mouseUp:anEvent];
case CPRightMouseDown: _rightMouseDownView = [_windowView hitTest:point];
return [_rightMouseDownView mouseDown:anEvent];
case CPRightMouseDragged: return [_rightMouseDownView mouseDragged:anEvent];
var selector;
if (type == CPRightMouseDragged)
{
selector = @selector(rightMouseDragged:)
if (![_leftMouseDownView respondsToSelector:selector])
selector = nil;
}
if (!selector)
selector = @selector(mouseDragged:)
return [_leftMouseDownView performSelector:selector withObject:anEvent];
case CPMouseMoved: if (!_acceptsMouseMovedEvents)
return;
@@ -1494,10 +1550,11 @@ CPTexturedBackgroundWindowMask
*/
- (void)resignKeyWindow
{
if (_firstResponder != self && [_firstResponder respondsToSelector:@selector(resignKeyWindow)])
if (_firstResponder !== self && [_firstResponder respondsToSelector:@selector(resignKeyWindow)])
[_firstResponder resignKeyWindow];
CPApp._keyWindow = nil;
if (CPApp._keyWindow === self)
CPApp._keyWindow = nil;
[[CPNotificationCenter defaultCenter]
postNotificationName:CPWindowDidResignKeyNotification
@@ -1858,7 +1915,8 @@ CPTexturedBackgroundWindowMask
postNotificationName:CPWindowDidResignMainNotification
object:self];
CPApp._mainWindow = nil;
if (CPApp._mainWindow === self)
CPApp._mainWindow = nil;
}
- (void)_updateMainAndKeyWindows
@@ -1866,9 +1924,6 @@ CPTexturedBackgroundWindowMask
var allWindows = [CPApp orderedWindows],
windowCount = [allWindows count];
if (!windowCount)
return;
if ([self isKeyWindow])
{
var keyWindow = [CPApp keyWindow];
@@ -1893,11 +1948,10 @@ CPTexturedBackgroundWindowMask
}
if (![CPApp keyWindow])
[keyWindow makeKeyWindow];
[menuWindow makeKeyWindow];
}
}
if ([self isMainWindow])
{
var mainWindow = [CPApp mainWindow];
@@ -71,11 +71,12 @@ var _CPToolbarViewBackgroundColor = nil;
[self addSubview:_toolbarBackgroundView positioned:CPWindowBelow relativeTo:nil];
}
var frame = CGRectMakeZero();
frame.origin = CGPointMakeCopy([self toolbarOffset]);
var frame = CGRectMakeZero(),
toolbarOffset = [self toolbarOffset];
frame.origin = CGPointMake(toolbarOffset.width, toolbarOffset.height);
frame.size = [_toolbarView frame].size;
[_toolbarBackgroundView setFrame:frame];
}
+4 -3
View File
@@ -36,6 +36,7 @@ var _CPWindowViewResizeIndicatorImage = nil;
CGSize _resizeIndicatorOffset;
CPView _toolbarView;
CGSize _toolbarOffset;
// BOOL _isAnimatingToolbar;
@@ -80,8 +81,8 @@ var _CPWindowViewResizeIndicatorImage = nil;
if (self)
{
_styleMask = aStyleMask;
_resizeIndicatorOffset = CGSizeMake(0.0, 0.0);
_toolbarOffset = CGSizeMake(0.0, 0.0);
_resizeIndicatorOffset = CGSizeMakeZero();
_toolbarOffset = CGSizeMakeZero();
}
return self;
@@ -269,7 +270,7 @@ var _CPWindowViewResizeIndicatorImage = nil;
- (CGSize)toolbarOffset
{
return CGSizeMakeZero();
return _toolbarOffset;
}
- (CPColor)toolbarLabelColor
-19
View File
@@ -322,25 +322,6 @@
return _documents;
}
- (void)setViewController:(CPViewController)aViewController
{
var containerView = [self viewControllerContainerView] || [[self window] contentView],
view = [_viewController view],
frame = view ? [view frame] : [containerView bounds];
[view removeFromSuperview];
_viewController = aViewController;
view = [_viewController view];
if (view)
{
[view setFrame:frame];
[containerView addSubview:view];
}
}
- (void)setViewControllerContainerView:(CPView)aView
{
_viewControllerContainerView = aView;
+6 -1
View File
@@ -171,12 +171,17 @@ var CPCibObjectDataKey = @"CPCibObjectDataKey";
- (void)connection:(CPURLConnection)aConnection didReceiveData:(CPString)data
{
// FIXME: Why aren't we getting connection:didFailWithError:
if (!data)
return [self connection:aConnection didFailWithError:nil];
_data = [CPData dataWithRawString:data];
}
- (void)connection:(CPURLConnection)aConnection didFailWithError:(CPError)anError
{
alert("cib: connection failed.");
if ([_loadDelegate respondsToSelector:@selector(cibDidFailToLoad:)])
[_loadDelegate cibDidFailToLoad:self];
_loadDelegate = nil;
}
+5
View File
@@ -118,4 +118,9 @@ var CPCibOwner = @"CPCibOwner";
[_loadDelegate cibDidFinishLoading:aCib];
}
- (void)cibDidFailToLoad:(CPCib)aCib
{
[_loadDelegate cibDidFailToLoad:aCib];
}
@end
+1 -2
View File
@@ -777,8 +777,7 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
@ignore
*/
+ (void)runLoopUpdateLayers
{if (window.oops) {alert(window.latest); objj_debug_print_backtrace();}
window.loop = true;
{
for (UID in CALayerRegisteredRunLoopUpdates)
{
var layer = CALayerRegisteredRunLoopUpdates[UID],
+1 -1
View File
@@ -210,7 +210,7 @@ function CGPathAddQuadCurveToPoint(aPath, aTransform, cpx, cpy, x, y)
if (aTransform)
{
cp = _CGPointApplyAffineTransform(control, aTransform);
cp = _CGPointApplyAffineTransform(cp, aTransform);
end = _CGPointApplyAffineTransform(end, aTransform);
}
+1
View File
@@ -46,6 +46,7 @@ var PrimaryPlatformWindow = NULL;
CPDictionary _windowLayers;
BOOL _mouseIsDown;
BOOL _mouseDownIsRightClick;
CPWindow _mouseDownWindow;
CPTimeInterval _lastMouseUp;
CPTimeInterval _lastMouseDown;
+10 -3
View File
@@ -40,6 +40,16 @@ var screenNeedsInitialization = NO,
return;
screenNeedsInitialization = [CPPlatform isBrowser];
// We do this here because doing it later breaks IE.
if (document.documentElement)
document.documentElement.style.overflow = "hidden";
if ([CPPlatform isBrowser])
window.onunload = function()
{
[CPApp terminate:nil];
}
}
+ (BOOL)isBrowser
@@ -121,9 +131,6 @@ var screenNeedsInitialization = NO,
bodyElement.style.overflow = "hidden";
if (document.documentElement)
document.documentElement.style.overflow = "hidden";
[[CPNotificationCenter defaultCenter]
postNotificationName:CPPlatformDidClearBodyElementNotification
object:self];
+56 -50
View File
@@ -22,9 +22,10 @@
#include "../CoreGraphics/CGGeometry.h"
var DOMSpanElement = nil,
DOMIFrameElement = nil,
DefaultFont = nil;
var DOMFixedWidthSpanElement = nil,
DOMFlexibleWidthSpanElement = nil,
DOMIFrameElement = nil,
DefaultFont = nil;
@implementation CPPlatformString : CPBasePlatformString
{
@@ -37,25 +38,30 @@ var DOMSpanElement = nil,
+ (void)createDOMElements
{
var style;
DOMIFrameElement = document.createElement("iframe");
// necessary for Safari caching bug:
DOMIFrameElement.name = "iframe_" + FLOOR(RAND() * 10000);
DOMIFrameElement.style.position = "absolute";
DOMIFrameElement.style.left = "-100px";
DOMIFrameElement.style.top = "-100px";
DOMIFrameElement.style.width = "1px";
DOMIFrameElement.style.height = "1px";
DOMIFrameElement.style.borderWidth = "0px";
DOMIFrameElement.style.overflow = "hidden";
DOMIFrameElement.style.zIndex = 100000000000;
DOMIFrameElement.className = "cpdontremove";
style = DOMIFrameElement.style;
style.position = "absolute";
style.left = "-100px";
style.top = "-100px";
style.width = "1px";
style.height = "1px";
style.borderWidth = "0px";
style.overflow = "hidden";
style.zIndex = 100000000000;
var bodyElement = [CPPlatform mainBodyElement];
bodyElement.appendChild(DOMIFrameElement);
var DOMIFrameDocument = (DOMIFrameElement.contentDocument || DOMIFrameElement.contentWindow.document);
DOMIFrameDocument.write("<html><head></head><body></body></html>");
DOMIFrameDocument.write('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'+
'<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head></head><body></body></html>');
DOMIFrameDocument.close();
// IE needs this wide <div> to prevent unwanted text wrapping:
@@ -65,18 +71,39 @@ var DOMSpanElement = nil,
DOMIFrameDocument.body.appendChild(DOMDivElement);
DOMSpanElement = DOMIFrameDocument.createElement("span");
DOMSpanElement.style.position = "absolute";
DOMSpanElement.style.visibility = "visible";
DOMSpanElement.style.padding = "0px";
DOMSpanElement.style.margin = "0px";
DOMFlexibleWidthSpanElement = DOMIFrameDocument.createElement("span");
style = DOMFlexibleWidthSpanElement.style;
style.position = "absolute";
style.visibility = "visible";
style.padding = "0px";
style.margin = "0px";
style.whiteSpace = "pre";
try {
DOMSpanElement.style.whiteSpace = "pre";
DOMFixedWidthSpanElement = DOMIFrameDocument.createElement("span");
style = DOMFixedWidthSpanElement.style;
style.display = "block";
style.position = "absolute";
style.visibility = "visible";
style.padding = "0px";
style.margin = "0px";
style.width = "1px";
style.wordWrap = "break-word";
try
{
style.whiteSpace = "pre";
style.whiteSpace = "-o-pre-wrap";
style.whiteSpace = "-pre-wrap";
style.whiteSpace = "-moz-pre-wrap";
style.whiteSpace = "pre-wrap";
}
catch(e)
{
//some versions of IE throw exceptions for unsupported properties.
style.whiteSpace = "pre";
}
catch (e) {}
DOMDivElement.appendChild(DOMSpanElement);
DOMDivElement.appendChild(DOMFlexibleWidthSpanElement);
DOMDivElement.appendChild(DOMFixedWidthSpanElement);
}
+ (CGSize)sizeOfString:(CPString)aString withFont:(CPFont)aFont forWidth:(float)aWidth
@@ -92,44 +119,23 @@ var DOMSpanElement = nil,
if (!DOMIFrameElement)
[self createDOMElements];
var style = DOMSpanElement.style;
var span;
if (!aWidth)
{
style.width = "";
try {
style.whiteSpace = "pre";
}
catch (e) {}
style.wordWrap = "normal";
}
span = DOMFlexibleWidthSpanElement;
else
{
style.width = ROUND(aWidth) + "px";
try
{
style.whiteSpace = "-o-pre-wrap";
style.whiteSpace = "-pre-wrap";
style.whiteSpace = "-moz-pre-wrap";
style.whiteSpace = "pre-wrap";
} catch(e)
{
//some versions of IE throw exceptions for unsupported properties.
}
style.wordWrap = "break-word";
span = DOMFixedWidthSpanElement;
span.style.width = ROUND(aWidth) + "px";
}
style.font = [aFont cssString];
span.style.font = [aFont cssString];
if (CPFeatureIsCompatible(CPJavascriptInnerTextFeature))
DOMSpanElement.innerText = aString;
span.innerText = aString;
else if (CPFeatureIsCompatible(CPJavascriptTextContentFeature))
DOMSpanElement.textContent = aString;
span.textContent = aString;
return _CGSizeMake(DOMSpanElement.clientWidth, DOMSpanElement.clientHeight);
return _CGSizeMake(span.clientWidth, span.clientHeight);
}
@end
+42 -7
View File
@@ -127,7 +127,8 @@ var PlatformWindows = [CPSet set];
// Define up here so compressor knows about em.
var CPDOMEventGetClickCount,
CPDOMEventStop,
StopDOMEventPropagation;
StopDOMEventPropagation,
StopContextMenuDOMEventPropagation;
var _DOMEventGuard;
@@ -312,6 +313,10 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
mouseEventImplementation = class_getMethodImplementation(theClass, mouseEventSelector),
mouseEventCallback = function (anEvent) { mouseEventImplementation(self, nil, anEvent); },
contextMenuEventSelector = @selector(contextMenuEvent:),
contextMenuEventImplementation = class_getMethodImplementation(theClass, contextMenuEventSelector),
contextMenuEventCallback = function (anEvent) { return contextMenuEventImplementation(self, nil, anEvent); },
scrollEventSelector = @selector(scrollEvent:),
scrollEventImplementation = class_getMethodImplementation(theClass, scrollEventSelector),
scrollEventCallback = function (anEvent) { scrollEventImplementation(self, nil, anEvent); },
@@ -335,6 +340,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
theDocument.addEventListener("mouseup", mouseEventCallback, NO);
theDocument.addEventListener("mousedown", mouseEventCallback, NO);
theDocument.addEventListener("mousemove", mouseEventCallback, NO);
theDocument.addEventListener("contextmenu", contextMenuEventCallback, NO);
theDocument.addEventListener("beforecopy", copyEventCallback, NO);
theDocument.addEventListener("beforecut", copyEventCallback, NO);
@@ -362,6 +368,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
theDocument.removeEventListener("mouseup", mouseEventCallback, NO);
theDocument.removeEventListener("mousedown", mouseEventCallback, NO);
theDocument.removeEventListener("mousemove", mouseEventCallback, NO);
theDocument.removeEventListener("contextmenu", contextMenuEventCallback, NO);
theDocument.removeEventListener("keyup", keyEventCallback, NO);
theDocument.removeEventListener("keydown", keyEventCallback, NO);
@@ -394,6 +401,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
theDocument.attachEvent("onmousedown", mouseEventCallback);
theDocument.attachEvent("onmousemove", mouseEventCallback);
theDocument.attachEvent("ondblclick", mouseEventCallback);
theDocument.attachEvent("oncontextmenu", contextMenuEventCallback);
theDocument.attachEvent("onkeyup", keyEventCallback);
theDocument.attachEvent("onkeydown", keyEventCallback);
@@ -416,6 +424,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
theDocument.detachEvent("onmousedown", mouseEventCallback);
theDocument.detachEvent("onmousemove", mouseEventCallback);
theDocument.detachEvent("ondblclick", mouseEventCallback);
theDocument.detachEvent("oncontextmenu", contextMenuEventCallback);
theDocument.detachEvent("onkeyup", keyEventCallback);
theDocument.detachEvent("onkeydown", keyEventCallback);
@@ -804,7 +813,6 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
}
}
- (void)_checkPasteboardElement
{
var value = _DOMPasteboardElement.value;
@@ -1047,11 +1055,12 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
{
if(_mouseIsDown)
{
event = _CPEventFromNativeMouseEvent(aDOMEvent, CPLeftMouseUp, location, modifierFlags, timestamp, windowNumber, nil, -1, CPDOMEventGetClickCount(_lastMouseUp, timestamp, location), 0);
event = _CPEventFromNativeMouseEvent(aDOMEvent, _mouseDownIsRightClick ? CPRightMouseUp : CPLeftMouseUp, location, modifierFlags, timestamp, windowNumber, nil, -1, CPDOMEventGetClickCount(_lastMouseUp, timestamp, location), 0);
_mouseIsDown = NO;
_lastMouseUp = event;
_mouseDownWindow = nil;
_mouseDownIsRightClick = NO;
}
if(_DOMEventMode)
@@ -1091,8 +1100,13 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
_DOMBodyElement.style["-khtml-user-drag"] = "element";
}
event = _CPEventFromNativeMouseEvent(aDOMEvent, CPLeftMouseDown, location, modifierFlags, timestamp, windowNumber, nil, -1, CPDOMEventGetClickCount(_lastMouseDown, timestamp, location), 0);
var button = aDOMEvent.button;
_mouseDownIsRightClick = button == 2 || (button == 0 && modifierFlags & CPControlKeyMask);
StopContextMenuDOMEventPropagation = YES;
event = _CPEventFromNativeMouseEvent(aDOMEvent, _mouseDownIsRightClick ? CPRightMouseDown : CPLeftMouseDown, location, modifierFlags, timestamp, windowNumber, nil, -1, CPDOMEventGetClickCount(_lastMouseDown, timestamp, location), 0);
_mouseIsDown = YES;
_lastMouseDown = event;
}
@@ -1102,7 +1116,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
if (_DOMEventMode)
return;
event = _CPEventFromNativeMouseEvent(aDOMEvent, _mouseIsDown ? CPLeftMouseDragged : CPMouseMoved, location, modifierFlags, timestamp, windowNumber, nil, -1, 1, 0);
event = _CPEventFromNativeMouseEvent(aDOMEvent, _mouseIsDown ? (_mouseDownIsRightClick ? CPRightMouseDragged : CPLeftMouseDragged) : CPMouseMoved, location, modifierFlags, timestamp, windowNumber, nil, -1, 1, 0);
}
var isDragging = [[CPDragServer sharedDragServer] isDragging];
@@ -1123,7 +1137,15 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
}
(CPArray)orderedWindowsAtLevel:(int)aLevel
- (void)contextMenuEvent:(DOMEvent)aDOMEvent
{
if (StopContextMenuDOMEventPropagation)
CPDOMEventStop(aDOMEvent, self);
return !StopContextMenuDOMEventPropagation;
}
- (CPArray)orderedWindowsAtLevel:(int)aLevel
{
var layer = [self layerAtLevel:aLevel create:NO];
@@ -1264,6 +1286,19 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
return !StopDOMEventPropagation;
}
- (void)_propagateContextMenuDOMEvent:(BOOL)aFlag
{
if (aFlag && CPBrowserIsEngine(CPGeckoBrowserEngine))
StopDOMEventPropagation = !aFlag;
StopContextMenuDOMEventPropagation = !aFlag;
}
- (BOOL)_willPropagateContextMenuDOMEvent
{
return StopContextMenuDOMEventPropagation;
}
- (CPWindow)hitTest:(CPPoint)location
{
if (self._only)
-18
View File
@@ -1,18 +0,0 @@
<html>
<head>
</head>
<body>
<div>Test custom cursors with .cur images.</div>
<div style="width: 20px; height: 20px; margin: 10px; background: #ddd; cursor: url(disappearingItemCursor.cur), default">disappearingItemCursor</div>
<div style="width: 20px; height: 20px; margin: 10px; background: #ddd; cursor: url(closedHandCursor.cur), default">closedHandCursor</div>
<div style="width: 20px; height: 20px; margin: 10px; background: #ddd; cursor: url(contextMenuCursor.cur), default">contextMenuCursor</div>
<div style="width: 20px; height: 20px; margin: 10px; background: #ddd; cursor: url(dragCopyCursor.cur), default">dragCopyCursor</div>
<div style="width: 20px; height: 20px; margin: 10px; background: #ddd; cursor: url(dragLinkCursor.cur), default">dragLinkCursor</div>
<div style="width: 20px; height: 20px; margin: 10px; background: #ddd; cursor: url(openHandCursor.cur), default">openHandCursor</div>
<div style="width: 20px; height: 20px; margin: 10px; background: #ddd; cursor: url(resizeDownCursor.cur), default">resizeDownCursor</div>
<div style="width: 20px; height: 20px; margin: 10px; background: #ddd; cursor: url(resizeLeftCursor.cur), default">resizeLeftCursor</div>
<div style="width: 20px; height: 20px; margin: 10px; background: #ddd; cursor: url(resizeRightCursor.cur), default">resizeRightCursor</div>
<div style="width: 20px; height: 20px; margin: 10px; background: #ddd; cursor: url(resizeUpCursor.cur), default">resizeUpCursor</div>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 506 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 340 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 B

+48 -11
View File
@@ -439,7 +439,7 @@
isVertical:NO]);
[button setValue:CPLeftTextAlignment forThemeAttribute:@"alignment" inState:CPThemeStateBordered];
[button setValue:[CPFont boldSystemFontOfSize:12.0] forThemeAttribute:@"font" inState:CPThemeStateBordered];
[button setValue:[CPFont systemFontOfSize:12.0] forThemeAttribute:@"font" inState:CPThemeStateBordered];
[button setValue:CGInsetMake(0.0, 0.0, 0.0, 20.0) forThemeAttribute:@"content-inset" inState:CPThemeStateBordered];
[button setValue:bezelColor forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered];
[button setValue:bezelColorSelected forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateSelected];
@@ -493,7 +493,7 @@
isVertical:NO]);
[button setValue:CPLeftTextAlignment forThemeAttribute:@"alignment" inState:CPThemeStateBordered];
[button setValue:[CPFont boldSystemFontOfSize:12.0] forThemeAttribute:@"font" inState:CPThemeStateBordered];
[button setValue:[CPFont systemFontOfSize:12.0] forThemeAttribute:@"font" inState:CPThemeStateBordered];
[button setValue:CGInsetMake(0.0, 0.0, 0.0, 20.0) forThemeAttribute:@"content-inset" inState:CPThemeStateBordered];
[button setValue:bezelColor forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered];
[button setValue:bezelColorSelected forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateSelected];
@@ -721,17 +721,54 @@
+ (CPButtonBar)themedButtonBar
{
var buttonBar = [[CPButtonBar alloc] initWithFrame:CGRectMake(0.0, 0.0, 100.0, 26.0)],
color = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
[
[_CPCibCustomResource imageResourceWithName:"buttonbar-bezel.png" size:CGSizeMake(1.0, 26.0)],
[_CPCibCustomResource imageResourceWithName:"buttonbar-bezel.png" size:CGSizeMake(1.0, 26.0)],
[_CPCibCustomResource imageResourceWithName:"buttonbar-bezel-right.png" size:CGSizeMake(13.0, 26.0)]
]
isVertical:NO]];
var buttonBar = [[CPButtonBar alloc] initWithFrame:CGRectMake(0.0, 0.0, 147.0, 26.0)],
color = [CPColor colorWithPatternImage:[_CPCibCustomResource imageResourceWithName:"buttonbar-bezel.png" size:CGSizeMake(1.0, 26.0)]];
[buttonBar setHasResizeControl:YES];
[buttonBar setValue:color forThemeAttribute:@"bezel-color"];
var resizeColor = [CPColor colorWithPatternImage:[_CPCibCustomResource imageResourceWithName:"buttonbar-resize-control.png" size:CGSizeMake(5.0, 10.0)]];
[buttonBar setValue:CGSizeMake(5.0, 10.0) forThemeAttribute:@"resize-control-size"];
[buttonBar setValue:CGInsetMake(9.0, 4.0, 7.0, 4.0) forThemeAttribute:@"resize-control-inset"];
[buttonBar setValue:resizeColor forThemeAttribute:@"resize-control-color"];
var buttonBezelColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
[
[_CPCibCustomResource imageResourceWithName:"buttonbar-button-bezel-left.png" size:CGSizeMake(2.0, 25.0)],
[_CPCibCustomResource imageResourceWithName:"buttonbar-button-bezel-center.png" size:CGSizeMake(1.0, 25.0)],
[_CPCibCustomResource imageResourceWithName:"buttonbar-button-bezel-right.png" size:CGSizeMake(2.0, 25.0)]
]
isVertical:NO]],
buttonBezelHighlightedColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
[
[_CPCibCustomResource imageResourceWithName:"buttonbar-button-bezel-highlighted-left.png" size:CGSizeMake(2.0, 25.0)],
[_CPCibCustomResource imageResourceWithName:"buttonbar-button-bezel-highlighted-center.png" size:CGSizeMake(1.0, 25.0)],
[_CPCibCustomResource imageResourceWithName:"buttonbar-button-bezel-highlighted-right.png" size:CGSizeMake(2.0, 25.0)]
]
isVertical:NO]],
buttonBezelDisabledColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
[
[_CPCibCustomResource imageResourceWithName:"buttonbar-button-bezel-disabled-left.png" size:CGSizeMake(2.0, 25.0)],
[_CPCibCustomResource imageResourceWithName:"buttonbar-button-bezel-disabled-center.png" size:CGSizeMake(1.0, 25.0)],
[_CPCibCustomResource imageResourceWithName:"buttonbar-button-bezel-disabled-right.png" size:CGSizeMake(2.0, 25.0)]
]
isVertical:NO]];
[buttonBar setValue:buttonBezelColor forThemeAttribute:@"button-bezel-color"];
[buttonBar setValue:buttonBezelHighlightedColor forThemeAttribute:@"button-bezel-color" inState:CPThemeStateHighlighted];
[buttonBar setValue:buttonBezelDisabledColor forThemeAttribute:@"button-bezel-color" inState:CPThemeStateDisabled];
[buttonBar setValue:[CPColor blackColor] forThemeAttribute:@"button-text-color"];
var popup = [CPButtonBar actionPopupButton];
[popup addItemWithTitle:"Item 1"];
[popup addItemWithTitle:"Item 2"];
[buttonBar setButtons:[[CPButtonBar plusButton], [CPButtonBar minusButton], popup]];
return buttonBar;
}
+20 -8
View File
@@ -5,13 +5,18 @@
{
}
- (void)_init
{
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 23.0))]];
}
- (id)initWithFrame:(CGRect)aFrame
{
if (self = [super initWithFrame:aFrame])
{
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 23.0))]];
[self _init];
}
return self;
}
@@ -20,16 +25,23 @@
var context = [[CPGraphicsContext currentContext] graphicsPort];
CGContextSetStrokeColor(context, [CPColor colorWithHexString:@"dce0e2"]);
var points = [
CGPointMake(aRect.origin.x, aRect.origin.y),
CGPointMake(aRect.origin.x + aRect.size.width, aRect.origin.y),
var points = [
CGPointMake(aRect.origin.x, aRect.origin.y + 0.5),
CGPointMake(aRect.origin.x, aRect.origin.y + aRect.size.height)
];
CGContextStrokeLineSegments(context, points, 2);
}
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
{
[self _init];
}
return self;
}
@end
+25 -38
View File
@@ -332,7 +332,8 @@ var HORIZONTAL_MARGIN = 3.0,
hasDOMTextElement = !!_DOMTextElement;
// Create or destroy the DOM Text Element as necessary
if (needsDOMTextElement !== hasDOMTextElement)
if (needsDOMTextElement !== hasDOMTextElement)
{
if (hasDOMTextElement)
{
_DOMElement.removeChild(_DOMTextElement);
@@ -361,6 +362,7 @@ var HORIZONTAL_MARGIN = 3.0,
// We have to set all these values now.
_flags |= _CPImageAndTextViewTextChangedFlag | _CPImageAndTextViewFontChangedFlag | _CPImageAndTextViewLineBreakModeChangedFlag;
}
}
var textStyle = hasDOMTextElement ? _DOMTextElement.style : nil;
@@ -369,6 +371,7 @@ var HORIZONTAL_MARGIN = 3.0,
hasDOMTextShadowElement = !!_DOMTextShadowElement;
if (needsDOMTextShadowElement !== hasDOMTextShadowElement)
{
if (hasDOMTextShadowElement)
{
_DOMElement.removeChild(_DOMTextShadowElement);
@@ -386,6 +389,7 @@ var HORIZONTAL_MARGIN = 3.0,
shadowStyle.font = [_font ? _font : [CPFont systemFontOfSize:12.0] cssString];
shadowStyle.position = "absolute";
shadowStyle.whiteSpace = textStyle.whiteSpace;
shadowStyle.wordWrap = textStyle.wordWrap;
shadowStyle.color = [_textShadowColor cssString];
shadowStyle.zIndex = 150;
@@ -394,7 +398,6 @@ var HORIZONTAL_MARGIN = 3.0,
if (document.attachEvent)
{
shadowStyle.overflow = textStyle.overflow;
shadowStyle.wordWrap = textStyle.wordWrap;
}
else
{
@@ -408,6 +411,7 @@ var HORIZONTAL_MARGIN = 3.0,
_flags |= _CPImageAndTextViewTextChangedFlag; //sigh...
}
}
var shadowStyle = hasDOMTextShadowElement ? _DOMTextShadowElement.style : nil;
@@ -447,9 +451,7 @@ var HORIZONTAL_MARGIN = 3.0,
case CPLineBreakByClipping: textStyle.overflow = "hidden";
textStyle.textOverflow = "clip";
textStyle.whiteSpace = "pre";
if (document.attachEvent)
textStyle.wordWrap = "normal";
textStyle.wordWrap = "normal";
break;
@@ -459,26 +461,23 @@ var HORIZONTAL_MARGIN = 3.0,
case CPLineBreakByTruncatingTail: textStyle.textOverflow = "ellipsis";
textStyle.whiteSpace = "nowrap";
textStyle.overflow = "hidden";
if (document.attachEvent)
textStyle.wordWrap = "normal";
textStyle.wordWrap = "normal";
break;
case CPLineBreakByCharWrapping:
case CPLineBreakByWordWrapping: if (document.attachEvent)
{
case CPLineBreakByWordWrapping: textStyle.wordWrap = "break-word";
try {
textStyle.whiteSpace = "pre";
textStyle.wordWrap = "break-word";
}
else
{
textStyle.whiteSpace = "-o-pre-wrap";
textStyle.whiteSpace = "-pre-wrap";
textStyle.whiteSpace = "-moz-pre-wrap";
textStyle.whiteSpace = "pre-wrap";
}
catch (e) {
//internet explorer doesn't like these properties
textStyle.whiteSpace = "pre";
}
textStyle.overflow = "hidden";
textStyle.textOverflow = "clip";
@@ -490,7 +489,6 @@ var HORIZONTAL_MARGIN = 3.0,
{
if (document.attachEvent)
{
shadowStyle.wordWrap = textStyle.wordWrap;
shadowStyle.overflow = textStyle.overflow;
}
else
@@ -499,6 +497,7 @@ var HORIZONTAL_MARGIN = 3.0,
shadowStyle.overflowY = textStyle.overflowY;
}
shadowStyle.wordWrap = textStyle.wordWrap;
shadowStyle.whiteSpace = textStyle.whiteSpace;
shadowStyle.textOverflow = textStyle.textOverflow;
}
@@ -510,6 +509,7 @@ var HORIZONTAL_MARGIN = 3.0,
// Create or destroy DOM Image element
if (needsDOMImageElement !== hasDOMImageElement)
{
if (hasDOMImageElement)
{
_DOMElement.removeChild(_DOMImageElement);
@@ -539,8 +539,8 @@ var HORIZONTAL_MARGIN = 3.0,
_DOMElement.appendChild(_DOMImageElement);
hasDOMImageElement = YES;
}
#endif
}
}
var size = [self bounds].size,
textRect = _CGRectMake(0.0, 0.0, size.width, size.height);
@@ -572,67 +572,54 @@ var HORIZONTAL_MARGIN = 3.0,
imageHeight *= scale;
}
#if PLATFORM(DOM)
_DOMImageElement.width = imageWidth;
_DOMImageElement.height = imageHeight;
imageStyle.width = imageWidth + "px";
imageStyle.height = imageHeight + "px";
#endif
imageStyle.width = MAX(imageWidth, 0) + "px";
imageStyle.height = MAX(imageHeight, 0) + "px";
if (_imagePosition === CPImageBelow)
{
#if PLATFORM(DOM)
imageStyle.left = FLOOR(centerX - imageWidth / 2.0) + "px";
imageStyle.top = FLOOR(size.height - imageHeight) + "px";
#endif
textRect.size.height = size.height - imageHeight - VERTICAL_MARGIN;
}
else if (_imagePosition === CPImageAbove)
{
#if PLATFORM(DOM)
CPDOMDisplayServerSetStyleLeftTop(_DOMImageElement, NULL, FLOOR(centerX - imageWidth / 2.0), 0);
#endif
textRect.origin.y += imageHeight + VERTICAL_MARGIN;
textRect.size.height = size.height - imageHeight - VERTICAL_MARGIN;
}
else if (_imagePosition === CPImageLeft)
{
#if PLATFORM(DOM)
imageStyle.top = FLOOR(centerY - imageHeight / 2.0) + "px";
imageStyle.left = "0px";
#endif
textRect.origin.x = imageWidth + HORIZONTAL_MARGIN;
textRect.size.width -= imageWidth + HORIZONTAL_MARGIN;
}
else if (_imagePosition === CPImageRight)
{
#if PLATFORM(DOM)
imageStyle.top = FLOOR(centerY - imageHeight / 2.0) + "px";
imageStyle.left = FLOOR(size.width - imageWidth) + "px";
#endif
textRect.size.width -= imageWidth + HORIZONTAL_MARGIN;
}
else if (_imagePosition === CPImageOnly)
{
#if PLATFORM(DOM)
imageStyle.top = FLOOR(centerY - imageHeight / 2.0) + "px";
imageStyle.left = FLOOR(centerX - imageWidth / 2.0) + "px";
#endif
}
}
#if PLATFORM(DOM)
if (hasDOMTextElement)
{
var textRectX = _CGRectGetMinX(textRect),
textRectY = _CGRectGetMinY(textRect),
textRectWidth = _CGRectGetWidth(textRect),
textRectHeight = _CGRectGetHeight(textRect);
if (_verticalAlignment !== CPTopVerticalTextAlignment)
{
if (!_textSize)
@@ -659,8 +646,8 @@ var HORIZONTAL_MARGIN = 3.0,
textStyle.top = ROUND(textRectY) + "px";
textStyle.left = ROUND(textRectX) + "px";
textStyle.width = ROUND(textRectWidth) + "px";
textStyle.height = ROUND(textRectHeight) + "px";
textStyle.width = MAX(ROUND(textRectWidth), 0) + "px";
textStyle.height = MAX(ROUND(textRectHeight), 0) + "px";
if (shadowStyle)
{
@@ -669,8 +656,8 @@ var HORIZONTAL_MARGIN = 3.0,
shadowStyle.top = ROUND(textRectY + _textShadowOffset.height) + "px";
shadowStyle.left = ROUND(textRectX + _textShadowOffset.width) + "px";
shadowStyle.width = ROUND(textRectWidth) + "px";
shadowStyle.height = ROUND(textRectHeight) + "px";
shadowStyle.width = MAX(ROUND(textRectWidth), 0) + "px";
shadowStyle.height = MAX(ROUND(textRectHeight), 0) + "px";
}
}
#endif
+213 -96
View File
@@ -8,6 +8,9 @@ require("narwhal").ensureEngine("rhino");
var FILE = require("file");
var OS = require("os");
var UTIL = require("util");
var CACHEMANIFEST = require("objective-j/cache-manifest");
var stream = require("term").stream;
var parser = new (require("args").Parser)();
@@ -24,6 +27,10 @@ parser.option("-F", "--framework", "frameworks")
.push()
.help("Add a frameworks directory, relative to INPUT_PROJECT (default: ['Frameworks'])");
parser.option("-P", "--path", "paths")
.push()
.help("Add a path (relative to the application root) to inline.");
parser.option("-f", "--force", "force")
.def(false)
.set(true)
@@ -34,6 +41,20 @@ parser.option("--index", "index")
.set()
.help("The root HTML file to modify (default: index.html)");
parser.option("-s", "--split", "number", "split")
.natural()
.def(0)
.help("Split into multiple files");
parser.option("-c", "--compressor", "compressor")
.def("shrinksafe")
.set()
.help("Select a compressor to use (closure-compiler, yuicompressor, shrinksafe), or \"none\" (default: shrinksafe)");
parser.option("--manifest", "manifest")
.set(true)
.help("Generate HTML5 cache manifest.");
parser.option("-v", "--verbose", "verbose")
.def(false)
.set(true)
@@ -81,144 +102,240 @@ function main(args)
var flattener = new ObjectiveJFlattener(rootPath);
flattener.options = options;
flattener.setIncludePaths(frameworks);
flattener.setEnvironments([environment, "ObjJ"]);
print("Loading application.");
flattener.load(mainPath);
flattener.finishLoading();
var applicationRoot = flattener.require("objective-j").StaticResource.resourceAtURL(rootPath)
print(applicationRoot.toString());
print("Loading default theme.");
flattener.require("objective-j").objj_eval("("+(function() {
var blend = [[CPThemeBlend alloc] initWithContentsOfURL:[[CPBundle bundleForClass:[CPApplication class]] pathForResource:[CPApplication defaultThemeName] + ".blend"]];
[blend loadWithDelegate:nil];
})+")")();
var applicationJS = flattener.buildApplicationJS(applicationRoot);
var applicationJSs = flattener.buildApplicationJS();
FILE.copyTree(rootPath, outputPath);
outputPath.join("Application.js").write(applicationJS);
applicationJSs.forEach(function(applicationJS, n) {
var name = "Application"+(n||"")+".js";
if (options.compressor === "none") {
print("skipping compression: " + name);
} else {
print("compressing: " + name);
applicationJS = require("minify/"+options.compressor).compress(applicationJS, { charset : "UTF-8", useServer : true });
}
outputPath.join(name).write(applicationJS, { charset : "UTF-8" });
});
rewriteMainHTML(outputPath.join(options.index));
if (options.manifest) {
CACHEMANIFEST.generateManifest(outputPath, {
index : outputPath.join(options.index),
exclude : Object.keys(flattener.filesToCache).map(function(path) { return outputPath.join(path).toString(); })
});
}
}
// ObjectiveJFlattener inherits from ObjectiveJRuntimeAnalyzer
function ObjectiveJFlattener(rootPath) {
ObjectiveJRuntimeAnalyzer.apply(this, arguments);
this.resourceBuffer = [];
this.bundleBuffer = [];
this.filesToCache = {};
this.fileCacheBuffer = [];
this.functionsBuffer = [];
this._outputBundles = {};
}
ObjectiveJFlattener.prototype = Object.create(ObjectiveJRuntimeAnalyzer.prototype);
ObjectiveJFlattener.prototype.buildApplicationJS = function(applicationRoot) {
this.serializeStaticResources(applicationRoot);
this.serializeStaticFileExecutables();
ObjectiveJFlattener.prototype.buildApplicationJS = function() {
var buffer = []
this.setupFileCache();
this.serializeFunctions();
this.serializeFileCache();
buffer.push("(function(){");
var additions = FILE.read(FILE.join(FILE.dirname(module.path), "..", "..", "cappuccino", "lib", "cappuccino", "objj-flatten-additions.js"), { charset:"UTF-8" });
buffer.push("var appURL = new CFURL('.', ObjectiveJ.pageURL);")
var applicationJSs = [];
buffer.push(this.bundleBuffer.join("\n"));
if (this.options.split === 0) {
var buffer = [];
buffer.push("var baseURL = new CFURL(\".\", ObjectiveJ.pageURL);");
buffer.push(additions);
buffer.push(this.fileCacheBuffer.join("\n"));
buffer.push(this.functionsBuffer.join("\n"));
buffer.push("ObjectiveJ.bootstrap();");
applicationJSs.push(buffer.join("\n"));
} else {
var appFilesCount = this.options.split;
buffer.push("var nodeStack = [];");
buffer.push("var applicationRoot = ObjectiveJ.StaticResource.resourceAtURL(appURL, true);");
buffer.push("var currentNode = null;");
buffer.push("var newNode;");
var buffers = [];
for (var i = 0; i <= appFilesCount; i++)
buffers.push([]);
buffer.push(this.resourceBuffer.join("\n"));
var chunks = this.fileCacheBuffer.concat(this.functionsBuffer).sort(function(chunkA, chunkB) {
return chunkA.length - chunkB.length;
});
buffer.push("})();");
// try to equally distribute the chunks. could be better but good enough for now.
var n = 0;
while (chunks.length) {
buffers[(n++ % appFilesCount) + 1].push(chunks.pop());
}
buffer.push(this.functionsBuffer.join("\n"));
buffers[0].push("var baseURL = new CFURL(\".\", ObjectiveJ.pageURL);");
buffers[0].push(additions);
buffer.push("ObjectiveJ.bootstrap();");
buffers[0].push("var appFilesCount = " + appFilesCount +";");
buffers[0].push("for (var i = 1; i <= appFilesCount; i++) {");
buffers[0].push(" var script = document.createElement(\"script\");");
buffers[0].push(" script.src = \"Application\"+i+\".js\";");
buffers[0].push(" script.charset = \"UTF-8\";");
buffers[0].push(" script.onload = function() { if (--appFilesCount === 0) ObjectiveJ.bootstrap(); };");
buffers[0].push(" document.getElementsByTagName(\"head\")[0].appendChild(script);");
buffers[0].push("}");
return buffer.join("\n");
buffers.forEach(function(buffer) {
applicationJSs.push(buffer.join("\n"));
});
}
return applicationJSs;
}
ObjectiveJFlattener.prototype.serializeStaticFileExecutables = function() {
this.require("objective-j").FileExecutable.allFileExecutables().forEach(function(aFileExecutable) {
var deps = aFileExecutable.fileDependencies().map(function(dependency) {
return "new ObjectiveJ.FileDependency(new CFURL("+JSON.stringify(dependency.path())+"),"+JSON.stringify(dependency.isLocal())+")"
}).join(",");
ObjectiveJFlattener.prototype.serializeFunctions = function() {
var inlineFunctions = true;//this.options.inlineFunctions;
var func = aFileExecutable._function.toString();
// HACK
func = func.replace(", require, exports, module, system, print, window", "");
var outputFiles = {};
this.functionsBuffer.push("var path = "+JSON.stringify(this.rootPath.relative(aFileExecutable.path()).toString())+";");
this.functionsBuffer.push("new ObjectiveJ.FileExecutable(path,"+
"new ObjectiveJ.Executable(null, ["+deps+"], path, "+func+"));");
var _cachedExecutableFunctions = {};
this.require("objective-j").FileExecutable.allFileExecutables().forEach(function(executable) {
var path = executable.path();
if (inlineFunctions)
{
// stringify the function, replacing arguments
var functionString = executable._function.toString().replace(", require, exports, module, system, print, window", ""); // HACK
var relative = this.rootPath.relative(path).toString();
this.functionsBuffer.push("ObjectiveJ.FileExecutable._cacheFunction(new CFURL("+JSON.stringify(relative)+", baseURL),\n"+functionString+");");
}
var bundle = this.context.global.CFBundle.bundleContainingURL(path);
if (bundle && bundle.infoDictionary())
{
var executablePath = bundle.executablePath(),
relativeToBundle = FILE.relative(FILE.join(bundle.path(), ""), path);
if (executablePath)
{
if (inlineFunctions)
{
// remove the code since we're inlining the functions
executable._code = "alert("+JSON.stringify(relativeToBundle)+");";
}
if (!outputFiles[executablePath])
{
outputFiles[executablePath] = [];
outputFiles[executablePath].push("@STATIC;1.0;");
}
var fileContents = executable.toMarkedString();
outputFiles[executablePath].push("p;" + relativeToBundle.length + ";" + relativeToBundle);
outputFiles[executablePath].push("t;" + fileContents.length + ";" + fileContents);
// stream.print("Adding \0green(" + this.rootPath.relative(path) + "\0) to \0cyan(" + this.rootPath.relative(executablePath) + "\0)");
}
}
else
CPLog.warn("No bundle (or info dictionary for) " + rootPath.relative(path));
}, this);
for (var executablePath in outputFiles)
{
var relative = this.rootPath.relative(executablePath).toString();
var contents = outputFiles[executablePath].join("");
this.filesToCache[relative] = contents;
}
}
ObjectiveJFlattener.prototype.serializeFileCache = function() {
for (var relative in this.filesToCache) {
var contents = this.filesToCache[relative];
print("caching: " + relative + " => " + (contents == null ? 404 : 200));
if (contents == null)
this.fileCacheBuffer.push("CFHTTPRequest._cacheRequest(new CFURL("+JSON.stringify(relative)+", baseURL), 404);");
else
this.fileCacheBuffer.push("CFHTTPRequest._cacheRequest(new CFURL("+JSON.stringify(relative)+", baseURL), 200, {}, "+JSON.stringify(contents)+");");
}
}
ObjectiveJFlattener.prototype.setupFileCache = function() {
var paths = {};
UTIL.update(paths, this.requestedURLs);
this.options.paths.forEach(function(relativePath) {
paths[this.rootPath.join(relativePath)] = true;
}, this);
Object.keys(paths).forEach(function(absolute) {
var relative = this.rootPath.relative(absolute).toString();
if (relative.indexOf("..") === 0)
{
print("skipping (parent of app root): " + absolute);
return;
}
if (FILE.isFile(absolute))
{
// if (this.options.maxCachedSize && FILE.size(absolute) > this.options.maxCachedSize)
// {
// print("skipping (larger than "+this.options.maxCachedSize+" bytes): " + absolute);
// return;
// }
var contents = FILE.read(absolute, { charset : "UTF-8" });
this.filesToCache[relative] = contents;
} else {
this.filesToCache[relative] = null;
}
}, this);
}
ObjectiveJFlattener.prototype.serializeStaticResources = function(node, depth) {
depth = depth || 0;
var bundle = this.context.global.CFBundle.bundleContainingURL(node.URL());
var bundlePath;
if (!bundle) {
stream.print("\0yellow(Warning:\0) No bundle for path: \0cyan("+node.URL()+"\0)");
}
else if ((bundlePath = bundle.bundlePath()) && !this._outputBundles[bundlePath]) {
this._outputBundles[bundlePath] = bundle;
stream.print("Writing bundle: \0cyan("+bundlePath+"\0)");
print(bundle.infoDictionary())
var relative = this.rootPath.relative(bundlePath).toString();
this.bundleBuffer.push("var bundle = new CFBundle("+
"new CFURL("+(relative ? JSON.stringify(relative) : "appURL")+", ObjectiveJ.pageURL)"+
");");
this.bundleBuffer.push("bundle._loadStatus = " + (1<<4) + ";");
this.bundleBuffer.push("bundle._isValid = true;");
if (bundle.infoDictionary()) {
this.bundleBuffer.push("bundle._infoDictionary = CFPropertyList.propertyListFromString(" +
JSON.stringify(CPPropertyListCreateData(bundle.infoDictionary()).rawString()) + ");");
}
}
// not the root node:
if (depth > 0) {
this.resourceBuffer.push("newNode = new ObjectiveJ.StaticResource(new CFURL(" +
JSON.stringify(node.name()) + "," +
"currentNode.URL().asDirectoryPathURL()" +
"), currentNode, " +
JSON.stringify(node.isDirectory()) + ", " +
JSON.stringify(node.isResolved()) + ");");
} else {
this.resourceBuffer.push("newNode = applicationRoot;");
}
// var contents = node.contents();
// if (contents) {
// this.resourceBuffer.push("newNode._contents = " + JSON.stringify(contents) + ";");
// }
if (!node.children())
return;
this.resourceBuffer.push("nodeStack.push(currentNode);");
this.resourceBuffer.push("currentNode = newNode;");
var children = node.children();
for (var name in children) {
this.serializeStaticResources(children[name], depth+1);
}
this.resourceBuffer.push("currentNode = nodeStack.pop();");
}
// "$1" is the matching indentation
var scriptTagsBefore = '$1<script type = "text/javascript">\n$1 OBJJ_AUTO_BOOTSTRAP = false;\n$1</script>';
var scriptTagsAfter = '$1<script type = "text/javascript" src = "Application.js"></script>';
var scriptTagsBefore =
'$1<script type = "text/javascript">\n'+
'$1 OBJJ_AUTO_BOOTSTRAP = false;\n'+
'$1</script>';
var scriptTagsAfter =
'$1<script type="text/javascript" src="Application.js" charset="UTF-8"></script>';
// enable CPLog:
// scriptTagsAfter = '$1<script type="text/javascript">\n$1 CPLogRegister(CPLogConsole);\n$1</script>\n' + scriptTagsAfter;
function rewriteMainHTML(indexHTMLPath) {
if (indexHTMLPath.isFile()) {
var indexHTML = indexHTMLPath.read();
var indexHTML = indexHTMLPath.read({ charset : "UTF-8" });
// inline the Application.js if it's smallish
var applicationJSPath = indexHTMLPath.dirname().join("Application.js");
if (applicationJSPath.size() < 10*1024) {
// escape any dollar signs by replacing them with two
// then indent by splitting/joining on newlines
scriptTagsAfter =
'$1<script type="text/javascript">\n'+
'$1 ' + applicationJSPath.read({ charset : "UTF-8" }).replace(/\$/g, "$$$$").split("\n").join("\n$1 ")+'\n'+
'$1</script>';
}
// attempt to find Objective-J script tag and add ours
var newIndexHTML = indexHTML.replace(/([ \t]+)<script[^>]+Objective-J\.js[^>]+>(?:\s*<\/script>)?/,
@@ -226,7 +343,7 @@ function rewriteMainHTML(indexHTMLPath) {
if (newIndexHTML !== indexHTML) {
stream.print("\0green(Modified: "+indexHTMLPath+".\0)");
indexHTMLPath.write(newIndexHTML);
indexHTMLPath.write(newIndexHTML, { charset : "UTF-8" });
return;
}
} else {
+17
View File
@@ -10,6 +10,8 @@ require("narwhal").ensureEngine("rhino");
var FILE = require("file");
var OS = require("os");
var CACHEMANIFEST = require("objective-j/cache-manifest");
var stream = require("term").stream;
var parser = new (require("args").Parser)();
@@ -31,11 +33,20 @@ parser.option("-f", "--force", "force")
.set(true)
.help("Force overwriting OUTPUT_PROJECT if it exists");
parser.option("--index", "index")
.def("index.html")
.set()
.help("The root HTML file to modify (default: index.html) (NOTE: currently only used by '--manifest' option)");
parser.option("-p", "--pngcrush", "png")
.def(false)
.set(true)
.help("Run pngcrush on all PNGs (pngcrush must be installed!)");
parser.option("--manifest", "manifest")
.set(true)
.help("Generate HTML5 cache manifest.");
parser.option("-v", "--verbose", "verbose")
.def(false)
.set(true)
@@ -146,6 +157,12 @@ function press(rootPath, outputPath, options) {
if (options.png) {
pngcrushDirectory(outputPath);
}
if (options.manifest) {
CACHEMANIFEST.generateManifest(outputPath, {
index : outputPath.join(options.index)
});
}
}
function pressEnvironment(rootPath, outputFiles, environment, options) {
+70
View File
@@ -0,0 +1,70 @@
var FILE = require("file");
var OS = require("os");
var NATIVEHOST_SOURCE = FILE.path(module.path).dirname().dirname().dirname().join("support", "NativeHost.app");
exports.buildNativeHost = function(rootPath, buildNative, options) {
options = options || {};
options.index = options.index || "index.html";
rootPath = FILE.path(rootPath);
buildNative = FILE.path(buildNative);
if (buildNative.exists())
buildNative.rmtree();
buildNative.dirname().mkdirs();
// FIXME: Narwhal doesn't preserve permissions
// FILE.copyTree(NATIVEHOST_SOURCE, buildNative);
OS.system(["cp", "-r", NATIVEHOST_SOURCE, buildNative]);
FILE.chmod(buildNative.join("Contents", "MacOS", "NativeHost"), 0755);
var rootBaseName = rootPath.basename();
var buildClientDirectory = buildNative.join("Contents", "Resources", rootBaseName);
FILE.mkdirs(FILE.dirname(buildClientDirectory));
// FILE.copyTree(rootPath, buildClientDirectory);
OS.system(["cp", "-r", rootPath, buildClientDirectory]);
var defaultBundleName = buildNative.basename().match(/^(.*)(\.app)?$/)[1];
function mergePlist(plist, path) {
var otherPlist = CFPropertyList.readPropertyListFromFile(String(path));
otherPlist.keys().forEach(function(key) {
var value = otherPlist.valueForKey(key);
plist.setValueForKey(key, value);
if (key === "CPBundleName")
plist.setValueForKey("CFBundleName", value);
if (key === "CFBundleIconFile") {
var iconPath = rootPath.join("Resources", value);
if (iconPath.isFile())
iconPath.copy(buildNative.join("Contents", "Resources", value));
else
print("Warning: CFBundleIconFile references " + value + " but does not exist in the resources directory.");
}
if (key === "CFBundleExecutable") {
buildNative.join("Contents", "MacOS", "NativeHost").rename(value);
// FIXME:
FILE.chmod(buildNative.join("Contents", "MacOS", value), 0755);
}
});
}
CFPropertyList.modifyPlist(buildNative.join("Contents", "Info.plist"), function(plist) {
plist.setValueForKey("CFBundleName", defaultBundleName);
plist.setValueForKey("NHInitialResource", FILE.join(rootBaseName, options.index));
// merge Cappuccino plist
var cappPlistPath = rootPath.join("Info.plist");
if (cappPlistPath.isFile())
mergePlist(plist, cappPlistPath);
if (options.extraPlistPath)
mergePlist(plist, options.extraPlistPath);
});
}
@@ -5,6 +5,8 @@ var Context = require("interpreter").Context;
ObjectiveJRuntimeAnalyzer = function(rootPath)
{
this.rootPath = rootPath;
this.rootURL = new CFURL(String(rootPath));
this.context = new Context();
this.scope = setupObjectiveJ(this.context);
@@ -28,6 +30,19 @@ ObjectiveJRuntimeAnalyzer = function(rootPath)
var url = this.executableURL();
return url ? url.absoluteURL().path() : null;
}
this.require("cappuccino/objj-flatten-additions");
if (!this.context.global.CFHTTPRequest._lookupCachedRequest)
print("Warning: CFHTTPRequest._lookupCachedRequest. Need to import objj-flatten-additions module.");
var requestedURLs = this.requestedURLs = {};
var _lookupCachedRequest = this.context.global.CFHTTPRequest._lookupCachedRequest;
this.context.global.CFHTTPRequest._lookupCachedRequest = function(aURL) {
var path = new CFURL(aURL, this.rootURL).absoluteURL().path();
requestedURLs[path] = true;
return _lookupCachedRequest.apply(null, arguments);
}
}
ObjectiveJRuntimeAnalyzer.prototype.setIncludePaths = function(includePaths) {
@@ -0,0 +1,57 @@
var URLCache = { };
CFHTTPRequest.prototype.open = function(/*String*/ method, /*String*/ url, /*Boolean*/ async, /*String*/ user, /*String*/ password)
{
var cachedRequest = CFHTTPRequest._lookupCachedRequest(url);
if (cachedRequest)
{
var self = this;
this._nativeRequest = cachedRequest;
this._nativeRequest.onreadystatechange = function()
{
ObjectiveJ.determineAndDispatchHTTPRequestEvents(self);
};
}
return this._nativeRequest.open(method, url, async, user, password);
}
CFHTTPRequest._cacheRequest = function(/*CFURL|String*/ aURL, /*Number*/ status, /*Object*/ headers, /*String*/ body)
{
URLCache[aURL] = new MockXMLHttpRequest(status, headers, body);
}
CFHTTPRequest._lookupCachedRequest = function(/*CFURL|String*/ aURL)
{
return URLCache[aURL];
}
function MockXMLHttpRequest(status, headers, body)
{
this.readyState = CFHTTPRequest.UninitializedState;
this.status = status || 200;
this.statusText = "";
this.responseText = body || "";
this._responseHeaders = headers || {};
};
MockXMLHttpRequest.prototype.open = function(method, url, async, user, password)
{
this.readyState = CFHTTPRequest.LoadingState;
this.async = async;
};
MockXMLHttpRequest.prototype.send = function(body)
{
var self = this;
self.responseText = self.responseText.toString();
function complete() {
for (self.readyState = CFHTTPRequest.LoadedState; self.readyState <= CFHTTPRequest.CompleteState; self.readyState++)
self.onreadystatechange();
}
(self.async ? ObjectiveJ.Asynchronous(complete) : complete)();
};
MockXMLHttpRequest.prototype.onreadystatechange = function() {};
MockXMLHttpRequest.prototype.abort = function() {};
MockXMLHttpRequest.prototype.setRequestHeader = function(header, value) {};
MockXMLHttpRequest.prototype.getAllResponseHeaders = function() { return this._responseHeaders; };
MockXMLHttpRequest.prototype.getResponseHeader = function(header) { return this._responseHeaders[header]; };
MockXMLHttpRequest.prototype.overrideMimeType = function(mimetype) {};
+170 -150
View File
@@ -37,7 +37,7 @@
- (id)initWithArray:(CPArray)anArray
{
self = [super init];
if (self)
{
_array = anArray;
@@ -67,13 +67,13 @@
- (id)initWithArray:(CPArray)anArray
{
self = [super init];
if (self)
{
_array = anArray;
_index = [_array count];
}
return self;
}
@@ -87,7 +87,7 @@
@end
/*!
/*!
@class CPArray
@brief A mutable array backed by a JavaScript Array.
@ingroup foundation
@@ -145,10 +145,10 @@
{
var i = 2,
array = [[self alloc] init],
argument;
count = arguments.length;
for(; i < arguments.length && (argument = arguments[i]) != nil; ++i)
array.push(argument);
for (; i < count; ++i)
array.push(arguments[i]);
return array;
}
@@ -182,10 +182,10 @@
- (id)initWithArray:(CPArray)anArray
{
self = [super init];
if (self)
[self setArray:anArray];
return self;
}
@@ -203,22 +203,22 @@
return [self initWithArray:anArray];
self = [super init];
if (self)
{
var index = 0,
count = [anArray count];
for(; index < count; ++index)
for (; index < count; ++index)
{
if (anArray[index].isa)
self[index] = [anArray[index] copy];
// Do a deep/shallow copy?
else
self[index] = anArray;
self[index] = anArray[index];
}
}
return self;
}
@@ -229,12 +229,12 @@
{
// The arguments array contains self and _cmd, so the first object is at position 2.
var i = 2,
argument;
for(; i < arguments.length && (argument = arguments[i]) != nil; ++i)
push(argument);
count = arguments.length;
return self;
for (; i < count; ++i)
push(arguments[i]);
return self;
}
/*!
@@ -246,12 +246,12 @@
- (id)initWithObjects:(id)objects count:(unsigned)aCount
{
self = [super init];
if (self)
{
var index = 0;
for(; index < aCount; ++index)
for (; index < aCount; ++index)
push(objects[index]);
}
@@ -278,97 +278,88 @@
/*!
Returns the index of \c anObject in this array.
If the object is \c nil or not in the array,
If the object is not in the array,
returns \c CPNotFound. It first attempts to find
a match using \c -isEqual:, then \c ==.
a match using \c -isEqual:, then \c ===.
@param anObject the object to search for
*/
- (int)indexOfObject:(id)anObject
{
if (anObject === nil)
return CPNotFound;
var i = 0,
var i = 0,
count = length;
// Only use -isEqual: if our object is a CPObject.
if (anObject.isa)
if (anObject && anObject.isa)
{
for(; i < count; ++i)
if([self[i] isEqual:anObject])
for (; i < count; ++i)
if ([self[i] isEqual:anObject])
return i;
}
// If indexOf exists, use it since it's probably
// If indexOf exists, use it since it's probably
// faster than anything we can implement.
else if (self.indexOf)
return indexOf(anObject);
// Last resort, do a straight forward linear O(N) search.
else
for(; i < count; ++i)
if(self[i] == anObject)
for (; i < count; ++i)
if (self[i] === anObject)
return i;
return CPNotFound;
}
/*!
Returns the index of \c anObject in the array
within \c aRange. It first attempts to find
a match using \c -isEqual:, then \c ==.
a match using \c -isEqual:, then \c ===.
@param anObject the object to search for
@param aRange the range to search within
@return the index of the object, or \c CPNotFound if it was not found.
*/
- (int)indexOfObject:(id)anObject inRange:(CPRange)aRange
{
if (anObject === nil)
return CPNotFound;
var i = aRange.location,
var i = aRange.location,
count = MIN(CPMaxRange(aRange), length);
// Only use isEqual: if our object is a CPObject.
if (anObject.isa)
if (anObject && anObject.isa)
{
for(; i < count; ++i)
if([self[i] isEqual:anObject])
for (; i < count; ++i)
if ([self[i] isEqual:anObject])
return i;
}
// Last resort, do a straight forward linear O(N) search.
else
for(; i < count; ++i)
if(self[i] == anObject)
for (; i < count; ++i)
if (self[i] === anObject)
return i;
return CPNotFound;
}
/*!
Returns the index of \c anObject in the array. The test for equality is done using only \c ==.
Returns the index of \c anObject in the array. The test for equality is done using only \c ===.
@param anObject the object to search for
@return the index of the object in the array. \c CPNotFound if the object is not in the array.
*/
- (int)indexOfObjectIdenticalTo:(id)anObject
{
if (anObject === nil)
return CPNotFound;
// If indexOf exists, use it since it's probably
// If indexOf exists, use it since it's probably
// faster than anything we can implement.
if (self.indexOf)
return indexOf(anObject);
// Last resort, do a straight forward linear O(N) search.
else
{
var index = 0,
var index = 0,
count = length;
for(; index < count; ++index)
if(self[index] === anObject)
for (; index < count; ++index)
if (self[index] === anObject)
return index;
}
return CPNotFound;
}
@@ -382,36 +373,33 @@
*/
- (int)indexOfObjectIdenticalTo:(id)anObject inRange:(CPRange)aRange
{
if (anObject === nil)
return CPNotFound;
// If indexOf exists, use it since it's probably
// If indexOf exists, use it since it's probably
// faster than anything we can implement.
if (self.indexOf)
{
var index = indexOf(anObject, aRange.location);
if (CPLocationInRange(index, aRange))
return index;
}
// Last resort, do a straight forward linear O(N) search.
else
{
var index = aRange.location,
var index = aRange.location,
count = MIN(CPMaxRange(aRange), length);
for(; index < count; ++index)
if(self[index] == anObject)
for (; index < count; ++index)
if (self[index] == anObject)
return index;
}
return CPNotFound;
}
/*!
Returns the index of \c anObject in the array, which must be sorted in the same order as
calling sortUsingSelector: with the selector passed to this method would result in.
calling sortUsingSelector: with the selector passed to this method would result in.
@param anObject the object to search for
@param aSelector the comparison selector to call on each item in the list, the same
selector should have been used to sort the array (or to maintain its sorted order).
@@ -419,12 +407,12 @@
*/
- (unsigned)indexOfObject:(id)anObject sortedBySelector:(SEL)aSelector
{
return [self indexOfObject:anObject sortedByFunction: function(lhs, rhs) { objj_msgSend(lhs, aSelector, rhs); }];
return [self indexOfObject:anObject sortedByFunction:function(lhs, rhs) { objj_msgSend(lhs, aSelector, rhs); }];
}
/*!
Returns the index of \c anObject in the array, which must be sorted in the same order as
calling sortUsingFunction: with the selector passed to this method would result in.
calling sortUsingFunction: with the selector passed to this method would result in.
The function will be called like so:
<pre>
aFunction(anObject, currentObjectInArrayForComparison)
@@ -441,7 +429,7 @@
/*!
Returns the index of \c anObject in the array, which must be sorted in the same order as
calling sortUsingFunction: with the selector passed to this method would result in.
calling sortUsingFunction: with the selector passed to this method would result in.
The function will be called like so:
<pre>
aFunction(anObject, currentObjectInArrayForComparison, context)
@@ -454,10 +442,23 @@
*/
- (unsigned)indexOfObject:(id)anObject sortedByFunction:(Function)aFunction context:(id)aContext
{
if (!aFunction || anObject === undefined)
var result = [self _indexOfObject:anObject sortedByFunction:aFunction context:aContext];
return result >= 0 ? result : CPNotFound;
}
- (unsigned)_indexOfObject:(id)anObject sortedByFunction:(Function)aFunction context:(id)aContext
{
if (!aFunction)
return CPNotFound;
var mid, c, first = 0, last = length - 1;
if (length === 0)
return -1;
var mid,
c,
first = 0,
last = length - 1;
while (first <= last)
{
mid = FLOOR((first + last) / 2);
@@ -476,12 +477,12 @@
}
}
return CPNotFound;
return -first - 1;
}
/*!
Returns the index of \c anObject in the array, which must be sorted in the same order as
calling sortUsingDescriptors: with the descriptors passed to this method would result in.
calling sortUsingDescriptors: with the descriptors passed to this method would result in.
@param anObject the object to search for
@param descriptors the array of descriptors to use to compare each item in the array that we search. the same
descriptors should have been used to sort the array (or to maintain its sorted order).
@@ -496,7 +497,7 @@
result = CPOrderedSame;
while (i < count)
if((result = [descriptors[i++] compareObject:lhs withObject:rhs]) != CPOrderedSame)
if ((result = [descriptors[i++] compareObject:lhs withObject:rhs]) != CPOrderedSame)
return result;
return result;
@@ -509,9 +510,10 @@
- (id)lastObject
{
var count = [self count];
if (!count) return nil;
if (!count)
return nil;
return self[count - 1];
}
@@ -537,7 +539,7 @@
var index = CPNotFound,
objects = [];
while((index = [indexes indexGreaterThanIndex:index]) !== CPNotFound)
while ((index = [indexes indexGreaterThanIndex:index]) !== CPNotFound)
[objects addObject:[self objectAtIndex:index]];
return objects;
@@ -573,11 +575,11 @@
{
if (!aSelector)
[CPException raise:CPInvalidArgumentException reason:"makeObjectsPerformSelector: 'aSelector' can't be nil"];
var index = 0,
var index = 0,
count = length;
for(; index < count; ++index)
for (; index < count; ++index)
objj_msgSend(self[index], aSelector);
}
@@ -592,10 +594,10 @@
if (!aSelector)
[CPException raise:CPInvalidArgumentException reason:"makeObjectsPerformSelector:withObject 'aSelector' can't be nil"];
var index = 0,
var index = 0,
count = length;
for(; index < count; ++index)
for (; index < count; ++index)
objj_msgSend(self[index], aSelector, anObject);
}
@@ -608,7 +610,7 @@
count = length,
argumentsArray = [nil, aSelector].concat(objects || []);
for(; index < count; ++index)
for (; index < count; ++index)
{
argumentsArray[0] = self[index];
objj_msgSend.apply(this, argumentsArray);
@@ -626,12 +628,12 @@
{
if (![anArray count] || ![self count])
return nil;
var i = 0,
count = [self count];
for(; i < count; ++i)
if([anArray containsObject:self[i]])
for (; i < count; ++i)
if ([anArray containsObject:self[i]])
return self[i];
return nil;
@@ -644,23 +646,23 @@
{
if (self === anArray)
return YES;
if(length != anArray.length)
if (anArray === nil || length !== anArray.length)
return NO;
var index = 0,
count = [self count];
for(; index < count; ++index)
for (; index < count; ++index)
{
var lhs = self[index],
rhs = anArray[index];
// If they're not equal, and either doesn't have an isa, or they're !isEqual (not isEqual)
if (lhs !== rhs && (lhs && !lhs.isa || rhs && !rhs.isa || ![lhs isEqual:rhs]))
return NO;
}
return YES;
}
@@ -668,8 +670,8 @@
{
if (self === anObject)
return YES;
if(![anObject isKindOfClass:[CPArray class]])
if (![anObject isKindOfClass:[CPArray class]])
return NO;
return [self isEqualToArray:anObject];
@@ -684,14 +686,9 @@
*/
- (CPArray)arrayByAddingObject:(id)anObject
{
if (anObject === nil || anObject === undefined)
[CPException raise:CPInvalidArgumentException
reason:"arrayByAddingObject: object can't be nil"];
var array = [self copy];
array.push(anObject);
return array;
}
@@ -704,17 +701,17 @@
return slice(0).concat(anArray);
}
/*
/*
- (CPArray)filteredArrayUsingPredicate:(CPPredicate)aPredicate
{
var i= 0,
var i= 0,
count = [self count],
array = [CPArray array];
for(; i<count; ++i)
if(aPredicate.evaluateWithObject(self[i]))
for (; i<count; ++i)
if (aPredicate.evaluateWithObject(self[i]))
array.push(self[i]);
return array;
}
*/
@@ -739,9 +736,9 @@
- (CPArray)sortedArrayUsingDescriptors:(CPArray)descriptors
{
var sorted = [self copy];
[sorted sortUsingDescriptors:descriptors];
return sorted;
}
@@ -764,9 +761,9 @@
- (CPArray)sortedArrayUsingFunction:(Function)aFunction context:(id)aContext
{
var sorted = [self copy];
[sorted sortUsingFunction:aFunction context:aContext];
return sorted;
}
@@ -777,7 +774,7 @@
- (CPArray)sortedArrayUsingSelector:(SEL)aSelector
{
var sorted = [self copy]
[sorted sortUsingSelector:aSelector];
return sorted;
@@ -811,7 +808,7 @@
count = [self count],
description = '(';
for(; index < count; ++index)
for (; index < count; ++index)
{
if (index === 0)
description += '\n';
@@ -843,11 +840,11 @@
var index = 0,
count = [self count],
array = [];
for(; index < count; ++index)
for (; index < count; ++index)
if (self[index].isa && [self[index] isKindOfClass:[CPString class]] && [filterTypes containsObject:[self[index] pathExtension]])
array.push(self[index]);
return array;
}
@@ -861,8 +858,8 @@
{
var i = 0,
count = [self count];
for(; i < count; ++i)
for (; i < count; ++i)
[self[i] setValue:aValue forKey:aKey];
}
@@ -876,10 +873,10 @@
var i = 0,
count = [self count],
array = [];
for(; i < count; ++i)
for (; i < count; ++i)
array.push([self[i] valueForKey:aKey]);
return array;
}
@@ -893,7 +890,7 @@
{
return slice(0);
}
@end
@implementation CPArray(CPMutableArray)
@@ -956,22 +953,44 @@
{
var indexesCount = [indexes count],
objectsCount = [objects count];
if(indexesCount !== objectsCount)
if (indexesCount !== objectsCount)
[CPException raise:CPRangeException reason:"the counts of the passed-in array (" + objectsCount + ") and index set (" + indexesCount + ") must be identical."];
var lastIndex = [indexes lastIndex];
if(lastIndex >= [self count] + indexesCount)
[CPException raise:CPRangeException reason:"the last index (" + lastIndex + ") must be less than the sum of the original count (" + [self count] + ") and the insertion count (" + indexesCount + ")."];
if (lastIndex >= [self count] + indexesCount)
[CPException raise:CPRangeException reason:"the last index (" + lastIndex + ") must be less than the sum of the original count (" + [self count] + ") and the insertion count (" + indexesCount + ")."];
var index = 0,
currentIndex = [indexes firstIndex];
for (; index < objectsCount; ++index, currentIndex = [indexes indexGreaterThanIndex:currentIndex])
[self insertObject:objects[index] atIndex:currentIndex];
}
- (unsigned)insertObject:(id)anObject inArraySortedByDescriptors:(CPArray)descriptors
{
var index = [self _indexOfObject:anObject sortedByFunction:function(lhs, rhs)
{
var i = 0,
count = [descriptors count],
result = CPOrderedSame;
while (i < count)
if ((result = [descriptors[i++] compareObject:lhs withObject:rhs]) != CPOrderedSame)
return result;
return result;
} context:nil];
if (index < 0)
index = -index - 1;
[self insertObject:anObject atIndex:index];
return index;
}
/*!
Replaces the element at \c anIndex with \c anObject.
The current element at position \c anIndex will be removed from the array.
@@ -990,10 +1009,10 @@
*/
- (void)replaceObjectsAtIndexes:(CPIndexSet)anIndexSet withObjects:(CPArray)objects
{
var i = 0,
var i = 0,
index = [anIndexSet firstIndex];
while(index != CPNotFound)
while (index != CPNotFound)
{
[self replaceObjectAtIndex:index withObject:objects[i++]];
index = [anIndexSet indexGreaterThanIndex:index];
@@ -1034,8 +1053,9 @@
*/
- (void)setArray:(CPArray)anArray
{
if(self == anArray) return;
if (self == anArray)
return;
splice.apply(self, [0, length].concat(anArray));
}
@@ -1073,7 +1093,7 @@
- (void)removeObject:(id)anObject inRange:(CPRange)aRange
{
var index;
while ((index = [self indexOfObject:anObject inRange:aRange]) != CPNotFound)
{
[self removeObjectAtIndex:index];
@@ -1097,7 +1117,7 @@
- (void)removeObjectsAtIndexes:(CPIndexSet)anIndexSet
{
var index = [anIndexSet lastIndex];
while (index != CPNotFound)
{
[self removeObjectAtIndex:index];
@@ -1126,7 +1146,7 @@
{
var index,
count = [self count];
while ((index = [self indexOfObjectIdenticalTo:anObject inRange:aRange]) !== CPNotFound)
{
[self removeObjectAtIndex:index];
@@ -1142,7 +1162,7 @@
{
var index = 0,
count = [anArray count];
for (; index < count; ++index)
[self removeObject:anArray[index]];
}
@@ -1176,11 +1196,11 @@
var i = 0,
count = [descriptors count],
result = CPOrderedSame;
while(i < count)
if((result = [descriptors[i++] compareObject:lhs withObject:rhs]) != CPOrderedSame)
while (i < count)
if ((result = [descriptors[i++] compareObject:lhs withObject:rhs]) != CPOrderedSame)
return result;
return result;
});
}
+11
View File
@@ -153,6 +153,12 @@
continue;
var value = object[key];
if (value === null)
{
[dictionary setObject:[CPNull null] forKey:key];
continue;
}
if (recursively)
{
@@ -521,6 +527,11 @@
return self.toString();
}
- (BOOL)containsKey:(id)aKey
{
var value = [self objectForKey:aKey];
return ((value !== nil) && (value !== undefined));
}
@end
@implementation CPDictionary (CPCoding)
+10 -3
View File
@@ -56,7 +56,7 @@ CPJSONPCallbackReplacementString = @"${JSONP_CALLBACK}";
+ (CPJSONPConnection)connectionWithRequest:(CPURLRequest)aRequest callback:(CPString)callbackParameter delegate:(id)aDelegate
{
return [[[self class] alloc] initWithRequest:aRequest callback:callbackParameter delegate:aDelegate startImmediately:YES];;
return [[[self class] alloc] initWithRequest:aRequest callback:callbackParameter delegate:aDelegate startImmediately:YES];
}
- (id)initWithRequest:(CPURLRequest)aRequest callback:(CPString)aString delegate:(id)aDelegate
@@ -88,7 +88,12 @@ CPJSONPCallbackReplacementString = @"${JSONP_CALLBACK}";
{
CPJSONPConnectionCallbacks["callback"+[self UID]] = function(data)
{
[_delegate connection:self didReceiveData:data];
if ([_delegate respondsToSelector:@selector(connection:didReceiveData:)])
[_delegate connection:self didReceiveData:data];
if ([_delegate respondsToSelector:@selector(connectionDidFinishLoading:)])
[_delegate connectionDidFinishLoading:self];
[self removeScriptTag];
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
@@ -118,7 +123,9 @@ CPJSONPCallbackReplacementString = @"${JSONP_CALLBACK}";
}
catch (exception)
{
[_delegate connection: self didFailWithError: exception];
if ([_delegate respondsToSelector:@selector(connection:didFailWithError:)])
[_delegate connection: self didFailWithError: exception];
[self removeScriptTag];
}
}
+9
View File
@@ -277,5 +277,14 @@ CPUnknownUserInfoKey = @"CPUnknownUserInfoKey";
@end
@implementation CPNull (KeyValueCoding)
- (id)valueForKey:(CPString)aKey
{
return self;
}
@end
@import "CPKeyValueObserving.j"
@import "CPArray+KVO.j"
+11 -5
View File
@@ -163,9 +163,15 @@ var CPArrayClass = Ni
@param data the data from which to read the graph
@return the unarchived object
*/
+ (id)unarchiveObjectWithData:(CPData)data
+ (id)unarchiveObjectWithData:(CPData)aData
{
var unarchiver = [[self alloc] initForReadingWithData:data],
if (!aData)
{
CPLog.error("Null data passed to -[CPKeyedUnarchiver unarchiveObjectWithData:].");
return nil;
}
var unarchiver = [[self alloc] initForReadingWithData:aData],
object = [unarchiver decodeObjectForKey:@"root"];
[unarchiver finishDecoding];
@@ -200,7 +206,7 @@ var CPArrayClass = Ni
- (CPDictionary)_decodeDictionaryOfObjectsForKey:(CPString)aKey
{
var object = _plistObject.valueForKey(aKey),
objectClass = object && object.isa;
objectClass = (object != nil) && object.isa;
if (objectClass === CPDictionaryClass || objectClass === CPMutableDictionaryClass)
{
@@ -315,7 +321,7 @@ var CPArrayClass = Ni
- (id)decodeObjectForKey:(CPString)aKey
{
var object = _plistObject.valueForKey(aKey),
objectClass = object && object.isa;
objectClass = (object != nil) && object.isa;
if (objectClass === CPDictionaryClass || objectClass === CPMutableDictionaryClass)
return _CPKeyedUnarchiverDecodeObjectAtIndex(self, object.valueForKey(_CPKeyedArchiverUIDKey));
@@ -519,7 +525,7 @@ var _CPKeyedUnarchiverDecodeObjectAtIndex = function(self, anIndex)
// If this object is a member of _CPKeyedArchiverValue, then we know
// that it is a wrapper for a primitive JavaScript object.
if (object && (object.isa === _CPKeyedArchiverValueClass))
if ((object != nil) && (object.isa === _CPKeyedArchiverValueClass))
object = [object JSObject];
return object;
+22 -3
View File
@@ -25,7 +25,7 @@
var CPNullSharedNull = nil;
/*!
/*!
@class CPNull
@ingroup foundation
@brief An object representation of \c nil.
@@ -41,7 +41,7 @@ var CPNullSharedNull = nil;
{
if (CPNullSharedNull)
return CPNullSharedNull;
return [super alloc];
}*/
/*!
@@ -53,8 +53,27 @@ var CPNullSharedNull = nil;
{
if (!CPNullSharedNull)
CPNullSharedNull = [[CPNull alloc] init];
return CPNullSharedNull;
}
/*!
Returns CPNull null.
@param aCoder the coder from which to do nothing
@return [CPNull null]
*/
- (id)initWithCoder:(CPCoder)aCoder
{
return [CPNull null];
}
/*!
Writes out nothing to the specified coder.
@param aCoder the coder to which nothing will
be written
*/
- (void)encodeWithCoder:(CPCoder)aCoder
{
}
@end
+1 -1
View File
@@ -61,7 +61,7 @@
- (void)forwardInvocation:(CPInvocation)anInvocation
{
[CPException raise:CPInvalidArgumentException
reason:@"-methodSignatureForSelector: called on abstract CPProxy class."];
reason:@"-forwardInvocation: called on abstract CPProxy class."];
}
// FIXME: This should be moved to the runtime?
+24 -19
View File
@@ -23,7 +23,7 @@
*
* TODO: Needs to implement CPCoding, CPCopying.
*/
@import "CPObject.j"
@import "CPArray.j"
@import "CPNumber.j"
@@ -79,7 +79,7 @@
/*
Creates and returns a set containing the objects in a given argument list.
@param anObject The first object to add to the new set.
@param ... A comma-separated list of objects, ending with nil, to add to the new set. If the same object appears more than once objects, it is added only once to the returned set.
@param ... A comma-separated list of objects, ending with nil, to add to the new set. If the same object appears more than once objects, it is added only once to the returned set.
*/
+ (id)setWithObjects:(id)anObject, ...
{
@@ -89,7 +89,7 @@
for(; i < argLength && ((argument = arguments[i]) !== nil); ++i)
[set addObject:argument];
return set;
}
@@ -112,7 +112,7 @@
_count = 0;
_contents = {};
}
return self;
}
@@ -121,21 +121,21 @@
@param array An array of objects to add to the new set. If the same object appears more than once in array, it is represented only once in the returned set.
*/
- (id)initWithArray:(CPArray)anArray
{
{
if (self = [self init])
{
var count = anArray.length;
while (count--)
[self addObject:anArray[count]];
}
return self;
}
/*
Initializes a newly allocated set with members taken from the specified list of objects.
@param objects A array of objects to add to the new set. If the same object appears more than once objects, it is added only once to the returned set.
@param objects A array of objects to add to the new set. If the same object appears more than once objects, it is added only once to the returned set.
@param count The number of objects from objects to add to the new set.
*/
- (id)initWithObjects:(id)objects count:(unsigned)count
@@ -158,7 +158,7 @@
for(; i < argLength && (argument = arguments[i]) != nil; ++i)
[self addObject:argument];
}
return self;
}
@@ -179,9 +179,9 @@
if (!aSet)
return self;
var contents = aSet._contents;
for (var property in contents)
{
if (contents.hasOwnProperty(property))
@@ -192,7 +192,7 @@
[self addObject:contents[property]];
}
}
return self;
}
@@ -202,13 +202,13 @@
- (CPArray)allObjects
{
var array = [];
for (var property in _contents)
{
if (_contents.hasOwnProperty(property))
array.push(_contents[property]);
}
return array;
}
@@ -222,7 +222,7 @@
if (_contents.hasOwnProperty(property))
return _contents[property];
}
return nil;
}
@@ -236,7 +236,7 @@
if (obj !== undefined && [obj isEqual:anObject])
return YES;
return NO;
}
@@ -277,7 +277,7 @@
@param set The set with which to compare the receiver.
*/
- (BOOL)isEqualToSet:(CPSet)set
{
{
// If both are subsets of each other, they are equal
return self === set || ([self count] === [set count] && [set isSubsetOfSet:self]);
}
@@ -295,7 +295,7 @@
if (![set containsObject:items[i]])
return NO;
}
return YES;
}
@@ -330,7 +330,7 @@
{
if ([self containsObject:object])
return object;
return nil;
}
@@ -467,6 +467,11 @@
}
}
- (CPString)description
{
return @"{(" + [self allObjects].join(", ") + ")}";
}
@end
@implementation CPSet (CPCopying)
+18
View File
@@ -664,6 +664,9 @@ var CPStringRegexSpecialCharacters = [
*/
- (CPString)pathExtension
{
if (lastIndexOf('.') === CPNotFound)
return "";
return substr(lastIndexOf('.') + 1);
}
@@ -699,6 +702,21 @@ var CPStringRegexSpecialCharacters = [
return path;
}
/*!
Deletes the extension of a string.
*/
- (CPString)stringByDeletingPathExtension
{
var extension = [self pathExtension];
if (extension === "")
return self;
if (lastIndexOf('.') < 1)
return self;
return substr(0, [self length] - (extension.length + 1));
}
- (CPString)stringByStandardizingPath
{
return objj_standardize_path(self);
+2 -2
View File
@@ -196,8 +196,8 @@ var CPURLURLStringKey = @"CPURLURLStringKey",
- (id)initWithCoder:(CPCoder)aCoder
{
return [self initWithURLString:[aCoder decodeObjectForKey:CPURLURLStringKey]
baseURL:[aCoder decodeObjectForKey:CPURLBaseURLKey]];
return [self initWithString:[aCoder decodeObjectForKey:CPURLURLStringKey]
relativeToURL:[aCoder decodeObjectForKey:CPURLBaseURLKey]];
}
- (void)encodeWithCoder:(CPCoder)aCoder
+22 -38
View File
@@ -107,14 +107,16 @@ task ("documentation", function()
// Downloads
task ("downloads", ["starter_download", "tools_download"]);
task ("downloads", ["starter_download"]);
$STARTER_README = FILE.join('Tools', 'READMEs', 'STARTER-README');
$STARTER_BOOTSTRAP = 'bootstrap.sh';
$STARTER_DOWNLOAD = FILE.join($BUILD_DIR, 'Cappuccino', 'Starter');
$STARTER_DOWNLOAD_APPLICATION = FILE.join($STARTER_DOWNLOAD, 'NewApplication');
$STARTER_DOWNLOAD_README = FILE.join($STARTER_DOWNLOAD, 'README');
$STARTER_DOWNLOAD_BOOTSTRAP = FILE.join($STARTER_DOWNLOAD, 'bootstrap.sh');
task ("starter_download", [$STARTER_DOWNLOAD_APPLICATION, $STARTER_DOWNLOAD_README, "documentation"], function()
task ("starter_download", [$STARTER_DOWNLOAD_APPLICATION, $STARTER_DOWNLOAD_README, $STARTER_DOWNLOAD_BOOTSTRAP, "documentation"], function()
{
if (FILE.exists($DOCUMENTATION_BUILD))
{
@@ -130,8 +132,8 @@ filedir ($STARTER_DOWNLOAD_APPLICATION, ["CommonJS"], function()
if (OS.system(["capp", "gen", $STARTER_DOWNLOAD_APPLICATION, "-t", "Application", "--noconfig"]))
// FIXME: uncomment this: we get conversion errors
//OS.exit(1); // rake abort if ($? != 0)
{}
OS.exit(1); // rake abort if ($? != 0)
//{}
// No tools means no objective-j gem
// FILE.rm(FILE.join($STARTER_DOWNLOAD_APPLICATION, 'Rakefile'))
});
@@ -141,36 +143,11 @@ filedir ($STARTER_DOWNLOAD_README, [$STARTER_README], function()
cp($STARTER_README, $STARTER_DOWNLOAD_README);
});
$TOOLS_README = FILE.join('Tools', 'READMEs', 'TOOLS-README');
$TOOLS_EDITORS = FILE.join('Tools', 'Editors');
$TOOLS_INSTALLER = FILE.join('Tools', 'Install', 'install-tools');
$TOOLS_DOWNLOAD = FILE.join($BUILD_DIR, 'Cappuccino', 'Tools');
$TOOLS_DOWNLOAD_EDITORS = FILE.join($TOOLS_DOWNLOAD, 'Editors');
$TOOLS_DOWNLOAD_README = FILE.join($TOOLS_DOWNLOAD, 'README');
$TOOLS_DOWNLOAD_INSTALLER = FILE.join($TOOLS_DOWNLOAD, 'install-tools');
$TOOLS_DOWNLOAD_COMMONJS = FILE.join($BUILD_DIR, "Cappuccino", "Tools", "CommonJS", "objective-j");
task ("tools_download", [$TOOLS_DOWNLOAD_EDITORS, $TOOLS_DOWNLOAD_README, $TOOLS_DOWNLOAD_INSTALLER, $TOOLS_DOWNLOAD_COMMONJS]);
filedir ($TOOLS_DOWNLOAD_EDITORS, [$TOOLS_EDITORS], function()
filedir ($STARTER_DOWNLOAD_BOOTSTRAP, [$STARTER_BOOTSTRAP], function()
{
cp_r(FILE.join($TOOLS_EDITORS, '.'), $TOOLS_DOWNLOAD_EDITORS);
});
filedir ($TOOLS_DOWNLOAD_README, [$TOOLS_README], function()
{
cp($TOOLS_README, $TOOLS_DOWNLOAD_README);
});
filedir ($TOOLS_DOWNLOAD_INSTALLER, [$TOOLS_INSTALLER], function()
{
cp($TOOLS_INSTALLER, $TOOLS_DOWNLOAD_INSTALLER);
});
filedir ($TOOLS_DOWNLOAD_COMMONJS, ["CommonJS"], function()
{
rm_rf($TOOLS_DOWNLOAD_COMMONJS);
cp_r($COMMONJS_PRODUCT, $TOOLS_DOWNLOAD_COMMONJS);
var bootstrap = FILE.read($STARTER_BOOTSTRAP, { charset : "UTF-8" }).replace('install_capp=""', 'install_capp="yes"');
FILE.write($STARTER_DOWNLOAD_BOOTSTRAP, bootstrap, { charset : "UTF-8" });
OS.system(["chmod", "+x", $STARTER_DOWNLOAD_BOOTSTRAP]);
});
// Deployment
@@ -233,21 +210,28 @@ task ("demos", function()
{
return this.name();
}
FILE.glob(FILE.join(demosDir, "demos", "**/Info.plist")).map(function(demoPath){
return new Demo(FILE.dirname(demoPath))
}).filter(function(demo){
return !demo.excluded();
}).forEach(function(demo)
{
var outputPath = FILE.join(demosDir, demo.name().replace(/\s/g, "-")+".zip");
OS.system("cd "+OS.enquote(FILE.dirname(demo.path()))+"; zip -ry -8 "+OS.enquote(outputPath)+" "+OS.enquote(demo.path()));
// copy frameworks into the demos
cp_r(FILE.join($STARTER_DOWNLOAD_APPLICATION, "Frameworks"), FILE.join(demo.path(), "Frameworks"));
rm_rf(FILE.join(demo.path(), "Frameworks", "Debug"));
var outputPath = demo.name().replace(/\s/g, "-")+".zip";
OS.system("cd "+OS.enquote(FILE.dirname(demo.path()))+" && zip -ry -8 "+OS.enquote(outputPath)+" "+OS.enquote(FILE.basename(demo.path())));
// remove the frameworks
rm_rf(FILE.join(demo.path(), "Frameworks"));
});
});
// Testing
task("test", ["build", "test-only"]);
task("test", ["CommonJS", "test-only"]);
task("test-only", function()
{
@@ -281,7 +265,7 @@ function pushPackage(path, remote, branch)
{
branch = branch || "master";
var pushPackagesPath = FILE.path(".push-package")
var pushPackagesPath = FILE.path(".push-package");
pushPackagesPath.mkdirs();
+2 -1
View File
@@ -437,12 +437,13 @@ function loadSpritedImagesForBundle(/*Bundle*/ aBundle, success, failure)
CFTotalBytesLoaded += anEvent.request.responseText().length;
decompileStaticFile(aBundle, anEvent.request.responseText(), spritedImagesURL);
aBundle._loadStatus &= ~CFBundleLoadingSpritedImages;
success();
}
catch(anException)
{
failure(anException);
}
success();
}, failure);
}
+10 -6
View File
@@ -196,9 +196,9 @@ CFHTTPRequest.prototype.overrideMimeType = function(/*String*/ aMimeType)
return this._nativeRequest.overrideMimeType(aMimeType);
}
CFHTTPRequest.prototype.open = function(/*...*/)
CFHTTPRequest.prototype.open = function(/*String*/ aMethod, /*String*/ aURL, /*Boolean*/ isAsynchronous, /*String*/ aUser, /*String*/ aPassword)
{
return this._nativeRequest.open(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]);
return this._nativeRequest.open(aMethod, aURL, isAsynchronous, aUser, aPassword);
}
CFHTTPRequest.prototype.send = function(/*Object*/ aBody)
@@ -259,7 +259,7 @@ function FileRequest(/*CFURL*/ aURL, onsuccess, onfailure)
if (aURL.pathExtension() === "plist")
request.overrideMimeType("text/xml");
if (FileRequest.async)
if (exports.asyncLoader)
{
request.onsuccess = Asynchronous(onsuccess);
request.onfailure = Asynchronous(onfailure);
@@ -270,12 +270,16 @@ function FileRequest(/*CFURL*/ aURL, onsuccess, onfailure)
request.onfailure = onfailure;
}
request.open("GET", aURL.absoluteString(), FileRequest.async);
request.open("GET", aURL.absoluteString(), exports.asyncLoader);
request.send("");
}
#ifdef BROWSER
FileRequest.async = YES;
exports.asyncLoader = YES;
#else
FileRequest.async = NO;
exports.asyncLoader = NO;
#endif
// FIXME: Get rid of these when we no longer need Mock requests in flatten.
exports.Asynchronous = Asynchronous;
exports.determineAndDispatchHTTPRequestEvents = determineAndDispatchHTTPRequestEvents;
+10
View File
@@ -91,6 +91,16 @@ CFPropertyList.writePropertyListToFile = function(/*CFPropertyList*/ aPropertyLi
{
return FILE.write(aFilePath, CFPropertyList.stringFromPropertyList(aPropertyList, aFormat), { charset:"UTF-8" });
}
CFPropertyList.modifyPlist = function(/*String*/ aFilePath, /*Function*/ aCallback, /*String*/ aFormat)
{
var string = FILE.read(aFilePath, { charset:"UTF-8" });
var format = CFPropertyList.sniffedFormatOfString(string);
var plist = CFPropertyList.propertyListFromString(string, format);
aCallback(plist);
CFPropertyList.writePropertyListToFile(plist, aFilePath, aFormat || format);
}
#endif
function serializePropertyList(/*CFPropertyList*/ aPropertyList, /*Object*/ serializers)
+25 -7
View File
@@ -314,7 +314,7 @@ function resolveURL(aURL)
resolvedPathComponents.splice(basePathComponents.length - 1, 1);
// If this doesn't start with a "..", then we're simply appending to already standardized paths.
if (pathComponents.length && pathComponents[0] === "..")
if (pathComponents.length && (pathComponents[0] === ".." || pathComponents[0] === "."))
standardizePathComponents(resolvedPathComponents, YES);
resolvedParts.pathComponents = resolvedPathComponents;
@@ -352,19 +352,26 @@ function standardizePathComponents(/*Array*/ pathComponents, /*BOOL*/ inPlace)
var index = 0,
resultIndex = 0,
count = pathComponents.length,
result = inPlace ? pathComponents : [];
result = inPlace ? pathComponents : [],
startsWithPeriod = NO;
for (; index < count; ++index)
{
var component = pathComponents[index];
if (component === "" || component === ".")
if (component === "")
continue;
if (component === ".")
{
startsWithPeriod = resultIndex === 0;
continue;
}
if (component !== ".." || resultIndex === 0 || result[resultIndex - 1] === "..")
{
//if (resultIndex !== index)
result[resultIndex] = component;
result[resultIndex] = component;
resultIndex++;
@@ -375,6 +382,9 @@ function standardizePathComponents(/*Array*/ pathComponents, /*BOOL*/ inPlace)
--resultIndex;
}
if (startsWithPeriod && resultIndex === 0)
result[resultIndex++] = ".";
result.length = resultIndex;
return result;
@@ -505,10 +515,11 @@ CFURL.prototype.hasDirectoryPath = function()
var lastPathComponent = this.lastPathComponent();
hasDirectoryPath = lastPathComponent === "." || lastPathComponent === "..";
this._hasDirectoryPath = hasDirectoryPath;
}
return this._hasDirectoryPath;
return hasDirectoryPath;
}
DISPLAY_NAME(CFURL.prototype.hasDirectoryPath);
@@ -646,7 +657,14 @@ CFURL.prototype.asDirectoryPathURL = function()
if (this.hasDirectoryPath())
return this;
return new CFURL(this.lastPathComponent() + "/", this);
var lastPathComponent = this.lastPathComponent();
// We do this because on Windows the path may start with C: and be
// misinterpreted as a scheme.
if (lastPathComponent !== "/")
lastPathComponent = "./" + lastPathComponent;
return new CFURL(lastPathComponent + "/", this);
}
DISPLAY_NAME(CFURL.prototype.asDirectoryPathURL);
+7
View File
@@ -357,3 +357,10 @@ function _CPLogInitPopup(logWindow)
}, false);
}
#endif
#if COMMONJS
CPLogDefault = CPLogPrint;
#else
CPLogDefault = (typeof window === "object" && window.console) ? CPLogConsole : CPLogPopup;
#endif
+7 -26
View File
@@ -148,37 +148,12 @@ exports.repl = function()
}
}
exports.objj_eval = function(/*String*/ aString)
{
// We need this while code still refers to window.
Executable.setCommonJSArguments(require, exports, module, system, print, window);
var executable = exports.preprocess(aString, "", 0);
if (!executable.hasLoadedFileDependencies())
executable.loadFileDependencies();
// A bit of a hack. Executable compiles the code itself into a function, but we want
// the raw code to eval here.
var code = executable._code;
// Not clear why these should be global, varing them doesn't seem to take effect with evaluateString.
global.objj_executeFile = Executable.fileExecuterForURL(FILE.cwd());
global.objj_importFile = Executable.fileImporterForURL(FILE.cwd());
if (typeof system !== "undefined" && system.engine === "rhino")
return Packages.org.mozilla.javascript.Context.getCurrentContext().evaluateString(global, code, "objj_eval", 0, NULL);
return eval(code);
}
Executable.setCommonJSParameters("require", "exports", "module", "system", "print", "window");
// creates a narwhal factory function in the objj module scope
exports.make_narwhal_factory = function(path)
{
return function(require, exports, module, system, print)
{
Executable.setCommonJSParameters("require", "exports", "module", "system", "print", "window");
Executable.setCommonJSArguments(require, exports, module, system, print, window);
Executable.fileImporterForURL(FILE.dirname(path))(path, YES);
}
@@ -207,5 +182,11 @@ exports.fullVersionString = function() {
);
}
global.ObjectiveJ = {};
for (key in exports)
if (Object.prototype.hasOwnProperty.call(exports, key))
global.ObjectiveJ[key] = exports[key];
if (require.main == module.id)
exports.run(system.args);
@@ -0,0 +1,113 @@
var FILE = require("file");
var MD5 = require("md5");
var FileList = require("jake").FileList;
var BundleTask = require("objective-j/jake/bundletask").BundleTask;
exports.generateManifest = function(productPath, options)
{
options = options || {};
indexFilePath = options.index || FILE.join(productPath, "index.html");
if (!FILE.isFile(indexFilePath)) {
print("Warning: Skipping cache manifest generation, no index file at "+indexFilePath);
return;
}
var index = FILE.read(indexFilePath, { charset : "UTF-8" });
var manifestName = "app.manifest";
var manifestPath = FILE.join(productPath, manifestName);
var manifestAttribute = 'manifest="'+manifestName+'"';
print("Generating cache manifest: " + manifestPath);
var manifestOut = FILE.open(manifestPath, "w", { charset : "UTF-8" });
manifestOut.print("CACHE MANIFEST");
manifestOut.print("");
manifestOut.print("CACHE:");
var list = new FileList(FILE.join(productPath, "**", "*"));
list.exclude(manifestPath);
list.exclude("**/.DS_Store", "**/.htaccess");
list.exclude("**/LICENSE");
list.exclude("**/MHTML*");
list.exclude("**/CommonJS.environment/*");
list.exclude("**/*.cur"); // FIXME: sprite these?
// FIXME: bleh. heuristic for whether index file includes debug frameworks
if (index.indexOf('"Frameworks/Debug"') < 0)
list.exclude("**/Frameworks/Debug/*");
if (options.exclude)
options.exclude.forEach(list.exclude.bind(list));
list.forEach(function(path) {
if (FILE.isFile(path)) {
var relative = FILE.relative(productPath, path);
// FIXME: check the actual sprited images file
// check index for references to file (for spinner.gif, etc)
if (BundleTask.isSpritable(path) && index.indexOf(relative) < 0)
return;
// include hash of each file in comments to expire when any file changes
var hash = MD5.hash(FILE.read(path, "b")).decodeToString("base16");
manifestOut.print("# " + hash);
manifestOut.print(relative);
}
});
manifestOut.print("");
manifestOut.print("NETWORK:");
manifestOut.print("*");
manifestOut.close();
// Insert "manifest" attribute in <html> tag of index file
var matchTag = index.match(/<html[^>]*>/i);
if (matchTag) {
var htmlTag = matchTag[0];
var newHTMLTag = null;
var matchAttr = htmlTag.match(/manifest\s*=\s*"([^"]*)"/i);
if (matchAttr) {
if (matchAttr[1] !== manifestName) {
newHTMLTag = htmlTag.replace(matchAttr[0], manifestAttribute);
}
} else {
newHTMLTag = htmlTag.replace(/>$/, " "+manifestAttribute+">");
}
if (newHTMLTag) {
print("Replacing html tag: \n " + htmlTag + "\nwith:\n " + newHTMLTag);
var newIndex = index.replace(htmlTag, newHTMLTag);
if (newIndex === index) {
print("Warning: No change!");
} else {
FILE.write(indexFilePath, newIndex, { charset : "UTF-8" });
}
}
}
else {
print("Warning: Couldn't find <html> tag in "+indexFilePath);
}
// Add Content-Type "text/cache-manifest" for manifest file to .htaccess
// This allows manifests to work out of the box on Apache (if htaccess overrides are allowed)
var htaccessPath = FILE.join(productPath, ".htaccess");
var htaccess = FILE.isFile(htaccessPath) ? FILE.read(htaccessPath, { charset : "UTF-8" }) : "";
var htaccessOut = FILE.open(htaccessPath, "w", { charset : "UTF-8" });
htaccessOut.print(htaccess);
var openTag = "<Files "+manifestName+">";
if (htaccess.indexOf(openTag) < 0) {
htaccessOut.print("");
htaccessOut.print(openTag);
htaccessOut.print("\tHeader set Content-Type text/cache-manifest");
htaccessOut.print("</Files>");
}
htaccessOut.close();
}
@@ -17,6 +17,8 @@ function ApplicationTask(aName)
this._frameworksPath = "Frameworks";
else
this._frameworksPath = null;
this._shouldGenerateCacheManifest = false;
}
ApplicationTask.__proto__ = BundleTask;
@@ -33,6 +35,7 @@ ApplicationTask.prototype.defineTasks = function()
this.defineFrameworksTask();
this.defineIndexFileTask();
this.defineCacheManifestTask();
}
ApplicationTask.prototype.setIndexFilePath = function(aFilePath)
@@ -59,6 +62,16 @@ ApplicationTask.prototype.frameworksPath = function()
return this._frameworksPath;
}
ApplicationTask.prototype.setShouldGenerateCacheManifest = function(shouldGenerateCacheManifest)
{
this._shouldGenerateCacheManifest = shouldGenerateCacheManifest;
}
ApplicationTask.prototype.shouldGenerateCacheManifest = function()
{
return this._shouldGenerateCacheManifest;
}
ApplicationTask.prototype.defineFrameworksTask = function()
{
// FIXME: platform requires...
@@ -72,7 +85,7 @@ ApplicationTask.prototype.defineFrameworksTask = function()
Jake.fileCreate(newFrameworks, function()
{
if (thisTask._frameworksPath === "capp")
OS.system("capp gen -f --force " + buildPath);
OS.system(["capp", "gen", "-f", "--force", buildPath]);
else if (thisTask._frameworksPath)
{
if (FILE.exists(newFrameworks))
@@ -106,6 +119,23 @@ ApplicationTask.prototype.defineIndexFileTask = function()
this.enhance([buildIndexFilePath]);
}
ApplicationTask.prototype.defineCacheManifestTask = function()
{
if (!this.shouldGenerateCacheManifest())
return;
var productPath = FILE.join(this.buildProductPath(), "");
var indexFilePath = this.buildIndexFilePath();
// TODO: can we conditionally generate based on outdated files?
var manifestPath = FILE.join(productPath, "app.manifest");
Jake.task(manifestPath, function() {
require("../cache-manifest").generateManifest(productPath, { index : indexFilePath });
});
this.enhance([manifestPath]);
}
exports.ApplicationTask = ApplicationTask;
exports.app = function(aName, aFunction)
@@ -16,8 +16,7 @@ var Task = Jake.Task,
function isImage(/*String*/ aFilename)
{
return FILE.isFile(aFilename) &&
UTIL.has([".png", ".jpg", ".jpeg", ".gif", ".tif", ".tiff"], FILE.extension(aFilename).toLowerCase());
return UTIL.has([".png", ".jpg", ".jpeg", ".gif", ".tif", ".tiff"], FILE.extension(aFilename).toLowerCase());
}
function mimeType(/*String*/ aFilename)
@@ -370,14 +369,17 @@ BundleTask.prototype.infoPlist = function()
return anEnvironment.name();
}));
infoPlist.setValueForKey("CPBundleExecutable", this.productName() + ".sj");
infoPlist.setValueForKey("CPBundleEnvironmentsWithImageSprites", this.environments().filter(
var environmentsWithImageSprites = this.environments().filter(
function(anEnvironment)
{
return anEnvironment.spritesImages();
}).map(function(anEnvironment)
return anEnvironment.spritesImages() && task(this.buildProductDataURLPathForEnvironment(anEnvironment)).prerequisites().filter(isImage).length > 0;
}, this).map(function(anEnvironment)
{
return anEnvironment.name();
}));
});
infoPlist.setValueForKey("CPBundleEnvironmentsWithImageSprites", environmentsWithImageSprites);
var principalClass = this.principalClass();
@@ -449,10 +451,14 @@ BundleTask.prototype.resourcesPath = function()
return FILE.join(this.buildProductPath(), "Resources", "");
}
// Don't sprite images larger than 32KB, IE 8 doesn't like it.
BundleTask.isSpritable = function(aResourcePath) {
return isImage(aResourcePath) && FILE.size(aResourcePath) < 32768;
}
BundleTask.prototype.defineResourceTask = function(aResourcePath, aDestinationPath)
{
// Don't sprite images larger than 32KB, IE 8 doesn't like it.
if (this.spritesResources() && isImage(aResourcePath) && FILE.size(aResourcePath) < 32768)
if (this.spritesResources() && BundleTask.isSpritable(aResourcePath))
{
this.environments().forEach(function(/*Environment*/ anEnvironment)
{
@@ -581,7 +587,6 @@ BundleTask.prototype.defineResourceTasks = function()
}, this);
}
var RESOURCES_PATH = FILE.join(FILE.absolute(FILE.dirname(module.path)), "RESOURCES"),
MHTMLTestPath = FILE.join(RESOURCES_PATH, "MHTMLTest.txt");
@@ -595,27 +600,29 @@ BundleTask.prototype.defineSpritedImagesTask = function()
var folder = anEnvironment.name() + ".environment",
resourcesPath = FILE.join(this.buildIntermediatesProductPath(), folder, "Resources", "");
function isDataResource(/*String*/ aFilename)
{
return FILE.isFile(aFilename) && aFilename.indexOf(resourcesPath) === 0 && isImage(aFilename);
}
var productName = this.productName(),
dataURLPath = this.buildProductDataURLPathForEnvironment(anEnvironment);
filedir (dataURLPath, function(aTask)
{
var prerequisites = aTask.prerequisites().filter(isImage);
if (!prerequisites.length)
{
if (FILE.exists(dataURLPath))
FILE.remove(dataURLPath);
return;
}
TERM.stream.print("Creating data URLs file... \0green(" + dataURLPath +"\0)");
var dataURLStream = FILE.open(dataURLPath, "w+", { charset:"UTF-8" });
dataURLStream.write("@STATIC;1.0;");
aTask.prerequisites().forEach(function(aFilename)
prerequisites.forEach(function(aFilename)
{
if (!isDataResource(aFilename))
return;
var resourcePath = "Resources/" + FILE.relative(resourcesPath, aFilename);
dataURLStream.write("u;" + resourcePath.length + ";" + resourcePath);
@@ -636,17 +643,24 @@ BundleTask.prototype.defineSpritedImagesTask = function()
filedir (MHTMLPath, function(aTask)
{
var prerequisites = aTask.prerequisites().filter(isImage);
if (!prerequisites.length)
{
if (FILE.exists(MHTMLPath))
FILE.remove(MHTMLPath);
return;
}
TERM.stream.print("Creating MHTML paths file... \0green(" + MHTMLPath +"\0)");
var MHTMLStream = FILE.open(MHTMLPath, "w+", { charset:"UTF-8" });
MHTMLStream.write("@STATIC;1.0;");
aTask.prerequisites().forEach(function(aFilename)
prerequisites.forEach(function(aFilename)
{
if (!isDataResource(aFilename))
return;
var resourcePath = "Resources/" + FILE.relative(resourcesPath, aFilename),
MHTMLResourcePath = "mhtml:" + FILE.join(folder, "MHTMLData.txt!") + resourcePath;
@@ -663,17 +677,24 @@ BundleTask.prototype.defineSpritedImagesTask = function()
filedir (MHTMLDataPath, function(aTask)
{
var prerequisites = aTask.prerequisites().filter(isImage);
if (!prerequisites.length)
{
if (FILE.exists(MHTMLDataPath))
FILE.remove(MHTMLDataPath);
return;
}
TERM.stream.print("Creating MHTML images file... \0green(" + MHTMLDataPath +"\0)");
var MHTMLDataStream = FILE.open(MHTMLDataPath, "w+", { charset:"UTF-8" });
MHTMLDataStream.write("/*\r\nContent-Type: multipart/related; boundary=\"_ANY_STRING_WILL_DO_AS_A_SEPARATOR\"\r\n\r\n");
aTask.prerequisites().forEach(function(aFilename)
prerequisites.forEach(function(aFilename)
{
if (!isDataResource(aFilename))
return;
var resourcePath = "Resources/" + FILE.relative(resourcesPath, aFilename);
MHTMLDataStream.write("--_ANY_STRING_WILL_DO_AS_A_SEPARATOR\r\n");
+1 -1
View File
@@ -27,7 +27,7 @@ if (typeof window !== "undefined")
window.setNativeTimeout = window.setTimeout;
window.clearNativeTimeout = window.clearTimeout;
window.setNativeInterval = window.setInterval;
window.clearNativeInterval = window.clearNativeInterval;
window.clearNativeInterval = window.clearInterval;
}
// Objective-J Constants
+4
View File
@@ -20,6 +20,10 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifdef BROWSER
CPLogRegister(CPLogDefault);
#endif
// formatting helpers
function objj_debug_object_format(aReceiver)
+55
View File
@@ -0,0 +1,55 @@
GLOBAL(objj_eval) = function(/*String*/ aString)
{
#if COMMONJS
var url = FILE.join(FILE.cwd(), "/");
Executable.setCommonJSParameters("require", "exports", "module", "system", "print", "window");
Executable.setCommonJSArguments(require, exports, module, system, print, window);
#else
var url = exports.pageURL;
#endif
// Temporarily switch the loader to sychronous mode since objj_eval must be synchronous
// therefore you shouldn't use @imports in objj_eval the browser
var asyncLoaderSaved = exports.asyncLoader;
exports.asyncLoader = NO;
var executable = exports.preprocess(aString, url, 0);
if (!executable.hasLoadedFileDependencies())
executable.loadFileDependencies();
// here we setup a scope object containing the free variables that would normally be arguments to the module function
global._objj_eval_scope = {};
global._objj_eval_scope.objj_executeFile = Executable.fileExecuterForURL(url);
global._objj_eval_scope.objj_importFile = Executable.fileImporterForURL(url);
#if COMMONJS
global._objj_eval_scope.require = require;
global._objj_eval_scope.exports = exports;
global._objj_eval_scope.module = module;
global._objj_eval_scope.system = system;
global._objj_eval_scope.print = print;
global._objj_eval_scope.window = window;
#endif
// A bit of a hack. Executable compiles the code itself into a function, but we want
// the raw code to eval here so we can get the result.
// No known way to get the result of a statement except via eval.
var code = "with(_objj_eval_scope){" + executable._code + "\n//*/\n}";
var result;
#if COMMONJS
if (typeof system !== "undefined" && system.engine === "rhino")
result = Packages.org.mozilla.javascript.Context.getCurrentContext().evaluateString(global, code, "objj_eval", 0, NULL);
else
#endif
result = eval(code);
// restore async loader setting
exports.asyncLoader = asyncLoaderSaved;
return result;
}
// deprecated, use global
exports.objj_eval = objj_eval;
+6 -3
View File
@@ -218,10 +218,13 @@ Executable.prototype.loadFileDependencies = function(aCallback)
{
var status = this._fileDependencyStatus;
if (status === ExecutableLoadedFileDependencies)
return aCallback();
if (aCallback)
{
if (status === ExecutableLoadedFileDependencies)
return aCallback();
this._fileDependencyCallbacks.push(aCallback)
this._fileDependencyCallbacks.push(aCallback);
}
if (status === ExecutableUnloadedFileDependencies)
{
+20 -5
View File
@@ -22,7 +22,7 @@
var FileExecutablesForURLStrings = { };
function FileExecutable(/*CFURL|String*/ aURL, /*Executable*/ anExecutable)
function FileExecutable(/*CFURL|String*/ aURL)
{
aURL = makeAbsoluteURL(aURL);
@@ -38,10 +38,7 @@ function FileExecutable(/*CFURL|String*/ aURL, /*Executable*/ anExecutable)
executable = NULL,
extension = aURL.pathExtension();
if (anExecutable)
executable = anExecutable;
else if (fileContents.match(/^@STATIC;/))
if (fileContents.match(/^@STATIC;/))
executable = decompile(fileContents, aURL);
else if (extension === "j" || !extension)
@@ -117,5 +114,23 @@ function decompile(/*String*/ aString, /*CFURL*/ aURL)
dependencies.push(new FileDependency(new CFURL(text), YES));
}
var fn = FileExecutable._lookupCachedFunction(aURL)
if (fn)
return new Executable(code, dependencies, aURL, fn);
return new Executable(code, dependencies, aURL);
}
var FunctionCache = { };
FileExecutable._cacheFunction = function(/*CFURL|String*/ aURL, /*Function*/ fn)
{
aURL = typeof aURL === "string" ? aURL : aURL.absoluteString();
FunctionCache[aURL] = fn;
}
FileExecutable._lookupCachedFunction = function(/*CFURL|String*/ aURL)
{
aURL = typeof aURL === "string" ? aURL : aURL.absoluteString();
return FunctionCache[aURL];
}
+1
View File
@@ -47,6 +47,7 @@
#include "Executable.js"
#include "FileExecutable.js"
#include "Runtime.js"
#include "Eval.js"
#if defined(DEBUG) || defined(COMMONJS)
#include "Debug.js"
#endif
+110 -21
View File
@@ -34,6 +34,8 @@ var TOKEN_ACCESSORS = "accessors",
TOKEN_SUPER = "super",
TOKEN_VAR = "var",
TOKEN_IN = "in",
TOKEN_PRAGMA = "pragma",
TOKEN_MARK = "mark",
TOKEN_EQUAL = '=',
TOKEN_PLUS = '+',
@@ -50,6 +52,7 @@ var TOKEN_ACCESSORS = "accessors",
TOKEN_OPEN_BRACKET = '[',
TOKEN_DOUBLE_QUOTE = '"',
TOKEN_PREPROCESSOR = '@',
TOKEN_HASH = '#',
TOKEN_CLOSE_BRACKET = ']',
TOKEN_QUESTION_MARK = '?',
TOKEN_OPEN_PARENTHESIS = '(',
@@ -171,9 +174,43 @@ var Preprocessor = function(/*String*/ aString, /*CFURL|String*/ aURL, /*unsigne
this._classMethod = false;
this._executable = NULL;
this._classLookupTable = {};
this._classVars = {};
var classObject = new objj_class();
for (var i in classObject)
this._classVars[i] = 1;
this.preprocess(this._tokens, this._buffer);
}
Preprocessor.prototype.setClassInfo = function(className, superClassName, ivars)
{
this._classLookupTable[className] = {superClassName:superClassName, ivars:ivars};
}
Preprocessor.prototype.getClassInfo = function(className)
{
return this._classLookupTable[className];
}
Preprocessor.prototype.allIvarNamesForClassName = function(className)
{
var names = {},
classInfo = this.getClassInfo(className);
while (classInfo)
{
for (var i in classInfo.ivars)
names[i] = 1;
classInfo = this.getClassInfo(classInfo.superClassName);
}
return names;
}
exports.Preprocessor = Preprocessor;
Preprocessor.Flags = { };
@@ -329,6 +366,29 @@ Preprocessor.prototype.directive = function(tokens, aStringBuffer, allowedDirect
return buffer;
}
Preprocessor.prototype.hash = function(tokens, aStringBuffer)
{
// Grab the next token, C preprocessor directives follow '#' immediately.
var buffer = aStringBuffer ? aStringBuffer : new StringBuffer(),
token = tokens.next();
// #pragma (C Preprocessor directive)
if (token === TOKEN_PRAGMA)
{
token = tokens.skip_whitespace();
// '#pragma mark' directive is used in Xcode editor for creating labels,
// which is irrelevant to Cappuccino - just swallow this line
if (token === TOKEN_MARK)
{
while ((token = tokens.next()).indexOf("\n") < 0);
}
}
// if not a #pragma directive, it should not be processed here
else
throw new SyntaxError(this.error_message("*** Expected \"pragma\" to follow # but instead saw \"" + token + "\"."));
}
Preprocessor.prototype.implementation = function(tokens, /*StringBuffer*/ aStringBuffer)
{
var buffer = aStringBuffer,
@@ -384,9 +444,9 @@ Preprocessor.prototype.implementation = function(tokens, /*StringBuffer*/ aStrin
// If we are at an opening curly brace ('{'), then we have an ivar declaration.
if (token == TOKEN_OPEN_BRACE)
{
var ivar_count = 0,
var ivar_names = {},
ivar_count = 0,
declaration = [],
attributes,
accessors = {};
@@ -402,15 +462,16 @@ Preprocessor.prototype.implementation = function(tokens, /*StringBuffer*/ aStrin
}
else if (token == TOKEN_SEMICOLON)
{
if (ivar_count++ == 0)
if (ivar_count++ === 0)
CONCAT(buffer, "class_addIvars(the_class, [");
else
CONCAT(buffer, ", ");
var name = declaration[declaration.length - 1];
CONCAT(buffer, "new objj_ivar(\"" + name + "\")");
ivar_names[name] = 1;
declaration = [];
if (attributes)
@@ -422,7 +483,7 @@ Preprocessor.prototype.implementation = function(tokens, /*StringBuffer*/ aStrin
else
declaration.push(token);
}
// If we have objects in our declaration, the user forgot a ';'.
if (declaration.length)
throw new SyntaxError(this.error_message("*** Expected ';' in ivar declaration, found '}'."));
@@ -433,6 +494,11 @@ Preprocessor.prototype.implementation = function(tokens, /*StringBuffer*/ aStrin
if (!token)
throw new SyntaxError(this.error_message("*** Expected '}'"));
this.setClassInfo(class_name, superclass_name === "Nil" ? null : superclass_name, ivar_names);
// build up the list of illegal method param names
var ivar_names = this.allIvarNamesForClassName(class_name);
for (ivar_name in accessors)
{
var accessor = accessors[ivar_name],
@@ -445,7 +511,7 @@ Preprocessor.prototype.implementation = function(tokens, /*StringBuffer*/ aStrin
if (IS_NOT_EMPTY(instance_methods))
CONCAT(instance_methods, ",\n");
CONCAT(instance_methods, this.method(new Lexer(getterCode)));
CONCAT(instance_methods, this.method(new Lexer(getterCode), ivar_names));
// setter
if (accessor["readonly"])
@@ -469,7 +535,7 @@ Preprocessor.prototype.implementation = function(tokens, /*StringBuffer*/ aStrin
if (IS_NOT_EMPTY(instance_methods))
CONCAT(instance_methods, ",\n");
CONCAT(instance_methods, this.method(new Lexer(setterCode)));
CONCAT(instance_methods, this.method(new Lexer(setterCode), ivar_names));
}
}
else
@@ -478,7 +544,10 @@ Preprocessor.prototype.implementation = function(tokens, /*StringBuffer*/ aStrin
// We must make a new class object for our class definition.
CONCAT(buffer, "objj_registerClassPair(the_class);\n");
}
if (!ivar_names)
var ivar_names = this.allIvarNamesForClassName(class_name);
while ((token = tokens.skip_whitespace()))
{
if (token == TOKEN_PLUS)
@@ -487,10 +556,9 @@ Preprocessor.prototype.implementation = function(tokens, /*StringBuffer*/ aStrin
if (IS_NOT_EMPTY(class_methods))
CONCAT(class_methods, ", ");
CONCAT(class_methods, this.method(tokens));
CONCAT(class_methods, this.method(tokens, this._classVars));
}
else if (token == TOKEN_MINUS)
{
this._classMethod = false;
@@ -498,19 +566,24 @@ Preprocessor.prototype.implementation = function(tokens, /*StringBuffer*/ aStrin
if (IS_NOT_EMPTY(instance_methods))
CONCAT(instance_methods, ", ");
CONCAT(instance_methods, this.method(tokens));
CONCAT(instance_methods, this.method(tokens, ivar_names));
}
// If we reach a # symbol, we may be at a C preprocessor directive.
else if (token == TOKEN_HASH)
{
this.hash(tokens, buffer);
}
// Check if we've reached @end...
else if (token == TOKEN_PREPROCESSOR)
{
// The only preprocessor directive we should ever encounter at this point is @end.
if ((token = tokens.next()) == TOKEN_END)
break;
else
throw new SyntaxError(this.error_message("*** Expected \"@end\", found \"@" + token + "\"."));
}
//else
// throw new SyntaxError(this.error_message("*** Expected a method declaration, or \"@end\", found \"" + token + "\"."));
}
if (IS_NOT_EMPTY(instance_methods))
@@ -560,15 +633,17 @@ Preprocessor.prototype._import = function(tokens)
this._dependencies.push(new FileDependency(new CFURL(URLString), isQuoted));
}
Preprocessor.prototype.method = function(/*Lexer*/ tokens)
Preprocessor.prototype.method = function(/*Lexer*/ tokens, ivar_names)
{
var buffer = new StringBuffer(),
token,
selector = "",
parameters = [],
types = [null];
while((token = tokens.skip_whitespace()) && token != TOKEN_OPEN_BRACE)
ivar_names = ivar_names || {};
while((token = tokens.skip_whitespace()) && token !== TOKEN_OPEN_BRACE && token !== TOKEN_SEMICOLON)
{
if (token == TOKEN_COLON)
{
@@ -593,8 +668,10 @@ Preprocessor.prototype.method = function(/*Lexer*/ tokens)
// Since this follows a colon, this must be the parameter name.
parameters[parameters.length] = token;
if (token in ivar_names)
throw new SyntaxError(this.error_message("*** Method ( "+selector+" ) uses a parameter name that is already in use ( "+token+" )"));
}
else if (token == TOKEN_OPEN_PARENTHESIS)
{
var type = "";
@@ -606,7 +683,6 @@ Preprocessor.prototype.method = function(/*Lexer*/ tokens)
// types[0] is the return argument
types[0] = type || null;
}
// Argument list ", ..."
else if (token == TOKEN_COMMA)
{
@@ -616,12 +692,21 @@ Preprocessor.prototype.method = function(/*Lexer*/ tokens)
// FIXME: Shouldn't allow any more after this.
}
// Build selector name.
else
selector += token;
}
if (token === TOKEN_SEMICOLON)
{
token = tokens.skip_whitespace();
if (token !== TOKEN_OPEN_BRACE)
{
throw new SyntaxError(this.error_message("Invalid semi-colon in method declaration. "+
"Semi-colons are allowed only to terminate the method signature, before the open brace."));
}
}
var index = 0,
count = parameters.length;
@@ -842,6 +927,10 @@ Preprocessor.prototype.preprocess = function(tokens, /*StringBuffer*/ aStringBuf
// If we reach an @ symbol, we are at a preprocessor directive.
else if (token == TOKEN_PREPROCESSOR)
this.directive(tokens, buffer);
// If we reach a # symbol, we may be at a C preprocessor directive.
else if (token == TOKEN_HASH)
this.hash(tokens, buffer);
// If we reach a bracket, we will either be preprocessing a message send, a literal
// array, or an array index.
+7 -1
View File
@@ -143,8 +143,14 @@ StaticResource.resourceAtURL = function(/*CFURL|String*/ aURL, /*BOOL*/ resolveA
resource = resource._children[name];
else if (resolveAsDirectoriesIfNecessary)
resource = new StaticResource(new CFURL(name, resource.URL()), resource, YES, YES);
{
// We do this because on Windows the path may start with C: and be
// misinterpreted as a scheme.
if (name !== "/")
name = "./" + name;
resource = new StaticResource(new CFURL(name, resource.URL()), resource, YES, YES);
}
else
throw new Error("Static Resource at " + aURL + " is not resolved (\"" + name + "\")");
}
+45
View File
@@ -0,0 +1,45 @@
@import <AppKit/CPView.j>
@import <AppKit/CPApplication.j>
[CPApplication sharedApplication]
@implementation CPViewTest : OJTestCase
{
CPView view;
}
- (void)setUp
{
view = [[CPView alloc] initWithFrame:CGRectMakeZero()];
[super setUp];
}
- (void)testCanCreate
{
[self assertTrue:!!view];
}
/*
During the layout process for the view, _CPImageAndTextView.j throws
a ReferenceError with the following:
"hasDOMImageElement" is not defined
The referenced variable is #if PLATFORM(DOM) excluded in all other
instances. While not isolated to the behaviour of a CPView alone, the
following test ensures that pending actions in the _CPDisplayServer can
be flushed without touching unimplemented portions of the test platform
(e.g. the DOM). There are times where we want to confirm that some setting
requiring relayout (e.g. string truncation based on available space), the
following test should help ensure those types of tests are safe to carry
out with ojunit.
Demonstrates issue #562.
*/
- (void)testCanFlushPendingLayoutWork
{
[self assert:undefined same:[_CPDisplayServer run]];
}
@end
+85 -16
View File
@@ -21,8 +21,8 @@
- (void)testsInsertObjectsAtIndexes
{
var array = [CPMutableArray arrayWithObjects:@"one", @"two", @"three", @"four", nil],
newAdditions = [CPArray arrayWithObjects:@"a", @"b", nil],
var array = [CPMutableArray arrayWithObjects:@"one", @"two", @"three", @"four"],
newAdditions = [CPArray arrayWithObjects:@"a", @"b"],
indexes = [CPMutableIndexSet indexSetWithIndex:1];
[indexes addIndex:3];
@@ -31,8 +31,8 @@
[self assert:array equals:[@"one", @"a", @"two", @"b", @"three", @"four"]];
var array = [CPMutableArray arrayWithObjects:@"one", @"two", @"three", @"four", nil],
newAdditions = [CPArray arrayWithObjects:@"a", @"b", nil],
var array = [CPMutableArray arrayWithObjects:@"one", @"two", @"three", @"four"],
newAdditions = [CPArray arrayWithObjects:@"a", @"b"],
indexes = [CPMutableIndexSet indexSetWithIndex:5];
[indexes addIndex:4];
@@ -41,8 +41,8 @@
[self assert:array equals:[@"one", @"two", @"three", @"four", @"a", @"b"]];
var array = [CPMutableArray arrayWithObjects: @"one", @"two", @"three", @"four", nil],
newAdditions = [CPArray arrayWithObjects: @"a", @"b", @"c", nil],
var array = [CPMutableArray arrayWithObjects: @"one", @"two", @"three", @"four"],
newAdditions = [CPArray arrayWithObjects: @"a", @"b", @"c"],
indexes = [CPMutableIndexSet indexSetWithIndex:1];
[indexes addIndex:2];
@@ -53,8 +53,8 @@
[self assert:array equals:[@"one", @"a", @"b", @"two", @"c", @"three", @"four"]];
var array = [CPMutableArray arrayWithObjects: @"one", @"two", @"three", @"four", nil],
newAdditions = [CPArray arrayWithObjects: @"a", @"b", @"c", nil],
var array = [CPMutableArray arrayWithObjects: @"one", @"two", @"three", @"four"],
newAdditions = [CPArray arrayWithObjects: @"a", @"b", @"c"],
indexes = [CPMutableIndexSet indexSetWithIndex:1];
[indexes addIndex:2];
@@ -64,10 +64,9 @@
[self assert:array equals:[@"one", @"a", @"b", @"two", @"three", @"four", @"c"]];
//
var array = [CPMutableArray arrayWithObjects:@"one", @"two", @"three", @"four", nil],
newAdditions = [CPArray arrayWithObjects:@"a", @"b", nil],
var array = [CPMutableArray arrayWithObjects:@"one", @"two", @"three", @"four"],
newAdditions = [CPArray arrayWithObjects:@"a", @"b"],
indexes = [CPMutableIndexSet indexSetWithIndex:5];
[indexes addIndex:6];
@@ -88,10 +87,10 @@
{
var array = [CPMutableArray arrayWithObjects:@"one", @"two", @"three", @"four", nil],
indexes = [CPMutableIndexSet indexSetWithIndex: 2];
[array removeObjectsAtIndexes: indexes];
[self assert:array equals:[@"one", @"two", @"four"]];
[self assert:array equals:[@"one", @"two", @"four", nil]];
}
- (void)testIndexOfObjectSortedByFunction
@@ -155,12 +154,82 @@
}
}
- (void)testInsertObjectInArraySortedByDescriptors
{
var descriptors = [[[CPSortDescriptor alloc] initWithKey:@"intValue" ascending:YES]];
var array = [1, 3, 5];
[array insertObject: 0 inArraySortedByDescriptors:descriptors];
[self assert:[0, 1, 3, 5] equals:array];
array = [1, 3, 5];
[array insertObject: 2 inArraySortedByDescriptors:descriptors];
[self assert:[1, 2, 3, 5] equals:array];
array = [1, 3, 5];
[array insertObject: 1 inArraySortedByDescriptors:descriptors];
[self assert:[1, 1, 3, 5] equals:array];
array = [1, 3, 5];
[array insertObject: 6 inArraySortedByDescriptors:descriptors];
[self assert:[1, 3, 5, 6] equals:array];
array = [1, 3, 5];
[array insertObject: 3 inArraySortedByDescriptors:descriptors];
[self assert:[1, 3, 3, 5] equals:array];
array = [];
[array insertObject: 3 inArraySortedByDescriptors:descriptors];
[self assert:[3] equals:array];
descriptors = [[[CPSortDescriptor alloc] initWithKey:@"intValue" ascending:NO]];
array = [5, 3, 1];
[array insertObject: 0 inArraySortedByDescriptors:descriptors];
[self assert:[5, 3, 1, 0] equals:array];
array = [5, 3, 1];
[array insertObject: 2 inArraySortedByDescriptors:descriptors];
[self assert:[5, 3, 2, 1] equals:array];
array = [5, 3, 1];
[array insertObject: 1 inArraySortedByDescriptors:descriptors];
[self assert:[5, 3, 1, 1] equals:array];
array = [5, 3, 1];
[array insertObject: 6 inArraySortedByDescriptors:descriptors];
[self assert:[6, 5, 3, 1] equals:array];
array = [5, 3, 1];
[array insertObject: 3 inArraySortedByDescriptors:descriptors];
[self assert:[5, 3, 3, 1] equals:array];
array = [];
[array insertObject: 3 inArraySortedByDescriptors:descriptors];
[self assert:[3] equals:array];
}
- (void)testInitWithArrayCopyItems
{
var a = [[CopyableObject new], 2, 3];
var a = [[CopyableObject new], 2, 3, {empty:true}];
var b = [[CPArray alloc] initWithArray:a copyItems:YES];
[self assert:a notEqual:b];
[self assert:a[0] notEqual:b[0]];
[self assert:a[1] equals:b[1]];
[self assert:a[2] equals:b[2]];
[self assertTrue:a[3] === b[3]];
}
- (void)testIsEqualToArray
{
var a = [1, 2, 3],
b = [5];
[self assertTrue:[a isEqualToArray:a]];
[self assertFalse:[a isEqualToArray:b]];
[self assertFalse:[a isEqualToArray:nil]];
}
@end
+8 -6
View File
@@ -63,12 +63,14 @@
- (void)testDescription
{
// Unfortunately the result will be different depending on the testing machine's timezone.
var expectedHour = 23
var expectedMinute = 31;
var offsetHours = Math.floor(new Date().getTimezoneOffset() / 60);
var offsetMinutes = new Date().getTimezoneOffset() - offsetHours * 60;
var expectedString = [CPString stringWithFormat:"2009-02-13 %02d:%02d:30 +%02d%02d", expectedHour-offsetHours, expectedMinute-offsetMinutes, offsetHours, offsetMinutes];
[self assert:expectedString equals: [[CPDate dateWithTimeIntervalSince1970: 1234567890] description]];
var date = [CPDate dateWithTimeIntervalSince1970: 1234567890],
expectedHour = 23,
expectedMinute = 31,
offsetHours = Math.floor(date.getTimezoneOffset() / 60),
offsetMinutes = date.getTimezoneOffset() - offsetHours * 60,
expectedString = [CPString stringWithFormat:"2009-02-13 %02d:%02d:30 +%02d%02d", expectedHour-offsetHours, expectedMinute-offsetMinutes, offsetHours, offsetMinutes];
[self assert:expectedString equals:[date description]];
}
- (void)testCopy

Some files were not shown because too many files have changed in this diff Show More