Merge branch 'master' of https://github.com/brentsimmons/Evergreen
This commit is contained in:
commit
8e36459209
|
@ -7,6 +7,12 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
6581C73820CED60100F4AD34 /* SafariExtensionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6581C73720CED60100F4AD34 /* SafariExtensionHandler.swift */; };
|
||||
6581C73A20CED60100F4AD34 /* SafariExtensionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6581C73920CED60100F4AD34 /* SafariExtensionViewController.swift */; };
|
||||
6581C73D20CED60100F4AD34 /* SafariExtensionViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6581C73B20CED60100F4AD34 /* SafariExtensionViewController.xib */; };
|
||||
6581C74020CED60100F4AD34 /* evergreen-subscribe-to-feed.js in Resources */ = {isa = PBXBuildFile; fileRef = 6581C73F20CED60100F4AD34 /* evergreen-subscribe-to-feed.js */; };
|
||||
6581C74220CED60100F4AD34 /* ToolbarItemIcon.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 6581C74120CED60100F4AD34 /* ToolbarItemIcon.pdf */; };
|
||||
6581C74620CED60100F4AD34 /* Subscribe to Feed.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 6581C73320CED60000F4AD34 /* Subscribe to Feed.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
840D617F2029031C009BC708 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 840D617E2029031C009BC708 /* AppDelegate.swift */; };
|
||||
840D61812029031C009BC708 /* MasterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 840D61802029031C009BC708 /* MasterViewController.swift */; };
|
||||
840D61832029031C009BC708 /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 840D61822029031C009BC708 /* DetailViewController.swift */; };
|
||||
|
@ -32,6 +38,8 @@
|
|||
842E45E51ED8C6B7000A8B52 /* MainWindowSplitView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842E45E41ED8C6B7000A8B52 /* MainWindowSplitView.swift */; };
|
||||
842E45E71ED8C747000A8B52 /* DB5.plist in Resources */ = {isa = PBXBuildFile; fileRef = 842E45E61ED8C747000A8B52 /* DB5.plist */; };
|
||||
843A3B5620311E7700BF76EC /* FeedListOutlineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843A3B5520311E7700BF76EC /* FeedListOutlineView.swift */; };
|
||||
8440C8AD2129F9F5002353D1 /* ArticlesDatabase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 841D4D682106B3E100DD04E6 /* ArticlesDatabase.framework */; };
|
||||
8440C8AE2129F9F5002353D1 /* ArticlesDatabase.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 841D4D682106B3E100DD04E6 /* ArticlesDatabase.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
84411E711FE5FBFA004B527F /* SmallIconProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84411E701FE5FBFA004B527F /* SmallIconProvider.swift */; };
|
||||
8444C8F21FED81840051386C /* OPMLExporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8444C8F11FED81840051386C /* OPMLExporter.swift */; };
|
||||
844B5B591FE9FE4F00C7C76A /* SidebarKeyboardDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844B5B581FE9FE4F00C7C76A /* SidebarKeyboardDelegate.swift */; };
|
||||
|
@ -253,6 +261,13 @@
|
|||
remoteGlobalIDString = 844BEE5A1F0AB3C8004AB7CD;
|
||||
remoteInfo = Articles;
|
||||
};
|
||||
8440C8AF2129F9F5002353D1 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 841D4D5E2106B3E100DD04E6 /* ArticlesDatabase.xcodeproj */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 844BEE361F0AB3AA004AB7CD;
|
||||
remoteInfo = ArticlesDatabase;
|
||||
};
|
||||
846E77391F6EF5D700A165E2 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 846E77301F6EF5D600A165E2 /* Account.xcodeproj */;
|
||||
|
@ -431,6 +446,17 @@
|
|||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
6581C75720CED60100F4AD34 /* Embed App Extensions */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 13;
|
||||
files = (
|
||||
6581C74620CED60100F4AD34 /* Subscribe to Feed.appex in Embed App Extensions */,
|
||||
);
|
||||
name = "Embed App Extensions";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
84B06F681ED37B9000F0B54B /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
@ -445,6 +471,7 @@
|
|||
84C37FB620DD8DBB00CA8CF5 /* RSParser.framework in Embed Frameworks */,
|
||||
84C37FA620DD8D8400CA8CF5 /* RSCore.framework in Embed Frameworks */,
|
||||
846E773E1F6EF67A00A165E2 /* Account.framework in Embed Frameworks */,
|
||||
8440C8AE2129F9F5002353D1 /* ArticlesDatabase.framework in Embed Frameworks */,
|
||||
841D4D6C2106B3ED00DD04E6 /* Articles.framework in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
|
@ -477,6 +504,15 @@
|
|||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
6581C73320CED60000F4AD34 /* Subscribe to Feed.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "Subscribe to Feed.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
6581C73420CED60100F4AD34 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
|
||||
6581C73720CED60100F4AD34 /* SafariExtensionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariExtensionHandler.swift; sourceTree = "<group>"; };
|
||||
6581C73920CED60100F4AD34 /* SafariExtensionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariExtensionViewController.swift; sourceTree = "<group>"; };
|
||||
6581C73C20CED60100F4AD34 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/SafariExtensionViewController.xib; sourceTree = "<group>"; };
|
||||
6581C73E20CED60100F4AD34 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
6581C73F20CED60100F4AD34 /* evergreen-subscribe-to-feed.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = "evergreen-subscribe-to-feed.js"; sourceTree = "<group>"; };
|
||||
6581C74120CED60100F4AD34 /* ToolbarItemIcon.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = ToolbarItemIcon.pdf; sourceTree = "<group>"; };
|
||||
6581C74320CED60100F4AD34 /* Subscribe_to_Feed.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Subscribe_to_Feed.entitlements; sourceTree = "<group>"; };
|
||||
8403E75A201C4A79007F7246 /* FeedListKeyboardDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedListKeyboardDelegate.swift; sourceTree = "<group>"; };
|
||||
840D617C2029031C009BC708 /* Evergreen.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Evergreen.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
840D617E2029031C009BC708 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
|
@ -672,6 +708,13 @@
|
|||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
6581C73020CED60000F4AD34 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
840D61792029031C009BC708 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
@ -705,6 +748,7 @@
|
|||
846E773D1F6EF67A00A165E2 /* Account.framework in Frameworks */,
|
||||
84C37FA520DD8D8400CA8CF5 /* RSCore.framework in Frameworks */,
|
||||
84FB9A2F1EDCD6C4003D53B9 /* Sparkle.framework in Frameworks */,
|
||||
8440C8AD2129F9F5002353D1 /* ArticlesDatabase.framework in Frameworks */,
|
||||
841D4D6B2106B3ED00DD04E6 /* Articles.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -719,6 +763,20 @@
|
|||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
6581C73620CED60100F4AD34 /* Safari Extension */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6581C73720CED60100F4AD34 /* SafariExtensionHandler.swift */,
|
||||
6581C73920CED60100F4AD34 /* SafariExtensionViewController.swift */,
|
||||
6581C73B20CED60100F4AD34 /* SafariExtensionViewController.xib */,
|
||||
6581C73E20CED60100F4AD34 /* Info.plist */,
|
||||
6581C73F20CED60100F4AD34 /* evergreen-subscribe-to-feed.js */,
|
||||
6581C74120CED60100F4AD34 /* ToolbarItemIcon.pdf */,
|
||||
6581C74320CED60100F4AD34 /* Subscribe_to_Feed.entitlements */,
|
||||
);
|
||||
path = "Safari Extension";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
840D617D2029031C009BC708 /* Evergreen-iOS */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -1090,6 +1148,7 @@
|
|||
840D617D2029031C009BC708 /* Evergreen-iOS */,
|
||||
840D61942029031D009BC708 /* Evergreen-iOSTests */,
|
||||
840D619F2029031E009BC708 /* Evergreen-iOSUITests */,
|
||||
6581C73620CED60100F4AD34 /* Safari Extension */,
|
||||
84FB9A2C1EDCD6A4003D53B9 /* Frameworks */,
|
||||
849C64741ED37A5D003D8FC0 /* EvergreenTests */,
|
||||
D5907CDA2002F084005947E5 /* xcconfig */,
|
||||
|
@ -1114,6 +1173,7 @@
|
|||
840D617C2029031C009BC708 /* Evergreen.app */,
|
||||
840D61912029031D009BC708 /* Evergreen-iOSTests.xctest */,
|
||||
840D619C2029031D009BC708 /* Evergreen-iOSUITests.xctest */,
|
||||
6581C73320CED60000F4AD34 /* Subscribe to Feed.appex */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
|
@ -1278,6 +1338,7 @@
|
|||
children = (
|
||||
847752FE2008879500D93690 /* CoreServices.framework */,
|
||||
84FB9A2D1EDCD6B8003D53B9 /* Sparkle.framework */,
|
||||
6581C73420CED60100F4AD34 /* Cocoa.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
path = Evergreen/Extensions;
|
||||
|
@ -1358,6 +1419,23 @@
|
|||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
6581C73220CED60000F4AD34 /* Subscribe to Feed */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 6581C75620CED60100F4AD34 /* Build configuration list for PBXNativeTarget "Subscribe to Feed" */;
|
||||
buildPhases = (
|
||||
6581C72F20CED60000F4AD34 /* Sources */,
|
||||
6581C73020CED60000F4AD34 /* Frameworks */,
|
||||
6581C73120CED60000F4AD34 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = "Subscribe to Feed";
|
||||
productName = "Subscribe to Feed";
|
||||
productReference = 6581C73320CED60000F4AD34 /* Subscribe to Feed.appex */;
|
||||
productType = "com.apple.product-type.app-extension";
|
||||
};
|
||||
840D617B2029031C009BC708 /* Evergreen-iOS */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 840D61A32029031E009BC708 /* Build configuration list for PBXNativeTarget "Evergreen-iOS" */;
|
||||
|
@ -1420,6 +1498,7 @@
|
|||
849C645E1ED37A5D003D8FC0 /* Resources */,
|
||||
84C987A52000AC9E0066B150 /* ShellScript */,
|
||||
84B06F681ED37B9000F0B54B /* Embed Frameworks */,
|
||||
6581C75720CED60100F4AD34 /* Embed App Extensions */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
|
@ -1432,6 +1511,7 @@
|
|||
84C37FB820DD8DBB00CA8CF5 /* PBXTargetDependency */,
|
||||
84C37FC820DD8E1D00CA8CF5 /* PBXTargetDependency */,
|
||||
841D4D6E2106B3ED00DD04E6 /* PBXTargetDependency */,
|
||||
8440C8B02129F9F5002353D1 /* PBXTargetDependency */,
|
||||
);
|
||||
name = Evergreen;
|
||||
productName = Evergreen;
|
||||
|
@ -1467,6 +1547,10 @@
|
|||
LastUpgradeCheck = 0930;
|
||||
ORGANIZATIONNAME = "Ranchero Software";
|
||||
TargetAttributes = {
|
||||
6581C73220CED60000F4AD34 = {
|
||||
DevelopmentTeam = M8L2WTLA8W;
|
||||
ProvisioningStyle = Manual;
|
||||
};
|
||||
840D617B2029031C009BC708 = {
|
||||
CreatedOnToolsVersion = 9.3;
|
||||
DevelopmentTeam = 9C84TZ7Q6Z;
|
||||
|
@ -1553,6 +1637,7 @@
|
|||
840D617B2029031C009BC708 /* Evergreen-iOS */,
|
||||
840D61902029031D009BC708 /* Evergreen-iOSTests */,
|
||||
840D619B2029031D009BC708 /* Evergreen-iOSUITests */,
|
||||
6581C73220CED60000F4AD34 /* Subscribe to Feed */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
@ -1708,6 +1793,16 @@
|
|||
/* End PBXReferenceProxy section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
6581C73120CED60000F4AD34 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
6581C74220CED60100F4AD34 /* ToolbarItemIcon.pdf in Resources */,
|
||||
6581C73D20CED60100F4AD34 /* SafariExtensionViewController.xib in Resources */,
|
||||
6581C74020CED60100F4AD34 /* evergreen-subscribe-to-feed.js in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
840D617A2029031C009BC708 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
@ -1780,11 +1875,20 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "# See https://blog.curtisherbert.com/automated-build-numbers/\n\ngit=`sh /etc/profile; which git`\nbranch_name=`$git symbolic-ref HEAD | sed -e 's,.*/\\\\(.*\\\\),\\\\1,'`\ngit_count=`$git rev-list $branch_name |wc -l | sed 's/^ *//;s/ *$//'`\nsimple_branch_name=`$git rev-parse --abbrev-ref HEAD`\n\nbuild_number=\"$git_count\"\nif [ $CONFIGURATION != \"Release\" ]; then\nbuild_number+=\"-$simple_branch_name\"\nfi\n\nplist=\"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}\"\ndsym_plist=\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist\"\n\n/usr/libexec/PlistBuddy -c \"Set :CFBundleVersion $build_number\" \"$plist\"\nif [ -f \"$DSYM_INFO_PLIST\" ] ; then\n/usr/libexec/PlistBuddy -c \"Set :CFBundleVersion $build_number\" \"$dsym_plist\"\nfi";
|
||||
shellScript = "# See https://blog.curtisherbert.com/automated-build-numbers/\n\ngit=`sh /etc/profile; which git`\nbranch_name=`$git symbolic-ref HEAD | sed -e 's,.*/\\\\(.*\\\\),\\\\1,'`\ngit_count=`$git rev-list $branch_name |wc -l | sed 's/^ *//;s/ *$//'`\nsimple_branch_name=`$git rev-parse --abbrev-ref HEAD`\n\nbuild_number=\"$git_count\"\nif [ $CONFIGURATION != \"Release\" ]; then\nbuild_number+=\"-$simple_branch_name\"\nfi\n\nplist=\"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}\"\ndsym_plist=\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist\"\n\n/usr/libexec/PlistBuddy -c \"Set :CFBundleVersion $build_number\" \"$plist\"\nif [ -f \"$DSYM_INFO_PLIST\" ] ; then\n/usr/libexec/PlistBuddy -c \"Set :CFBundleVersion $build_number\" \"$dsym_plist\"\nfi\n";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
6581C72F20CED60000F4AD34 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
6581C73A20CED60100F4AD34 /* SafariExtensionViewController.swift in Sources */,
|
||||
6581C73820CED60100F4AD34 /* SafariExtensionHandler.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
840D61782029031C009BC708 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
@ -1976,6 +2080,11 @@
|
|||
name = Articles;
|
||||
targetProxy = 841D4D6D2106B3ED00DD04E6 /* PBXContainerItemProxy */;
|
||||
};
|
||||
8440C8B02129F9F5002353D1 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
name = ArticlesDatabase;
|
||||
targetProxy = 8440C8AF2129F9F5002353D1 /* PBXContainerItemProxy */;
|
||||
};
|
||||
846E77401F6EF67A00A165E2 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
name = Account;
|
||||
|
@ -2019,6 +2128,14 @@
|
|||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
6581C73B20CED60100F4AD34 /* SafariExtensionViewController.xib */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
6581C73C20CED60100F4AD34 /* Base */,
|
||||
);
|
||||
name = SafariExtensionViewController.xib;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
840D61842029031C009BC708 /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
|
@ -2095,6 +2212,30 @@
|
|||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
6581C74720CED60100F4AD34 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = D5907CE02002F0FA005947E5 /* Evergreen_target.xcconfig */;
|
||||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = "Safari Extension/Subscribe_to_Feed.entitlements";
|
||||
INFOPLIST_FILE = "Safari Extension/Info.plist";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.ranchero.Evergreen.Subscribe-to-Feed";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = macosx;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
6581C74820CED60100F4AD34 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = D5907CE02002F0FA005947E5 /* Evergreen_target.xcconfig */;
|
||||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = "Safari Extension/Subscribe_to_Feed.entitlements";
|
||||
INFOPLIST_FILE = "Safari Extension/Info.plist";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.ranchero.Evergreen.Subscribe-to-Feed";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = macosx;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
840D61A42029031E009BC708 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
|
@ -2545,6 +2686,15 @@
|
|||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
6581C75620CED60100F4AD34 /* Build configuration list for PBXNativeTarget "Subscribe to Feed" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
6581C74720CED60100F4AD34 /* Debug */,
|
||||
6581C74820CED60100F4AD34 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
840D61A32029031E009BC708 /* Build configuration list for PBXNativeTarget "Evergreen-iOS" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
|
|
|
@ -38,7 +38,7 @@ class UnreadIndicatorView: NSView {
|
|||
override func draw(_ dirtyRect: NSRect) {
|
||||
|
||||
if #available(OSX 10.14, *) {
|
||||
let color = isEmphasized && isSelected ? NSColor.white : NSColor.controlAccent
|
||||
let color = isEmphasized && isSelected ? NSColor.white : NSColor.controlAccentColor
|
||||
color.setFill()
|
||||
} else {
|
||||
let color = isEmphasized && isSelected ? NSColor.white : NSColor.systemBlue
|
||||
|
|
|
@ -343,6 +343,7 @@
|
|||
844BEE701F0AB3C9004AB7CD /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.13;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.ranchero.Articles;
|
||||
|
@ -353,6 +354,7 @@
|
|||
844BEE711F0AB3C9004AB7CD /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.13;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.ranchero.Articles;
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11134" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11134"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="SafariExtensionViewController" customModuleProvider="target">
|
||||
<connections>
|
||||
<outlet property="view" destination="c22-O7-iKe" id="vwT-Xx-Aiz"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<customView id="c22-O7-iKe">
|
||||
<rect key="frame" x="0.0" y="0.0" width="330" height="119"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="4Iy-aV-wGF">
|
||||
<rect key="frame" x="103" y="82" width="124" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Subscribe to Feed" id="2Ec-kd-q2K">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
</customView>
|
||||
</objects>
|
||||
</document>
|
|
@ -0,0 +1,64 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Subscribe to Feed</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
<string>com.apple.Safari.extension</string>
|
||||
<key>NSExtensionPrincipalClass</key>
|
||||
<string>$(PRODUCT_MODULE_NAME).SafariExtensionHandler</string>
|
||||
<key>SFSafariContentScript</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>Script</key>
|
||||
<string>evergreen-subscribe-to-feed.js</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>SFSafariToolbarItem</key>
|
||||
<dict>
|
||||
<key>Action</key>
|
||||
<string>Command</string>
|
||||
<key>Identifier</key>
|
||||
<string>Button</string>
|
||||
<key>Image</key>
|
||||
<string>ToolbarItemIcon.pdf</string>
|
||||
<key>Label</key>
|
||||
<string>Subscribe to Feed</string>
|
||||
</dict>
|
||||
<key>SFSafariWebsiteAccess</key>
|
||||
<dict>
|
||||
<key>Allowed Domains</key>
|
||||
<array>
|
||||
<string>*.*</string>
|
||||
</array>
|
||||
<key>Level</key>
|
||||
<string>All</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2018 Ranchero Software. All rights reserved.</string>
|
||||
<key>NSHumanReadableDescription</key>
|
||||
<string>This extension adds a Safari toolbar button for easily subscribing to the syndication feed for the current page.</string>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,128 @@
|
|||
//
|
||||
// SafariExtensionHandler.swift
|
||||
// Subscribe to Feed
|
||||
//
|
||||
// Created by Daniel Jalkut on 6/11/18.
|
||||
// Copyright © 2018 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import SafariServices
|
||||
|
||||
class SafariExtensionHandler: SFSafariExtensionHandler {
|
||||
|
||||
// Safari App Extensions don't support any reasonable means of detecting whether a
|
||||
// specific Safari page was loaded with the benefit of the extension's injected
|
||||
// JavaScript. For this reason a condition can easily be reached where the toolbar
|
||||
// icon is active for a page, but the expected supporting code is not loaded into
|
||||
// the page. To detect this and disable our icon, we use a kind of "ping" trick
|
||||
// to verify whether our code is installed.
|
||||
|
||||
// I tried to use a NSMapTable from String to the closure directly, but Swift
|
||||
// complains that the object has to be a class type.
|
||||
typealias ValidationHandler = (Bool, String) -> Void
|
||||
class ValidationWrapper {
|
||||
let validationHandler: ValidationHandler
|
||||
|
||||
init(validationHandler: @escaping ValidationHandler) {
|
||||
self.validationHandler = validationHandler
|
||||
}
|
||||
}
|
||||
|
||||
// Maps from UUID to a validation wrapper
|
||||
static var gPingPongMap = Dictionary<String, ValidationWrapper>()
|
||||
static var validationQueue = DispatchQueue(label: "Toolbar Validation")
|
||||
|
||||
// Bottleneck for calling through to a validation handler we have saved, and removing it from the list.
|
||||
static func callValidationHandler(forHandlerID handlerID: String, withShouldValidate shouldValidate: Bool) {
|
||||
if let validationWrapper = gPingPongMap[handlerID] {
|
||||
validationWrapper.validationHandler(shouldValidate, "")
|
||||
gPingPongMap.removeValue(forKey: handlerID)
|
||||
}
|
||||
}
|
||||
|
||||
override func messageReceived(withName messageName: String, from page: SFSafariPage, userInfo: [String : Any]?) {
|
||||
if (messageName == "subscribeToFeed") {
|
||||
if let feedURLString = userInfo?["url"] as? String {
|
||||
if let feedURL = URL(string: feedURLString) {
|
||||
// We could do something more Evergreen-specific like invoke an app-specific scheme
|
||||
// to subscribe in the app. For starters we just let NSWorkspace open the URL in the
|
||||
// default "feed:" URL scheme handler.
|
||||
NSWorkspace.shared.open(feedURL)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (messageName == "pong") {
|
||||
if let validationIDString = userInfo?["validationID"] as? String {
|
||||
// Should we validate the button?
|
||||
let shouldValidate = userInfo?["shouldValidate"] as? Bool ?? false
|
||||
SafariExtensionHandler.callValidationHandler(forHandlerID: validationIDString, withShouldValidate:shouldValidate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override func toolbarItemClicked(in window: SFSafariWindow) {
|
||||
window.getActiveTab { (activeTab) in
|
||||
activeTab?.getActivePage(completionHandler: { (activePage) in
|
||||
activePage?.dispatchMessageToScript(withName: "toolbarButtonClicked", userInfo: nil)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
override func validateToolbarItem(in window: SFSafariWindow, validationHandler: @escaping ((Bool, String) -> Void)) {
|
||||
|
||||
let uniqueValidationID = NSUUID().uuidString
|
||||
|
||||
SafariExtensionHandler.validationQueue.sync {
|
||||
|
||||
// Save it right away to eliminate any doubt of whether the handler gets deallocated while
|
||||
// we are waiting for a callback from the getActiveTab or getActivatePage methods below.
|
||||
let validationWrapper = ValidationWrapper(validationHandler: validationHandler)
|
||||
SafariExtensionHandler.gPingPongMap[uniqueValidationID] = validationWrapper
|
||||
|
||||
// To avoid problems with validation handlers dispatched after we've, for example,
|
||||
// switched to a new tab, we aggressively clear out the map of any pending validations,
|
||||
// and focus only on the newest validation request we've been asked for.
|
||||
for thisValidationID in SafariExtensionHandler.gPingPongMap.keys {
|
||||
if thisValidationID != uniqueValidationID {
|
||||
// Default to valid ... we'll know soon enough whether the latest state
|
||||
// is actually still valid or not...
|
||||
SafariExtensionHandler.callValidationHandler(forHandlerID: thisValidationID, withShouldValidate: true);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// See comments above where gPingPongMap is declared. Upon being asked to validate the
|
||||
// toolbar icon for a specific page, we save the validationHandler and postpone calling
|
||||
// it until we have either received a response from our installed JavaScript, or until
|
||||
// a timeout period has elapsed
|
||||
window.getActiveTab { (activeTab) in
|
||||
guard let activeTab = activeTab else {
|
||||
SafariExtensionHandler.callValidationHandler(forHandlerID: uniqueValidationID, withShouldValidate:false);
|
||||
return
|
||||
}
|
||||
|
||||
activeTab.getActivePage { (activePage) in
|
||||
guard let activePage = activePage else {
|
||||
SafariExtensionHandler.callValidationHandler(forHandlerID: uniqueValidationID, withShouldValidate:false);
|
||||
return
|
||||
}
|
||||
|
||||
activePage.getPropertiesWithCompletionHandler { (pageProperties) in
|
||||
if let isActive = pageProperties?.isActive {
|
||||
if isActive {
|
||||
// Capture the uniqueValidationID to ensure it doesn't change out from under us on a future call
|
||||
activePage.dispatchMessageToScript(withName: "ping", userInfo: ["validationID": uniqueValidationID])
|
||||
|
||||
let pongTimeoutInNanoseconds = Int(Double(NSEC_PER_SEC) * 0.5)
|
||||
let timeoutDeadline = DispatchTime.now() + DispatchTimeInterval.nanoseconds(pongTimeoutInNanoseconds)
|
||||
DispatchQueue.main.asyncAfter(deadline: timeoutDeadline, execute: { [timedOutValidationID = uniqueValidationID] in
|
||||
SafariExtensionHandler.callValidationHandler(forHandlerID: timedOutValidationID, withShouldValidate:false)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// SafariExtensionViewController.swift
|
||||
// Subscribe to Feed
|
||||
//
|
||||
// Created by Daniel Jalkut on 6/11/18.
|
||||
// Copyright © 2018 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import SafariServices
|
||||
|
||||
class SafariExtensionViewController: SFSafariExtensionViewController {
|
||||
|
||||
// This would be the place to handle a popover that could, for example, list the possibly multiple feeds offered by a site.
|
||||
static let shared: SafariExtensionViewController = {
|
||||
let shared = SafariExtensionViewController()
|
||||
shared.preferredContentSize = NSSize(width:320, height:240)
|
||||
return shared
|
||||
}()
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,118 @@
|
|||
var thisPageLinkObjects = null;
|
||||
|
||||
// I convert the native "link" node into an object that I can pass out to the global page
|
||||
function objectFromLink(theLink) {
|
||||
var linkObject = new Object();
|
||||
|
||||
linkObject.href = theLink.href;
|
||||
linkObject.type = theLink.type;
|
||||
linkObject.title = theLink.title;
|
||||
|
||||
return linkObject;
|
||||
}
|
||||
|
||||
// Some sites will list feeds with inappropriate or at least less-than-ideal information
|
||||
// in the MIME type attribute. We cover some edge cases here that allow to be passed through,
|
||||
// where they will successfully open as "feed://" URLs in the browser.
|
||||
function isValidFeedLink(theLink) {
|
||||
var isValid = false;
|
||||
|
||||
switch (theLink.type)
|
||||
{
|
||||
case "application/atom+xml":
|
||||
case "application/x.atom+xml":
|
||||
case "application/rss+xml":
|
||||
// These types do not require other criteria.
|
||||
isValid = (theLink.href != null);
|
||||
|
||||
case "text/xml":
|
||||
case "application/rdf+xml":
|
||||
// These types require a title that has "RSS" in it.
|
||||
if (theLink.title && theLink.title.search(/RSS/i) != -1)
|
||||
{
|
||||
isValid = (theLink.href != null);
|
||||
}
|
||||
}
|
||||
|
||||
return isValid;
|
||||
}
|
||||
|
||||
function scanForSyndicationFeeds() {
|
||||
// In case we don't find any, we establish that we have at least tried by setting the
|
||||
// variables to empty instead of null.
|
||||
thisPageLinkObjects = []
|
||||
|
||||
thisPageLinks = document.getElementsByTagName("link");
|
||||
|
||||
for (thisLinkIndex = 0; thisLinkIndex < thisPageLinks.length; thisLinkIndex++)
|
||||
{
|
||||
var thisLink = thisPageLinks[thisLinkIndex];
|
||||
var thisLinkRel = thisLink.getAttribute("rel");
|
||||
if (thisLinkRel == "alternate")
|
||||
{
|
||||
if (isValidFeedLink(thisLink))
|
||||
{
|
||||
thisPageLinkObjects.push(objectFromLink(thisLink));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function subscribeToFeed(theFeed) {
|
||||
// Convert the URL to a feed:// scheme because Safari
|
||||
// will refuse to load e.g. a feed that is listed merely
|
||||
// as "text/xml". We do some preflighting of the link rel
|
||||
// in the PageLoadEnd.js so we can be more confident it's a
|
||||
// good feed: URL.
|
||||
var feedURL = theFeed.href;
|
||||
if (feedURL.match(/^http[s]?:\/\//))
|
||||
{
|
||||
feedURL = feedURL.replace(/^http[s]?:\/\//, "feed://");
|
||||
}
|
||||
else if (feedURL.match(/^feed:/) == false)
|
||||
{
|
||||
feedURL = "feed:" + feedURL;
|
||||
}
|
||||
|
||||
safari.extension.dispatchMessage("subscribeToFeed", { "url": feedURL });
|
||||
}
|
||||
|
||||
function messageHandler(event) {
|
||||
if (event.name === "toolbarButtonClicked")
|
||||
{
|
||||
// Workaround Radar #31182842, in which residual copies of our
|
||||
// app extension may remain loaded in context of pages in Safari,
|
||||
// causing multiple responses to broadcast message about toolbar
|
||||
// button being clicked. In the case of the "extra" injections,
|
||||
// the document location is null, so we can avoid doing on anything.
|
||||
if ((document.location != null) && (thisPageLinkObjects.length > 0))
|
||||
{
|
||||
feedToOpen = thisPageLinkObjects[0];
|
||||
subscribeToFeed(feedToOpen);
|
||||
}
|
||||
}
|
||||
else if (event.name === "ping")
|
||||
{
|
||||
// Just a hack to get the toolbar icon validation to work as expected.
|
||||
// If we don't pong back, the extension knows we are not loaded in a page.
|
||||
|
||||
// There is a bug in Safari where the messageHandler is apparently held on to by Safari
|
||||
// even after an extension is disabled. So an effort to "ping" an extension's scripts will
|
||||
// succeed even if its been disabled and the page reloaded. Checking for the existance of
|
||||
// document.location seems to ensure we have enough of a handle still on the document that
|
||||
// we can do something useful with it.
|
||||
var shouldValidate = (document.location != null) && (thisPageLinkObjects.length > 0);
|
||||
|
||||
// Pass back the same validationID we were handed so they can look up the correlated validationHandler
|
||||
safari.extension.dispatchMessage("pong", { "validationID": event.message.validationID, "shouldValidate": shouldValidate });
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
// Prevent injecting the JavaScript in IFRAMES, and from acting before Safari is ready...
|
||||
if ((window.top === window) && (typeof safari != 'undefined') && (document.location != null))
|
||||
{
|
||||
safari.self.addEventListener("message", messageHandler, false)
|
||||
scanForSyndicationFeeds();
|
||||
}
|
||||
});
|
|
@ -2,6 +2,12 @@
|
|||
|
||||
Evergreen uses [Git submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules) to include shared frameworks. At this writing (June 2018) they are DB5, RSCore, RSDatabase, RSWeb, RSTree, and RSParser.
|
||||
|
||||
After your first checkout:
|
||||
|
||||
git submodule init
|
||||
git submodule update
|
||||
|
||||
|
||||
To add a submodule:
|
||||
|
||||
git submodule add https://github.com/username/path
|
||||
|
|
Loading…
Reference in New Issue